¿Cómo leer la salida del monitor dbus?


20

Estoy jugando con dbus-monitor para tratar de entender cómo funciona dbus en el entorno Ubuntu. Tengo varias preguntas al respecto:

  1. ¿Me podría decir cómo leer lo siguiente correctamente? Entiendo la gran idea, pero no los detalles.

    signal sender=:1.1948 -> dest=(null destination) serial=1829990 path=/org/ayatana/menu/DA00003; interface=org.ayatana.dbusmenu; member=ItemPropertyUpdated
    int32 23
    string "enabled"
    variant boolean true
    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1399 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications;
    member=GetCapabilities

    Entiendo que el primero es una señal, mientras que el segundo es un método. ¿ Destino significa que puede haber un receptor / ranura específica para una señal? ¿Qué es un miembro ? ¿Y los elementos de la lista siguen la señal de los argumentos pasados ​​en la señal? ¿Qué son el remitente y las publicaciones seriadas ?

  2. Noté algo sobre la relación entre el control de volumen y las notificaciones. Por lo que leí de la salida del monitor dbus

    method call sender=:1.6 -> dest=org.freedesktop.Notifications serial=1400 path=/org/freedesktop/Notifications; interface=org.freedesktop.Notifications; member=Notify
    string "gnome-settings-daemon"
    uint32 0
    string "notification-audio-volume-medium"
    string " "
    string ""
    array [
    ]
    array [
    dict entry(
    string "value"
    variant int32 38
    )
    dict entry(
    string "x-canonical-private-synchronous"
    variant string "volume"
    )
    ]
    int32 -1

    Parece que la notificación se activa por su método. Simplemente no entiendo por qué funciona de esta manera. En mi opinión, tendría más sentido si hubiera una señal emitida "notificación-audio-volumen-medio", mientras que la notificación escucharía esta señal y reaccionaría en consecuencia. Si el envío / recepción fuera público en lugar de privado, ¿no permitiría una mayor flexibilidad y eficiencia? Por ejemplo, si había una señal pública para "notificación-audio-volumen-medio" varias aplicaciones podrían escuchar esta señal (lo que permitiría la existencia de aplicaciones de notificación competidoras) y los desarrolladores solo tendrían que preocuparse por enviar señales, mientras que recoger y manejar una señal sería el negocio de la aplicación notificante (o cualquier otro programa que necesita esas señales).

  3. Soy nuevo en Dbus y quiero aprender más, ya que estoy trabajando con Dbus en Python, principalmente para desarrollar algunos applets. He visto el tutorial dbus-python y enseña cómo escuchar todas las señales (sin especificar la interfaz ni la ruta, etc.) Pero, ¿cómo rastrear los métodos cuando se los llama, como lo hace dbus-monitor?

Si tienes la paciencia para enseñar cómo funciona eso, eres bienvenido.

Respuestas:


24

Introducción a D-Bus

  • D-Bus proporciona medios para comunicarse entre servicios . Los servicios pueden ser anónimos (identificados únicamente por la dirección del autobús, como: 1.6), y pueden adquirir nombres conocidos , como org.freedesktop.Notificationso org.freedesktop.NetworkManager. El remitente y el destino que puede ver en los registros son servicios. "Destino nulo" significa difusión: entrega a todos los servicios.

  • Un servicio puede exportar uno o varios objetos al bus. Los objetos reciben rutas de objeto , como /org/freedesktop/NetworkManager/ActiveConnection/1o /org/ayatana/menu/DA00003. Las rutas de objetos usan la barra como separador, como las rutas del sistema de archivos.

  • Cada objeto puede soportar una o varias interfaces . Una interfaz no es más que un conjunto de métodos y señales, conocidos coloquialmente como miembros (muy similar a la interfaz OOP). Los métodos y las señales tienen firmas fijas. Los miembros siempre tienen espacios de nombres dentro de nombres de interfaz conocidos .

  • Una vez publicados, los nombres conocidos nunca cambian .

  • Cualquier servicio puede conectarse a las señales de otro servicio y llamar asincrónicamente sus métodos. Cualquier servicio puede emitir señales.

Señales

Ahora a sus preguntas específicas.

remitente de señal =: 1.1948 -> dest = (destino nulo) serial = 1829990 ruta = / org / ayatana / menu / DA00003; interfaz = org.ayatana.dbusmenu; member = ItemPropertyUpdated
int32 23
cadena "habilitada"
variante boolean true

Sí, tienes razón, esta es una señal. Es transmitido por el servicio :1.1948, y el objeto "auto" es /org/ayatana/menu/DA00003. La señal tiene un nombre ItemPropertyUpdatedque se define en la interfaz org.ayatana.dbusmenu(como org.ayatana.dbusmenu::ItemPropertyUpdateden C ++). El serial, supongo, es una especie de identificador único del evento en el bus.

Luego vemos los argumentos de la señal. De acuerdo con la documentación de la interfaz , el primer argumento int32 es la identificación de un elemento, la segunda cadena es el nombre de su propiedad y la tercera variante es el valor de la propiedad. Entonces, el /org/ayatana/menu/DA00003objeto nos está notificando que la identificación del artículo # 23 cambió su enabledpropiedad a verdadero.


Otro ejemplo de señales:

remitente de señal =: 1.1602 -> dest = (destino nulo) serial = 20408 ruta = / im / pidgin / purple / PurpleObject; interfaz = im.pidgin.purple.PurpleInterface; miembro = SendingChatMsg
   int32 47893
   cadena "prueba"
   uint32 1
remitente de señal =: 1.1602 -> dest = (destino nulo) serial = 20409 ruta = / im / pidgin / purple / PurpleObject; interfaz = im.pidgin.purple.PurpleInterface; miembro = IrcSendingText
   int32 64170
   cadena "PRIVMSG #chat: prueba

Envié un mensaje de texto "prueba" usando Pidgin a un canal IRC, y /im/pidgin/purple/PurpleObjectemití dos señales debajo de la im.pidgin.purple.PurpleInterfaceinterfaz: primero una general SendingChatMsg, luego una más específica IrcSendingText.

Métodos

Ahora métodos. Los métodos son una forma de pedirle a los objetos de D-Bus que hagan algo o realizar alguna consulta y devolver datos. Son bastante similares a los métodos clásicos de OOP, excepto que los métodos D-Bus se llaman de forma asincrónica.

Llamemos a un método D-Bus mediante programación.

import dbus, dbus.proxies

#-- connect to the session bus (as opposed to the system bus)
session = dbus.SessionBus()

#-- create proxy object of D-Bus object
obj_proxy = dbus.proxies.ProxyObject(conn=session,
         bus_name="org.freedesktop.Notifications",     #-- name of the service we are retrieving object from
         object_path="/org/freedesktop/Notifications") #-- the object path

#-- create proxy object of the D-Bus object wrapped into specific interface
intf_proxy = dbus.proxies.Interface(obj_proxy, "org.freedesktop.Notifications")

#-- lastly, create proxy object of the D-Bus method
method_proxy = intf_proxy.get_dbus_method("Notify")

#-- ... and call the method
method_proxy("test from python",
             dbus.UInt32(0),
             "bluetooth",     #-- icon name
             "Notification summary",
             "Here goes notification body",
             [], {},
             5) #-- timeout

Tenga en cuenta los argumentos, especialmente el nombre del icono. En su ejemplo, "notification-audio-volume-medium"fue el ícono del altavoz de volumen de potencia media.

Servicios personalizados

Es absolutamente posible ejecutar sus propios servicios D-Bus, exportar sus propios objetos D-Bus y definir sus propias interfaces D-Bus con sus propios métodos y señales. Todo esto se puede hacer en Python con bastante facilidad una vez que comprenda el concepto general y lea la dbusdocumentación del módulo.:)


La discusión es bienvenida, aunque podría no estar disponible en un día o dos.
ulidtko

Gracias :) Esto aclara mucho. Es de alguna manera divertido que los remitentes puedan ser anónimos, cuando uso DFeet, hay un nombre de proceso correspondiente a cada remitente, pero eso no se refleja en la salida del monitor dbus. ¿Se pueden rastrear los procesos? Ahora con Python he visto que puedo enviar señales o proporcionar métodos o activar los métodos de otras partes. ¿También es posible interceptar métodos? ¿Supongamos que quiero ver si el programa A activa el método Dbus de B y hago algo con él?
Benjamin

Acerca de las notificaciones: el aviso-osd se activa pasivamente por otras aplicaciones, en lugar de buscar señales activamente. ¿No es poco práctico o no entiendo algo sobre Dbus? Quiero hacer una aplicación que reemplace el osmos de notificación y recopile notificaciones en una especie de bandeja de entrada. ¿Puedo interceptar notificaciones escuchando señales entonces?
Benjamin

@Benjamin, bueno, cuando quieres interceptar llamadas de método dirigidas a servicios extranjeros, es muy probable que pienses en un diseño roto. Lo que debe hacer para reemplazar notify-osd es escribir un programa que brinde el org.freedesktop.Notificationsservicio. De esta manera, todas las llamadas de método a este servicio serán manejadas por su código.
ulidtko

¿Qué es el "yo" obejct?
kawing-chiu

10

También estaba buscando una solución para recopilar las notificaciones de escritorio a través de dbus con un script de Python. Esta pregunta fue la más cercana que tuve con googlear, pero escribir un reemplazo para notify-osd parecía una exageración :)

Mirando las fuentes de applet de notificaciones recientes, recibí algunos consejos sobre cómo monitorear los mensajes dbus y aquí está la implementación de Python que se me ocurrió:

import gtk
import dbus
from dbus.mainloop.glib import DBusGMainLoop

def filter_cb(bus, message):
    # the NameAcquired message comes through before match string gets applied
    if message.get_member() != "Notify":
        return
    args = message.get_args_list()
    # args are
    # (app_name, notification_id, icon, summary, body, actions, hints, timeout)
    print("Notification from app '%s'" % args[0])
    print("Summary: %s" % args[3])
    print("Body: %s", args[4])


DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
bus.add_match_string(
    "type='method_call',interface='org.freedesktop.Notifications',member='Notify'")
bus.add_message_filter(filter_cb)
gtk.main()

Espero que esto ayude a alguien, ya que parece que no hay muchos ejemplos simples de Python relacionados con el monitoreo de los mensajes dbus.


1
¡Seguramente me ayudó! ¡Muchas gracias! Algunas sugerencias para usted: "type = 'method_call'" no es necesario, ya que las notificaciones solo usan llamadas a métodos. No hay señales en la especificación. Además, "member = 'Notify'" tampoco es necesario, ya que ya está filtrando eso en su función (y, como dijo correctamente, no puede evitarlo debido al primer NameAquiredmensaje)
MestreLion
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.