Если вы достаточно давно пользуетесь операционной системой Linux, то, наверное, уже не раз слышали о сервисе DBus. Он фигурирует в различных логах программ, инструкциях по настройке системы, а также вы можете видеть сервис DBus-daemon, который непонятно зачем загружается при старте системы.
В этой статье мы попытаемся разобраться, что такое DBus, зачем он нужен, а также как его можно использовать для эффективного управления приложениями в системе.
Что такое Dbus?
Dbus или Desktop Bus — это система, которая используется в основном в операционной системе Linux для того, чтобы различные приложения и сервисы могли общаться между собой. Но с помощью Dbus могут взаимодействовать не только приложения, но и пользователи с приложениями.
По сути, DBus состоит из управляющего демона, API для языков программирования, с помощью которых приложения могут взаимодействовать с системой и консольного клиента.
Каждое приложение, которое хочет работать с DBus, должно зарегистрировать свой сервис в демоне DBus. Поскольку все приложения и сервисы могут беспрепятственно обмениваться сообщениями, этот способ еще называется шина DBus. На шине каждое приложение имеет свой адрес, а каждое сообщение имеет своего отправителя и адресата. Приложение может обмениваться сообщениями даже не с одним, а несколькими приложениями одновременно. Каждое приложение может отправлять сообщения и прослушивать входящие.
Этот механизм дает системе огромную гибкость, например, программы могут подписываться на сообщения о подключении новых устройств, изменении настроек, изменении состояния системы и многое другое. Все это с помощью стандартизированного интерфейса DBus, что гарантирует совместимость. Также программы могут регистрировать свои сервисы таким образом, чтобы программа запускалась только при поступлении сообщений и не работала в фоне.
Обычно Dbus создает две шины или области, в которых программы могут обмениваться сообщениями. Это системная шина — для системных сервисов. Ее главная задача — доставка сообщений об изменении состояния оборудования. Вторая шина сессионная, создается отдельно для каждого пользователя и позволяет приложениям, запущенным от его имени взаимодействовать между собой.
Объекты Dbus
Каждое приложение, которое использует Dbus, регистрирует свой объект, а также может регистрировать несколько интерфейсов. Когда объекту отправляется сообщение, его получает и приложение. У каждого объекта уникальное имя. Оно похоже на путь в файловой системе. Чтобы имя каждого объекта было уникальным в нем используется префикс разработчика, например, /org/kde или /com/redhat.
Путь объекта DBus состоит из трех частей:
- Имя сервиса;
- Имя объекта;
Несколько примеров объектов:
- org.freedesktop.NetworkManager
- org.freedesktop.UDisks
- org.freedesktop.DisplayManager
- org.kde.plasmashell
Части имени объектов разделены точкой. Каждый объект имеет один или несколько интерфейсов, которым можно отправлять сообщения.
Интерфейсы имеют очень похожий путь на путь объекта, в некоторых случаях, имя интерфейса совпадает с именем объекта, но если интерфейсов несколько, то они могут отличаться. В отличие от объекта имя интерфейса разделено слэшем. Вот несколько примеров имен интерфейсов, в скобках я привел объекты, в которых есть эти интерфейсы:
- /org/mpris/MediaPlayer2/Player (org.mpris.MediaPlayer2.VLC)
- /org/PluseAudio/ServerLookup1 (org.PluseAudio1)
Сообщения Dbus
Сообщения Dbus это тоже довольно сложная тема. Они бывают четырех разных типов. Это вызовы методов, результаты вызовов, сигналы и ошибки. Dbus проектировался для использования в первую очередь в программах, поэтому и были реализованы такие сложные структуры. Когда осуществляется вызов метода, программа должна обработать данные и потом в ответном сообщении вернуть результат (результат выполнения) или ошибку.
Доступные объекты Dbus
Большинство доступных объектов Dbus описаны на сайте freedesktop.org. Но лучший способ узнать какие сервисы поддерживает система — это воспользоваться программой qdbusviewer. В окружении рабочего стола kde она поставляется по умолчанию, в Gnome и других ее можно установить из пакета qttools5-dev-tools:
sudo apt install qttools5-dev-tools
Запустив программу через главное меню вы увидите вот такое главное окно:
Здесь вы можете увидеть на левой панели список доступных объектов, на правой — пути к интерфейсу внутри объекта и методы. Внизу консоль, в которую выводится информация об успешности ваших действий.
В программе, как и положено, есть две шины, сессионная и системная. К каждой из них вы можете получить доступ. С помощью программы даже можно отсылать сообщения вызывая методы и меняя свойства. Но это не совсем правильный способ. Как пользоваться Dbus мы рассмотрим ниже.
Как использовать Dbus?
Обращаться к сервисам Dbus можно с помощью консольной утилиты dbus-send. Рассмотрим ее синтаксис:
$ dbus-send опции —dest адрес_объекта интерфейс метод параметры
- опции — настраивают общее поведение утилиты;
- адрес_объекта — объект, которому мы собираемся отправлять сообщение;
- интерфейс — интерфейс объекта, который получит сообщение;
- метод — метод интерфейса, который будет вызван, или сигнал;
- параметры — дополнительные параметры, если они нужны.
Рассмотрим опции утилиты:
- —system — использовать системную шину для отправки сообщений;
- —session — использовать сессионную шину;
- —dest — объект, которому будет отправлено сообщение;
- —print-reply — напечатать ответ;
- —reply-timeout — таймаут ожидания ответа;
- —type — тип сообщения, может быть signal, method_call, error, method_result.
Таким образом, когда выполняется запрос, скажем method_call утилита отправляет сообщение указанному нами объекту, затем ждет от него ответа, ответ приходит сообщением method_result, и если было указанно, что ответ нужно вывести на экран, он будет выведен. Все поля нужно заполнять полностью, полный путь объекта, полное имя интерфейса и полное имя метода, включая имя интерфейса.
Вы уже знаете, как и где искать нужные вам интерфейсы, а теперь рассмотрим пару примеров отправки сообщений Dbus.
Получаем список сетевых адаптеров NetworkManager:
dbus-send --system --print-reply --reply-timeout=120000 --type=method_call --dest='org.freedesktop.NetworkManager' '/org/freedesktop/NetworkManager' org.freedesktop.NetworkManager.GetDevices
Что здесь происходит? Мы сообщаем программе, что хотим видеть ответ, тип сообщения — вызов метода, объект org.freedesktop.NetworkManager, интерфейс /org/freedesktop/NetworkManager, и метод org.freedesktop.NetworkManager.GetDevices
Включим музыку в плеере VLC:
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Play
Поставим на паузу:
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Pause
Здесь org.mpris.MediaPlayer2.vlc — объект, интерфейс — /org/mpris/MediaPlayer2, метод — org.mpris.MediaPlayer2.Player.Pause
Методы могут получать параметры, например, перемотаем наш трек на несколько секунд:
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.mpris.MediaPlayer2.Player.Seek int64:10000000
Узнать тип переменной можно тоже с помощью qdbusviewer. Кликните по методу правой кнопкой и выберите Call, в открывшемся диалоговом окне будет предложено ввести значение переменной, а также указан ее тип.
Кроме методов, здесь есть переменные. Понять с чем мы имеем дело, методом или переменной можно тоже с помощью qdbusviewer. Для методов будет написано method, для переменных property. Но посмотреть значение переменной не так просто, для этого используется такая конструкция:
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Get string:org.mpris.MediaPlayer2.Player string:Volume
Вместо того чтобы обратиться напрямую к переменной интерфейса, мы используем метод org.freedesktop.DBus.Properties.Get объекта /org/mpris/MediaPlayer2 и передаем ему две строки. Имя интерфейса и имя переменной. Данный пример показывает, как посмотреть текущую громкость VLC.
Установить значение переменной еще сложнее. Для этого используется метод org.freedesktop.DBus.Properties.Set:
dbus-send --print-reply --dest=org.mpris.MediaPlayer2.vlc /org/mpris/MediaPlayer2 org.freedesktop.DBus.Properties.Set string:org.mpris.MediaPlayer2.Player string:Volume variant:double:1.1
Пример изменяет громкость воспроизведения VLC. Этот метод принимает уже три параметра две уже знакомые нам строки и новое значение переменной. Значение переменной имеет тип variant и ему нужно задать нужный тип переменной, в нашем случае нужна double. Посмотреть какой тип переменной нужен вам можно в qdbusviewer, кликните по переменной правой кнопкой мыши и нажмите Set Value. Здесь кроме поля ввода значения вы увидите нужный тип переменной.
Выводы
Теперь вы знаете не только что такое Dbus, но и все необходимые основы, чтобы использование Dbus было для вас достаточно простым в вашей системе и вы могли применять его на полную для управления своими программами. Нашли интересную команду Dbus, которая будет полезна другим пользователям? Напишите в комментариях!