Для чего на практике полезен D-Bus?

Для чего на практике полезен D-Bus?

dbusПредполагается, что он предоставит «простой способ взаимодействия приложений друг с другом».

Но я все еще не уверен, для чего это полезно на практике. Я никогда не видел ситуации, когда это dbusбыло бы полезно, я вижу только предупреждения о том, что какой-то dbusкомпонент столкнулся с ошибками, например, когда я запускаю terminator из командной строки (чтобы я мог видеть ошибки):

Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files

Я избавился от вышеуказанной ошибки, добавив NO_AT_BRIDGE=1в /etc/environment. Понятия не имею, что это делает.

Почти все приложения gui, похоже, связаны с dbus. Некоторые из них можно запускать без dbus, например:

terminator --no-dbus

Я не вижу никакой разницы в поведении. Что должно перестать работать, если terminatorзапустить без dbus?

Кроме того, я попробовал отключить различные компоненты dbus, чтобы посмотреть, что перестает работать:

Я удалил, /etc/X11/Xsession.d/95dbus_update-activation-envпросто чтобы посмотреть, что будет. Там был следующий код:

if [ -n "$DBUS_SESSION_BUS_ADDRESS" ] && [ -x "/usr/bin/dbus-update-activation-environment" ]; then
  # subshell so we can unset environment variables
  (
    # unset login-session-specifics
    unset XDG_SEAT
    unset XDG_SESSION_ID
    unset XDG_VTNR

    # tell dbus-daemon --session to put the Xsession's environment in activated services' environments
    dbus-update-activation-environment --verbose --all
  )
fi

Насколько я могу судить, все работает одинаково. Какова была цель приведенного выше скрипта?

В какой ситуации моим приложениям будет полезно общаться друг с другом через dbus?

Есть ли приложения, которые не работают без dbus?

Моя система — Debian Buster, и я использую простую среду Openbox (без какой-либо среды рабочего стола, такой как Gnome или KDE)

решение1

dbusделает именно то, что вы сказали: обеспечивает двустороннюю связь между приложениями.


Для вашего конкретного примера, который вы упомянули terminator. Отman-страница терминатора, мы видим:

--new-tab
    If this is specified and Terminator is already running, DBus 
    will be used to spawn a new tab in the first Terminator window.

Итак, если вы сделаете это из другого терминала (konsole, xterm, gnome-terminal):

$ terminator &
$ terminator --new-tab &

Вы увидите, что первая команда открывает новое окно. Вторая команда открывает новую вкладку в первом окне. Это делается вторым процессом, который использует dbus для поиска первого процесса, запрашивает у него открытие новой вкладки и затем завершается.

Если вы делаете это с другого терминала:

$ terminator --no-dbus &
$ terminator --new-tab &

Вы увидите, что первая команда открывает новое окно. Вторая команда не может найти dbus первого окна, поэтому она запускает новое окно. Я установил terminator, чтобы проверить это, и это правда.

Кроме того, я подозреваю, что это затронет polkit. Polkit использует dbus для повышения привилегий для приложений с графическим интерфейсом. Это похоже sudoна мир графического интерфейса. Если вы находитесь в gnome и видите, что весь экран перекрывается, пока вас просят ввести пароль администратора, это polkit в действии. Я подозреваю, что вы не получите этого приглашения ни в одном приложении с графическим интерфейсом, из которого вы запустите, terminatorесли у вас есть --no-dbus. Он либо не сможет пройти аутентификацию, либо вернется к какой-либо терминальной аутентификации. Из terminatortry pkexec ls. Это будет работать lsс повышенными привилегиями. Посмотрите, отличается ли это с --no-dbusопцией и без нее. У меня нет агента polkit в моем оконном менеджере (i3), поэтому я не могу это проверить.


Я в основном знаком с dbus в контексте systemd, поэтому остальная часть моего ответа будет взята оттуда.

Есть ли приложения, которые не работают без dbus?

Да. Возьмите systemctl. systemctl statusвыполнит запрос к "org.freedesktop.systemd1"и предоставит его вам. systemctl startвызовет метод dbus и передаст единицу в качестве аргумента этому методу. systemdполучит вызов и выполнит действие.

Если вы хотите предпринять действие в ответ на изменение состояний единицы systemd (например, foo.service), вы можете получить файловый дескриптор для интерфейса org.freedesktop.DBus.Propertiesс путем /org/freedesktop/systemd1/unit/foo_2eserviceи членом PropertiesChanged. Настройте inotifyна этом FD, и у вас внезапно появится способ реагировать на запуск, остановку, сбой службы и т. д.

Если вы хотите посмотреть, что доступно на системной шине данных для определенного устройства (например, ssh.service), попробуйте выполнить следующую команду:

busctl introspect \
    org.freedesktop.systemd1 \
    /org/freedesktop/systemd1/unit/ssh_2eservice
NAME                                TYPE      SIGNATURE       RESULT/VALUE                             FLAGS
org.freedesktop.DBus.Introspectable interface -               -                                        -
.Introspect                         method    -               s                                        -
org.freedesktop.DBus.Peer           interface -               -                                        -
.GetMachineId                       method    -               s                                        -
.Ping                               method    -               -                                        -
org.freedesktop.DBus.Properties     interface -               -                                        -
.Get                                method    ss              v                                        -
.GetAll                             method    s               a{sv}                                    -
.Set                                method    ssv             -                                        -
.PropertiesChanged                  signal    sa{sv}as        -                                        -
org.freedesktop.systemd1.Service    interface -               -                                        -
.AttachProcesses                    method    sau             -                                        -
.GetProcesses                       method    -               a(sus)                                   -
.AllowedCPUs                        property  ay              0                                        -
.AllowedMemoryNodes                 property  ay              0                                        -
.AmbientCapabilities                property  t               0                                        const
.AppArmorProfile                    property  (bs)            false ""                                 const
.BindPaths                          property  a(ssbt)         0                                        const
.BindReadOnlyPaths                  property  a(ssbt)         0                                        const
.BlockIOAccounting                  property  b               false                                    -
.BlockIODeviceWeight                property  a(st)           0                                        -
.BlockIOReadBandwidth               property  a(st)           0                                        -
.BlockIOWeight                      property  t               18446744073709551615                     -
.BlockIOWriteBandwidth              property  a(st)           0                                        -
.BusName                            property  s               ""                                       const
.CPUAccounting                      property  b               false                                    -
.CPUAffinity                        property  ay              0                                        const
.CPUAffinityFromNUMA                property  b               false                                    const
.CPUQuotaPerSecUSec                 property  t               18446744073709551615                     -
.CPUQuotaPeriodUSec                 property  t               18446744073709551615                     -
.CPUSchedulingPolicy                property  i               0                                        const
.CPUSchedulingPriority              property  i               0                                        const
.CPUSchedulingResetOnFork           property  b               false                                    const
.CPUShares                          property  t               18446744073709551615                     -
.CPUUsageNSec                       property  t               18446744073709551615                     -
.CPUWeight                          property  t               18446744073709551615                     -
.CacheDirectory                     property  as              0                                        const
.CacheDirectoryMode                 property  u               493                                      const
.CapabilityBoundingSet              property  t               18446744073709551615                     const
.CleanResult                        property  s               "success"                                emits-change
.ConfigurationDirectory             property  as              0                                        const
.ConfigurationDirectoryMode         property  u               493                                      const
.ControlGroup                       property  s               "/system.slice/ssh.service"              -
.ControlPID                         property  u               0                                        emits-change
.CoredumpFilter                     property  t               51                                       const
.DefaultMemoryLow                   property  t               0                                        -
.DefaultMemoryMin                   property  t               0                                        -
.Delegate                           property  b               false                                    -
.DelegateControllers                property  as              0                                        -
.DeviceAllow                        property  a(ss)           0                                        -
.DevicePolicy                       property  s               "auto"                                   -
.DisableControllers                 property  as              0                                        -
.DynamicUser                        property  b               false                                    const
.EffectiveCPUs                      property  ay              0                                        -
.EffectiveMemoryNodes               property  ay              0                                        -
.Environment                        property  as              0                                        const
.EnvironmentFiles                   property  a(sb)           1 "/etc/default/ssh" true                const
.ExecCondition                      property  a(sasbttttuii)  0                                        emits-invalidation
.ExecConditionEx                    property  a(sasasttttuii) 0                                        emits-invalidation
.ExecMainCode                       property  i               0                                        emits-change
.ExecMainExitTimestamp              property  t               0                                        emits-change
.ExecMainExitTimestampMonotonic     property  t               0                                        emits-change
.ExecMainPID                        property  u               835                                      emits-change
.ExecMainStartTimestamp             property  t               1597235861087584                         emits-change
.ExecMainStartTimestampMonotonic    property  t               5386565                                  emits-change
.ExecMainStatus                     property  i               0                                        emits-change
.ExecReload                         property  a(sasbttttuii)  2 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecReloadEx                       property  a(sasasttttuii) 2 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecStart                          property  a(sasbttttuii)  1 "/usr/sbin/sshd" 3 "/usr/sbin/sshd" "… emits-invalidation
.ExecStartEx                        property  a(sasasttttuii) 1 "/usr/sbin/sshd" 3 "/usr/sbin/sshd" "… emits-invalidation
.ExecStartPost                      property  a(sasbttttuii)  0                                        emits-invalidation
.ExecStartPostEx                    property  a(sasasttttuii) 0                                        emits-invalidation
.ExecStartPre                       property  a(sasbttttuii)  1 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecStartPreEx                     property  a(sasasttttuii) 1 "/usr/sbin/sshd" 2 "/usr/sbin/sshd" "… emits-invalidation
.ExecStop                           property  a(sasbttttuii)  0                                        emits-invalidation
.ExecStopEx                         property  a(sasasttttuii) 0                                        emits-invalidation
.ExecStopPost                       property  a(sasbttttuii)  0                                        emits-invalidation
.ExecStopPostEx                     property  a(sasasttttuii) 0                                        emits-invalidation
.FileDescriptorStoreMax             property  u               0                                        const
.FinalKillSignal                    property  i               9                                        const
.GID                                property  u               4294967295                               emits-change
.Group                              property  s               ""                                       const
.GuessMainPID                       property  b               true                                     const
.IOAccounting                       property  b               false                                    -
.IODeviceLatencyTargetUSec          property  a(st)           0                                        -
.IODeviceWeight                     property  a(st)           0                                        -
.IOReadBandwidthMax                 property  a(st)           0                                        -
.IOReadBytes                        property  t               18446744073709551615                     -
.IOReadIOPSMax                      property  a(st)           0                                        -
.IOReadOperations                   property  t               18446744073709551615                     -
.IOSchedulingClass                  property  i               0                                        const
.IOSchedulingPriority               property  i               0                                        const
.IOWeight                           property  t               18446744073709551615                     -
.IOWriteBandwidthMax                property  a(st)           0                                        -
.IOWriteBytes                       property  t               18446744073709551615                     -
.IOWriteIOPSMax                     property  a(st)           0                                        -
.IOWriteOperations                  property  t               18446744073709551615                     -
.IPAccounting                       property  b               false                                    -
.IPAddressAllow                     property  a(iayu)         0                                        -
.IPAddressDeny                      property  a(iayu)         0                                        -
.IPEgressBytes                      property  t               18446744073709551615                     -
.IPEgressFilterPath                 property  as              0                                        -
.IPEgressPackets                    property  t               18446744073709551615                     -
.IPIngressBytes                     property  t               18446744073709551615                     -
.IPIngressFilterPath                property  as              0                                        -
.IPIngressPackets                   property  t               18446744073709551615                     -
.IgnoreSIGPIPE                      property  b               true                                     const
.InaccessiblePaths                  property  as              0                                        const
...skipping...
.CollectMode                        property  s               "inactive"                               const
.ConditionResult                    property  b               true                                     emits-change
.ConditionTimestamp                 property  t               1597235861034899                         emits-change
.ConditionTimestampMonotonic        property  t               5333881                                  emits-change
.Conditions                         property  a(sbbsi)        1 "ConditionPathExists" false true "/et… emits-invalidation
.ConflictedBy                       property  as              0                                        const
.Conflicts                          property  as              1 "shutdown.target"                      const
.ConsistsOf                         property  as              0                                        const
.DefaultDependencies                property  b               true                                     const
.Description                        property  s               "OpenBSD Secure Shell server"            const
.Documentation                      property  as              2 "man:sshd(8)" "man:sshd_config(5)"     const
.DropInPaths                        property  as              0                                        const
.FailureAction                      property  s               "none"                                   const
.FailureActionExitStatus            property  i               -1                                       const
.Following                          property  s               ""                                       -
.FragmentPath                       property  s               "/lib/systemd/system/ssh.service"        const
.FreezerState                       property  s               "running"                                emits-change
.Id                                 property  s               "ssh.service"                            const
.IgnoreOnIsolate                    property  b               false                                    const
.InactiveEnterTimestamp             property  t               0                                        emits-change
.InactiveEnterTimestampMonotonic    property  t               0                                        emits-change
.InactiveExitTimestamp              property  t               1597235861039525                         emits-change
.InactiveExitTimestampMonotonic     property  t               5338505                                  emits-change
.InvocationID                       property  ay              16 90 215 118 165 228 162 72 57 179 144… emits-change
.Job                                property  (uo)            0 "/"                                    emits-change
.JobRunningTimeoutUSec              property  t               18446744073709551615                     const
.JobTimeoutAction                   property  s               "none"                                   const
.JobTimeoutRebootArgument           property  s               ""                                       const
.JobTimeoutUSec                     property  t               18446744073709551615                     const
.JoinsNamespaceOf                   property  as              0                                        const
.LoadError                          property  (ss)            "" ""                                    const
.LoadState                          property  s               "loaded"                                 const
.Names                              property  as              2 "ssh.service" "sshd.service"           const
.NeedDaemonReload                   property  b               false                                    const
.OnFailure                          property  as              0                                        const
.OnFailureJobMode                   property  s               "replace"                                const
.PartOf                             property  as              0                                        const
.Perpetual                          property  b               false                                    const
.PropagatesReloadTo                 property  as              0                                        const
.RebootArgument                     property  s               ""                                       const
.Refs                               property  as              0                                        -
.RefuseManualStart                  property  b               false                                    const
.RefuseManualStop                   property  b               false                                    const
.ReloadPropagatedFrom               property  as              0                                        const
.RequiredBy                         property  as              0                                        const
.Requires                           property  as              3 "system.slice" "-.mount" "sysinit.tar… const
.RequiresMountsFor                  property  as              1 "/run/sshd"                            const
.Requisite                          property  as              0                                        const
.RequisiteOf                        property  as              0                                        const
.SourcePath                         property  s               ""                                       const
.StartLimitAction                   property  s               "none"                                   const
.StartLimitBurst                    property  u               5                                        const
.StartLimitIntervalUSec             property  t               10000000                                 const
.StateChangeTimestamp               property  t               1597235861208937                         emits-change
.StateChangeTimestampMonotonic      property  t               5507917                                  emits-change
.StopWhenUnneeded                   property  b               false                                    const
.SubState                           property  s               "running"                                emits-change
.SuccessAction                      property  s               "none"                                   const
.SuccessActionExitStatus            property  i               -1                                       const
.Transient                          property  b               false                                    const
.TriggeredBy                        property  as              0                                        const
.Triggers                           property  as              0                                        const
.UnitFilePreset                     property  s               "enabled"                                -
.UnitFileState                      property  s               "enabled"                                -
.WantedBy                           property  as              1 "multi-user.target"                    const
.Wants                              property  as              0                                        const

Из этого видно, что интерфейс dbus довольно мощный.

Вы можете спросить: почему эти приложения просто не взаимодействуют через сокеты или файлы?

DBus предоставляет общий интерфейс. Вам не нужна другая логика для вызова методов или проверки свойств в зависимости от приложения, с которым вы общаетесь. Вам просто нужно знать имя пути.

Я использовал systemdв качестве примера, потому что это то, что я лучше всего понимаю, но есть куча применений dbus на большинстве настольных компьютеров. Все, от аутентификации до настроек отображения, доступно на dbus.

решение2

@Stewart уже дал отличный подробный ответ о D-Bus, но я хочу дополнить его общей идеей о дизайне D-Bus.

«Традиционный» способ межпроцессного взаимодействия (IPC) в системах UNIX и Linux напрямую использует сокеты, например, процесс A открывает, /var/run/a.socketа процесс B читает/записывает в него. Это работает довольно хорошо для тесно связанных программ, которые были разработаны для взаимодействия друг с другом.

Однако вам может понадобиться связь между процессами двух программ, где программа B даже не существовала, когда была написана программа A. D-Bus пытается решить эту проблему, предоставляя протоколы для связи и обнаружения служб. Таким образом, только интерфейс b должен был существовать, когда была написана программа A, а процесс B реализует интерфейс b.

Таким образом, D-Bus можно охарактеризовать как «менеджер» IPC.

Исторически инструменты интерфейса командной строки (CLI) обычно также используют менеджер IPC, оболочку, для связи с произвольными программами с помощью каналов. Проблема с этим подходом в том, что он не обеспечивает проверку данных, стандартизированные протоколы и т. д. Таким образом, он может использоваться только опытными пользователями. Инструменты GUI в целом должны делать это «невидимо». Однако все больше и больше инструментов CLI начинают использовать D-Bus, в значительной степени как альтернативу sudo(1). Так что вы можете, как непривилегированный пользователь, выполнить systemctl poweroff, и он запросит у вас аутентификацию (это можно сравнить с UAC в Windows). В зависимости от вашего поставщика polkit это может быть даже запрос GUI. По крайней мере, в теории, этот подход более гибкий и допускает более тонкие привилегии и работает без двоичных файлов setuid (например sudo). Это можно рассматривать как функцию безопасности.

Конечно, как абстракция, это вносит некоторую сложность (по крайней мере, в зависимости программ). Однако, чем больше программ (разумно) используют его, тем меньше это бремени. Нравится ли вам D-Bus и текущая разработка, я не могу вам сказать. Но современные операционные системы, как правило, предоставляют множество важных служб за пределами ядра (и теперь снова выносят исторические вещи ядра, микроядерные) из-за более сложных требований современных вычислений. Так что, если вам «просто» нужен «простой» терминал, все это может считаться «раздутым», но индустрия требует этого по веской причине, и все больше разработчиков отмечают преимущества использования D-Bus. Это сегодняшняя замена для старого доброго конвейера в вашей оболочке (не системный интерфейс, на самом деле D-Bus использует pipe()и т. д.).

решение3

В традиционном Unix обычно мало общения между запущенными программами. Каждая программа работает в полностью отдельном адресном пространстве и взаимодействует только с ядром. Эта модель проста и надежна, но права доступа в основном слишком грубы для сред рабочего стола, а реализация мелкозернистого контроля доступа во многих случаях слишком сложна.

Одним из примеров, где ядро ​​улучшает контроль доступа, является файловая система — непривилегированные программы могут отправлять запрос на запись ядру, который преобразуется в запрос на запись, отправляемый на жесткий диск, не нарушая разделения между программами. Однако это довольно сложный уровень, и контроль все еще недостаточно хорош для современных настольных компьютеров, где пользователи могут захотеть подключить USB-накопитель.

Для других функций, например, доступа к звуковой карте, ядро ​​реализует только простую модель доступа: как только программа получает доступ к звуковой карте, она может воспроизводить и записывать звук, а также управлять элементами управления микшером, и не существует механизма для отзыва этого доступа, кроме завершения программы.

В среде настольного компьютера нам нужна более совершенная модель: браузер должен иметь возможность использовать микрофон и веб-камеру только после запроса пользователя, а когда пользователь выходит из системы, любая запущенная программа должна потерять доступ к микрофону, но если пользователь захочет запустить вычисление ночью, это все равно должно быть возможно.

Система X Window является хорошим прецедентом для осуществления контроля доступа в пользовательской программе — рендеринг в окно выполняется путем отправки запроса в другую программу, которая вычисляет конечное содержимое экрана, которое отображается. Будет ли запрос преобразован в видимое изменение содержимого экрана, решается на основе текущих настроек контроля доступа: перемещение окна на передний план дает этой программе доступ на запись в область экранного пространства, отправка его на задний план отменяет этот доступ.

В настоящее время среды рабочего стола предоставляют множество таких программ-посредников, поэтому для каждой функции должен быть протокол связи и метод открытия дескриптора этой программы.

dbus предоставляет общий протокол и брокерскую службу, где программы могут запрашивать подключение к программе, предоставляющей контроль доступа к определенным функциям. Если целевая программа уже запущена, брокер просто пересылает запросы, если она еще не запущена, брокер запускает программу по требованию, если знает, как это сделать.

Эквивалентная функциональность в Windows — это COM/DCOM в сочетании с реестром.

решение4

Кажется, все по-прежнему работает под XFCE (некоторые рабочие столы, например, gnome, могут работать)больше зависит отdbus). Я запускаю приложения черезпожарная тюрьмапоэтому потеря каких-либо предполагаемых преимуществ безопасности dbusна самом деле не является поводом для беспокойства.

Следующие дистрибутивы Linux, похоже, прекрасно работают без dbus& systemd:

Могут возникнуть незначительные проблемы, но если вы достаточно компетентны, их легко устранить.

Связанный контент