Come leggere l'output di dbus-monitor?


20

Sto giocando con dbus-monitor per cercare di capire come funziona dbus in ambiente Ubuntu. Ho diverse domande al riguardo:

  1. La prego di farmi sapere come leggere correttamente quanto segue? Capisco la grande idea, ma non i dettagli.

    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
    

    Capisco che il primo è un segnale mentre il secondo è un metodo. Ha destinazione significa che ci può essere una specifica ricevitore / slot per un segnale? Cos'è un membro ? E gli elementi dell'elenco seguono il segnale gli argomenti passati nel segnale? Cosa sono mittente e numeri di serie ?

  2. Ho notato qualcosa sulla relazione tra controllo del volume e notifiche. Da quello che ho letto dall'output di dbus-monitor

    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
    

    Sembra che la notifica sia attivata dal suo metodo. Semplicemente non capisco davvero perché funzioni in questo modo. A mio avviso, avrebbe più senso se venisse emesso un segnale "notifica-volume-audio-medio" mentre la notifica avrebbe ascoltato questo segnale e avrebbe reagito di conseguenza. Se l'invio / la ricezione fossero pubblici piuttosto che privati, non consentirebbe maggiore flessibilità ed efficienza? Ad esempio se c'era un segnale pubblico per "notifica-volume-audio-medio" quindi diverse applicazioni potrebbero ascoltare questo segnale (che consentirebbe la realizzazione di applicazioni di notifica concorrenti) e gli sviluppatori dovrebbero semplicemente preoccuparsi di inviare segnali, mentre la raccolta e la gestione di un segnale sarebbe l'attività dell'applicazione di notifica (o qualsiasi altra programma che necessita di quei segnali).

  3. Sono appena nuovo su Dbus e voglio saperne di più mentre lavoro con Dbus su Python, principalmente per sviluppare alcune applet. Ho visto il tutorial di dbus-python e insegna come ascoltare tutti i segnali (specificando né interfaccia né percorso, ecc.) Ma come tenere traccia dei metodi quando vengono chiamati, come fa dbus-monitor?

Se hai la pazienza di insegnare come funziona, sei il benvenuto.

Risposte:


24

Introduzione a D-Bus

  • D-Bus fornisce i mezzi per comunicare tra i servizi . I servizi possono essere anonimi (identificati esclusivamente dall'indirizzo del bus, come: 1.6), e i servizi possono acquisire nomi noti , come org.freedesktop.Notificationso org.freedesktop.NetworkManager. Il mittente e la destinazione che è possibile visualizzare nei registri sono servizi. "Destinazione nulla" significa trasmissione: consegna a tutti i servizi.

  • Un servizio può esportare uno o più oggetti sul bus. Agli oggetti vengono dati percorsi di oggetti , come /org/freedesktop/NetworkManager/ActiveConnection/1o /org/ayatana/menu/DA00003. I percorsi degli oggetti usano la barra come separatore, come i percorsi del filesystem.

  • Ogni oggetto può supportare una o più interfacce . Un'interfaccia non è altro che un insieme di metodi e segnali, noti in modo colorato come membri (molto simili all'interfaccia OOP). Metodi e segnali hanno firme fisse. I membri sono sempre spazi dei nomi all'interno di nomi di interfaccia noti.

  • Una volta pubblicati, i nomi noti non cambiano mai .

  • Qualsiasi servizio può connettersi ai segnali di un altro servizio e chiamare in modo asincrono i suoi metodi. Qualsiasi servizio può emettere segnali.

segnali

Ora alle tue domande specifiche.

mittente del segnale =: 1.1948 -> dest = (destinazione nulla) seriale = 1829990 percorso = / org / ayatana / menu / DA00003; interface = org.ayatana.dbusmenu; membro = ItemPropertyUpdated
int32 23
stringa "abilitata"
variante vero booleano

Sì, hai ragione, questo è un segnale. È trasmesso dal servizio :1.1948e l'oggetto "self" lo è /org/ayatana/menu/DA00003. Il segnale ha un nome ItemPropertyUpdateddefinito nell'interfaccia org.ayatana.dbusmenu(come org.ayatana.dbusmenu::ItemPropertyUpdatedin C ++). Il seriale, immagino, è una specie di identificatore univoco dell'evento sul bus.

Quindi vediamo gli argomenti del segnale. Secondo la documentazione dell'interfaccia , il primo argomento int32 è l'ID di un elemento, la seconda stringa è il nome della sua proprietà e la terza variante è il valore della proprietà. Quindi, l' /org/ayatana/menu/DA00003oggetto ci sta notificando che l'oggetto n. 23 ha cambiato la sua enabledproprietà in vera.


Un altro esempio sui segnali:

mittente del segnale =: 1.1602 -> dest = (destinazione nulla) seriale = 20408 percorso = / im / pidgin / purple / PurpleObject; interface = im.pidgin.purple.PurpleInterface; membro = SendingChatMsg
   int32 47893
   stringa "test"
   uint32 1
mittente del segnale =: 1.1602 -> dest = (destinazione nulla) seriale = 20409 percorso = / im / pidgin / purple / PurpleObject; interface = im.pidgin.purple.PurpleInterface; membro = IrcSendingText
   int32 64170
   stringa "PRIVMSG #chat: test

Ho inviato un messaggio di testo "test" utilizzando Pidgin a un canale IRC ed ho /im/pidgin/purple/PurpleObjectemesso due segnali sotto l' im.pidgin.purple.PurpleInterfaceinterfaccia: prima un generale SendingChatMsg, poi uno più specifico IrcSendingText.

metodi

Ora metodi. I metodi sono un modo per chiedere agli oggetti D-Bus di fare qualcosa o di eseguire query e restituire dati. Sono abbastanza simili ai metodi OOP classici, tranne per il fatto che i metodi D-Bus sono chiamati in modo asincrono.

Chiamiamo un metodo D-Bus a livello di codice.

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

Nota gli argomenti, in particolare il nome dell'icona. Nel tuo esempio "notification-audio-volume-medium"c'era l'icona dell'altoparlante a volume medio.

Servizi personalizzati

È assolutamente possibile eseguire i propri servizi D-Bus, esportare i propri oggetti D-Bus e definire le proprie interfacce D-Bus con i propri metodi e segnali. Tutto questo può essere fatto abbastanza facilmente in Python dopo aver compreso il concetto generale e aver letto la dbusdocumentazione del modulo.:)


La discussione è benvenuta, anche se potrei non essere disponibile tra un giorno o due.
Ulidtko,

Grazie :) Questo chiarisce molto. È in qualche modo divertente che i mittenti possano essere anonimi, quando uso DFeet, esiste un nome di processo corrispondente a ciascun mittente, ma ciò non si riflette nell'output di dbus-monitor. È possibile tracciare i processi? Ora con Python ho visto che posso inviare segnali o fornire metodi o attivare metodi di altre parti. È anche possibile intercettare metodi? Supponiamo che io voglia vedere se il programma A innesca il metodo Dbus di B e fare qualcosa con esso?
Benjamin,

Informazioni sulle notifiche: la notifica-osd viene attivata passivamente da altre applicazioni, piuttosto che cercare attivamente segnali. Non è impraticabile o non fraintendo qualcosa su Dbus? Voglio fare una domanda che sostituisca la notifica-osd e raccolga le notifiche in una sorta di posta in arrivo. Posso intercettare le notifiche ascoltando i segnali allora?
Benjamin,

@Benjamin, beh, quando vuoi intercettare le chiamate di metodo dirette a servizi stranieri, molto probabilmente pensi a un design rotto. Quello che dovresti fare per sostituire notify-osd è scrivere un programma che fornisce il org.freedesktop.Notificationsservizio. In questo modo tutte le chiamate di metodo a questo servizio saranno gestite dal tuo codice.
Ulidtko,

Cos'è l'obejct "sé"?
kawing-chiu,

10

Stavo anche cercando una soluzione per raccogliere le notifiche desktop tramite dbus con uno script Python. Questa domanda è stata la più vicina che ho avuto su Google, ma scrivere un sostituto per Notify-OSD sembrava un eccessivo :)

Osservando le fonti dell'applet delle notifiche recenti ho ricevuto alcuni suggerimenti su come monitorare i messaggi dbus ed ecco l'implementazione di Python che mi è venuta in mente:

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()

Spero che questo aiuti qualcuno, in quanto sembra che non ci siano molti semplici esempi di pitone relativi al monitoraggio dei messaggi dbus.


1
Mi ha sicuramente aiutato! Grazie mille! Alcuni suggerimenti per te: "type = 'method_call'" non è necessario, poiché le notifiche utilizzano solo chiamate di metodo. Nessun segnale nelle specifiche. Inoltre, "member = 'Notifica'" non è necessario, poiché lo stai già filtrando nella tua funzione (e, come hai detto correttamente, non puoi evitarlo a causa del primo NameAquiredmessaggio)
MestreLion
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.