dbus -- message and message bus

Posted by gothica on Mon, 31 Jan 2022 23:59:42 +0100

Message and message bus

Application a is connected to the message bus, which obtains a well-known common name (recorded as connection a). In application a, object A1 provides interface I1, and interface I1 has method M1. When application B is connected to the message bus, it is required to call method M1 of interface I1 of object A1 on connection a.

In the addition example mentioned above, the above paragraph can be instantiated as: application example service and session bus connection. This connection gets a well-known public name "org.fmddlmyy.Test". The object "/ TestObj" in the application example service provides the interface "org.fmddlmyy.Test.Basic", and the interface "org.fmddlmyy.Test.Basic" has the method "Add". The application d-feet are connected to the session bus. It is required to call the method "Add" of the interface "org.fmddlmyy.Test.Basic" connecting the object "/ TestObj" on "org.fmddlmyy.Test".

Application B invokes the method of application A. in fact, application B sends a message of "method_call" to application a. Application a sends the return value to application B through a message of type "method_retn". Let's briefly introduce the messages on the D-Bus.

1. D-Bus message

As mentioned above, the most basic D-Bus protocol is one-to-one communication protocol. Different from using socket directly, D-Bus is a message oriented protocol. All functions of D-Bus are accomplished through messages flowing on the connection.

1.1 message type

D-Bus has four types of messages:

  • method_call method call
  • method_return method returns
  • Error error
  • Signal signal

The remote method call described earlier uses method_call and method_return message. As the name suggests, an error message is generated when an error occurs. If you put method_call is regarded as a call, and the signal message is an incoming call. It will be discussed in detail later.

1.2. DBUS send and DBUS monitor

dbus provides two Gadgets: dbus send and dbus monitor. We can send messages using dbus send. Use dbus monitor to monitor the messages flowing on the bus. Let's call the previous Add method by sending a message through dbus send, where dbus send acts as application B. Observe the messages in the calling process with dbus monitor.

For the detailed usage of DBUS send, please refer to the manual. The general form of calling remote methods is:

$ dbus-send [--system | --session] --type=method_call --print-reply --dest=Connection name object path interface name.Method name parameter type:Parameter value parameter type:Parameter value

The parameter types supported by DBUS send include: string, int32, uint32, double, byte and Boolean.

2. Method and signal of message bus

2.1 overview

Message bus is a special application, which can transfer messages between applications connected to it. Think of the message bus as a router. It is through the message bus that D-Bus realizes many to one and one to many communication on the basis of one-to-one communication protocol.

Although message bus has special forwarding function, it is also an application. The communication between other applications and the message bus is also completed through the basic message types in Section 1.1. As an application, the message bus also provides its own interface, including methods and signals.

We can call the methods provided by the message bus by sending a message to the object "/" on the connection "org.freedesktop.DBus". In fact, applications connect to other applications on the message bus through these methods to complete the work of requesting common names.

2.2 list

To use DBUS send on FCP and AC boards, you need to execute export $(DBUS launch) first

root@xxxx-obmc:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
Failed to open connection to "session" message bus: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead
root@xxxx-obmc:~# export $(dbus-launch)
root@xxxx-obmc:~#
root@xxxx-obmc:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return time=61305.454012 sender=org.freedesktop.DBus -> destination=:1.0 serial=3 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string ":1.0"
   ]
root@xxxx-obmc:~#

The message bus object supports the standard interface "org.freedesktop.DBus.Introspectable" mentioned in the first lecture. We can call org. Com freedesktop. DBus. Introspectable. The introspect method looks at the interfaces supported by the message bus object. For example:

$ dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect
root@xxxx-obmc:~# dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.Introspectable.Introspect
method return time=109.212525 sender=org.freedesktop.DBus -> destination=:1.1 serial=3 reply_serial=2
   string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
  <interface name="org.freedesktop.DBus">
    <method name="Hello">
      <arg direction="out" type="s"/>
    </method>
    <method name="RequestName">
      <arg direction="in" type="s"/>
      <arg direction="in" type="u"/>
      <arg direction="out" type="u"/>
    </method>
    <method name="ReleaseName">
      <arg direction="in" type="s"/>
      <arg direction="out" type="u"/>
    </method>
    <method name="StartServiceByName">
      <arg direction="in" type="s"/>
      <arg direction="in" type="u"/>
      <arg direction="out" type="u"/>
    </method>
    <method name="UpdateActivationEnvironment">
      <arg direction="in" type="a{ss}"/>
    </method>
    <method name="NameHasOwner">
      <arg direction="in" type="s"/>
      <arg direction="out" type="b"/>
    </method>
    <method name="ListNames">
      <arg direction="out" type="as"/>
    </method>
    <method name="ListActivatableNames">
      <arg direction="out" type="as"/>
    </method>
    <method name="AddMatch">
      <arg direction="in" type="s"/>
    </method>
    <method name="RemoveMatch">
      <arg direction="in" type="s"/>
    </method>
    <method name="GetNameOwner">
      <arg direction="in" type="s"/>
      <arg direction="out" type="s"/>
    </method>
    <method name="ListQueuedOwners">
      <arg direction="in" type="s"/>
      <arg direction="out" type="as"/>
    </method>
    <method name="GetConnectionUnixUser">
      <arg direction="in" type="s"/>
      <arg direction="out" type="u"/>
    </method>
    <method name="GetConnectionUnixProcessID">
      <arg direction="in" type="s"/>
      <arg direction="out" type="u"/>
    </method>
    <method name="GetAdtAuditSessionData">
      <arg direction="in" type="s"/>
      <arg direction="out" type="ay"/>
    </method>
    <method name="GetConnectionSELinuxSecurityContext">
      <arg direction="in" type="s"/>
      <arg direction="out" type="ay"/>
    </method>
    <method name="ReloadConfig">
    </method>
    <method name="GetId">
      <arg direction="out" type="s"/>
    </method>
    <method name="GetConnectionCredentials">
      <arg direction="in" type="s"/>
      <arg direction="out" type="a{sv}"/>
    </method>
    <property name="Features" type="as" access="read">
      <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
    </property>
    <property name="Interfaces" type="as" access="read">
      <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
    </property>
    <signal name="NameOwnerChanged">
      <arg type="s"/>
      <arg type="s"/>
      <arg type="s"/>
    </signal>
    <signal name="NameLost">
      <arg type="s"/>
    </signal>
    <signal name="NameAcquired">
      <arg type="s"/>
    </signal>
  </interface>
  <interface name="org.freedesktop.DBus.Introspectable">
    <method name="Introspect">
      <arg direction="out" type="s"/>
    </method>
  </interface>
  <interface name="org.freedesktop.DBus.Peer">
    <method name="GetMachineId">
      <arg direction="out" type="s"/>
    </method>
    <method name="Ping">
    </method>
  </interface>
  <node name="org/freedesktop/DBus"/>
</node>
"

From the output, we can see that the session bus object supports the standard interface "org.freedesktop.DBus.Introspectable" and the interface "org.freedesktop.DBus". The interface "org.freedesktop.DBus" has 16 methods and 3 signals. The following table lists a brief description of the 12 methods of "org.freedesktop.DBus"

mathodexplain
org.freedesktop.DBus.RequestName (in STRING name, in UINT32 flags, out UINT32 reply)Request public name. The definition of flag is as follows: DBUS_ NAME_ FLAG_ ALLOW_ REPLACEMENT 1 DBUS_ NAME_ FLAG_ REPLACE_ EXISTING 2 DBUS_ NAME_ FLAG_ DO_ NOT_ The return value reply of queue 4 is defined as follows: DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 DBUS_REQUEST_NAME_REPLY_IN_QUEUE 2 DBUS_REQUEST_NAME_REPLY_EXISTS 3 DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER 4
org.freedesktop.DBus.ReleaseName (in STRING name, out UINT32 reply)Release the public name. The return value reply is defined as follows: DBUS_RELEASE_NAME_REPLY_RELEASED 1 DBUS_RELEASE_NAME_REPLY_NON_EXISTENT 2 DBUS_RELEASE_NAME_REPLY_NOT_OWNER 3
org.freedesktop.DBus.Hello (out STRING unique_name)An application must call hello to get the unique name of its connection before sending messages to other applications through the message bus. The return value is the unique name of the connection. dbus does not define a special command to cut off the connection. Closing the socket is to cut off the connection. In the dbus monitor output in section 1.2, you can see that dbus send calls the Hello method of the message bus.
org.freedesktop.DBus.ListNames (out ARRAY of STRING bus_names)Returns all connection names connected on the message bus, including all public and unique names. For example, the connection "org.fmddlmyy.Test" has both the public name "org.fmddlmyy.Test" and the unique name ": 1.21", both of which will be returned.
org.freedesktop.DBus.ListActivatableNames (out ARRAY of STRING bus_names)Returns the names of all services that can be started. dbus supports on-demand service startup, that is, start the service according to the request of the application.
org.freedesktop.DBus.NameHasOwner (in STRING name, out BOOLEAN has_owner)Checks whether any connection has the specified name.
org.freedesktop.DBus.StartServiceByName (in STRING name, in UINT32 flags, out UINT32 ret_val)Start the service by name. The parameter flags is not used yet. Return value ret_val is defined as follows: 1. The service has been started successfully. 2. There is already a connection with the service name to be started
org.freedesktop.DBus.GetNameOwner (in STRING name, out STRING unique_connection_name)Returns the unique name of the connection with the specified public name.
org.freedesktop.DBus.GetConnectionUnixUser (in STRING connection_name, out UINT32 unix_user_id)Returns the Unix user id of the server process corresponding to the specified connection.
org.freedesktop.DBus.AddMatch (in STRING rule)Add a matching rule for the current connection.
org.freedesktop.DBus.RemoveMatch (in STRING rule)Removes the specified matching rule for the current connection.
org.freedesktop.DBus.GetId (out STRING id)Returns the ID of the message bus. This ID is unique for the lifetime of the message bus.

The three signals of the interface "org.freedesktop.DBus" are:

signalexplain
org.freedesktop.DBus.NameOwnerChanged (STRING name, STRING old_owner, STRING new_owner)The owner of the specified name has changed.
org.freedesktop.DBus.NameLost (STRING name)The notification app lost ownership of the specified name.
org.freedesktop.DBus.NameAcquired (STRING name)The notification application has obtained ownership of the specified name.

Differences between session and system parameters:

dbus-send --session --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return time=875.939015 sender=org.freedesktop.DBus -> destination=:1.2 serial=3 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string ":1.2"
   ]
root@obmc:~#
root@obmc:~#
root@obmc:~#
root@obmc:~# dbus-send --system --type=method_call --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListNames
method return time=908.657105 sender=org.freedesktop.DBus -> destination=:1.143 serial=4294967295 reply_serial=2
   array [
      string "org.freedesktop.DBus"
  ......
   ]

In XYZ openbmc_ project. Control. Host. Take NMI as an example to view its root object.

root@obmc:~# dbus-send --system --type=method_call --print-reply --dest=xyz.openbmc_project.Control.Host.NMI / org.freedesktop.DBus.Introspectable.Introspect
method return time=1482.867385 sender=:1.50 -> destination=:1.144 serial=150 reply_serial=2
   string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
 <interface name="org.freedesktop.DBus.Peer">
  <method name="Ping"/>
  <method name="GetMachineId">
   <arg type="s" name="machine_uuid" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Introspectable">
  <method name="Introspect">
   <arg name="data" type="s" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Properties">
  <method name="Get">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="out" type="v"/>
  </method>
  <method name="GetAll">
   <arg name="interface" direction="in" type="s"/>
   <arg name="properties" direction="out" type="a{sv}"/>
  </method>
  <method name="Set">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="in" type="v"/>
  </method>
  <signal name="PropertiesChanged">
   <arg type="s" name="interface"/>
   <arg type="a{sv}" name="changed_properties"/>
   <arg type="as" name="invalidated_properties"/>
  </signal>
 </interface>
 <interface name="org.freedesktop.DBus.ObjectManager">
  <method name="GetManagedObjects">
   <arg type="a{oa{sa{sv}}}" name="object_paths_interfaces_and_properties" direction="out"/>
  </method>
  <signal name="InterfacesAdded">
   <arg type="o" name="object_path"/>
   <arg type="a{sa{sv}}" name="interfaces_and_properties"/>
  </signal>
  <signal name="InterfacesRemoved">
   <arg type="o" name="object_path"/>
   <arg type="as" name="interfaces"/>
  </signal>
 </interface>
 <node name="xyz"/>
</node>
"

As above, there is a child node under the root directory. The search information is as follows. The interface information obtained is consistent with the information obtained under the root directory.

root@obmc:~# dbus-send --system --type=method_call --print-reply --dest=xyz.openbmc_project.Control.Host.NMI /xyz org.freedesktop.DBus.Introspectable.Introspect
method return time=1762.447872 sender=:1.50 -> destination=:1.145 serial=151 reply_serial=2
   string "<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
 <interface name="org.freedesktop.DBus.Peer">
  <method name="Ping"/>
  <method name="GetMachineId">
   <arg type="s" name="machine_uuid" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Introspectable">
  <method name="Introspect">
   <arg name="data" type="s" direction="out"/>
  </method>
 </interface>
 <interface name="org.freedesktop.DBus.Properties">
  <method name="Get">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="out" type="v"/>
  </method>
  <method name="GetAll">
   <arg name="interface" direction="in" type="s"/>
   <arg name="properties" direction="out" type="a{sv}"/>
  </method>
  <method name="Set">
   <arg name="interface" direction="in" type="s"/>
   <arg name="property" direction="in" type="s"/>
   <arg name="value" direction="in" type="v"/>
  </method>
  <signal name="PropertiesChanged">
   <arg type="s" name="interface"/>
   <arg type="a{sv}" name="changed_properties"/>
   <arg type="as" name="invalidated_properties"/>
  </signal>
 </interface>
 <node name="openbmc_project"/>
</node>
"

2.3.2 automatic startup of ListActivatableNames and server

The results obtained by using session and system here are inconsistent.

root@obmc:~# dbus-send --system --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListActivatableNames
method return time=1939.107887 sender=org.freedesktop.DBus -> destination=:1.146 serial=4294967295 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string "org.freedesktop.Avahi"
      string "org.freedesktop.hostname1"
      string "org.freedesktop.login1"
      string "org.freedesktop.network1"
      string "org.freedesktop.resolve1"
      string "org.freedesktop.systemd1"
      string "org.freedesktop.timedate1"
      string "org.freedesktop.timesync1"
      string "xyz.openbmc_project.EntityManager"
   ]
root@obmc:~# dbus-send --session --print-reply --dest=org.freedesktop.DBus / org.freedesktop.DBus.ListActivatableNames
method return time=1960.060127 sender=org.freedesktop.DBus -> destination=:1.3 serial=3 reply_serial=2
   array [
      string "org.freedesktop.DBus"
      string "org.freedesktop.systemd1"
   ]

Execution:

root@obmc:~# cat /usr/share/dbus-1/services/*|grep Name|awk -F= '{print $2}'|sort
org.freedesktop.systemd1

It sends all files under "/ usr/share/dbus-1/services /" to grep to filter out the rows containing "Name". The rows containing "Name" are sent to awk for processing. Awk uses "=" as the column separator, takes out the second column, and then sends it to sort for output. The "/ usr/share/dbus-1/services /" directory is where DBUS puts the service file. The server that needs to be started automatically will put a service file in this directory, for example:

root@obmc:~# cat /usr/share/dbus-1/services/org.freedesktop.systemd1.service
#  SPDX-License-Identifier: LGPL-2.1+
#
#  This file is part of systemd.
#
#  systemd is free software; you can redistribute it and/or modify it
#  under the terms of the GNU Lesser General Public License as published by
#  the Free Software Foundation; either version 2.1 of the License, or
#  (at your option) any later version.
[D-BUS Service]
Name=org.freedesktop.systemd1
Exec=/bin/false
User=root

Name is the public name of the server, and Exec is the execution path of the server. When a customer requests a service, but the service has not been started. dbus will automatically start the service according to the service file.

Literature

Some contents in doc / subdirectory are pre built and can be browsed here. If you are new to D-Bus, this tutorial is probably the best Getting Started Guide (even if it is very incomplete, it covers the Basics).

General D-Bus protocol information:

Documentation specific to the reference implementation dbus:

Articles on the Internet, including some tutorials:

Topics: ARM bmc