浅谈 D-Bus、udevd 和 hald

  D-Bus 是针对桌面环境优化的 IPC(Inter-Process Communication,进程间通信)机制,用于进程间的通信或进程与内核的通信。最基本的 D-Bus 协议是一对一的通信协议。但在很多情况下,通信的一方是消息总线。消息总线是一个特殊的应用,它同时与多个应用通信,并在应用之间传递消息。下面我们会在实例中观察消息总线的作用。消息总线的角色有点类似与X系统中的窗口管理器,窗口管理器既是X客户,又负责管理窗口。
  支持 D-Bus 的系统都有两个标准的消息总线:系统总线和会话总线。系统总线用于系统与应用的通信;会话总线用于应用之间的通信。
  如果应用程序使用了 libdbus 就能够接收到来自内核的有关硬件热插拔的通知,比如U盘的插入和拔出。那么,其中经过了怎样的过程呢。
  首先,udev 通过 NetLink 注册内核的设备事件,当有设备插入/拔除时,udev 就会收到通知,它会从事件中所带参数和 sysfs 中的信息,加载适当的驱动程序(也可以通过 hald 去运行应用程序让用户选择可用的驱动),创建 dev 下的结点,让设备处于可用的状态。
  接着,dev 把设备插入/拔除的事件通过 socket:/org/freedesktop/hal/udev_event 转发给 HALD 的。
  然后,HALD 挂在 socket:/org/freedesktop/hal/udev_event 上等待事件,有事件发生时就调用相关函数处理,它先从事件中取出主要参数,创建一个 hotplug_event 对象,把它放入事件队列中,创建一个设备对象,设置设备的属性,调用相关 callouts,然后放入设备列表中,并触发 signal 让 dbus 通知相关应用程序。如果是拔除设备,则调用相关 callouts,然后从设备列表中删除,并触发 signal 让 dbus 通知相关应用程序。

  hal(hardware abstract lever)硬件抽象。Linux 的 hal 运行于用户空间作为一个 daemon 进程。监听一个 socket 接口。等待 udev 发来的通知。 udev 为设备加载驱动,设备可用后,往往有 udev 的规则,让 udev 通知 hald 表示设备变动了。 hal 作为一个硬件的数据库,记录了硬件的属性,当前硬件有哪些,他们的属性是什么,等等信息。 因而,用户态程序可以查询hald得到硬件的信息。也可以注册监听事件在 hald 上面。当监听的硬件事件发生时候,hald 会通知他们。

浅谈 D-Bus、udevd 和 hald

说明:
  1、实线箭头为主动调用,虚线箭头为事件上报。
  2、udev 通过 NetLink 注册内核的设备事件,当有设备插入/拔除时,udev 就会收到通知,它会从事件中所带参数和 sysfs 中的信息,加载适当的驱动程序,创建 dev 下的结点,让设备处于可用的状态。
  3、udev 只是一个框架,它的行为完全受它的规则所控制,这些规则存放在目录 /etc/udev/rules.d/中,其中 90-hal.rules 是用来让 udev 把设备插入/拔除的事件通过socket:/org/freedesktop/hal/udev_event 转发给 HAL 的。
  4、HAL 挂在 socket:/org/freedesktop/hal/udev_event 上等待事件,有事件发生时就调用函数 hald_udev_data 处理,它先从事件中取出主要参数,创建一个 hotplug_event 对象,把它放入事件队列中,然后调用 hotplug_event_process_queue 处理事件。
  5、函数 hotplug_event_begin 负责具体事件的处理,它把全部事件分为四类,并分别处理 hotplug_event_begin_sysfs 处理普通设备事件,hotplug_event_begin_acpi 处理 ACPI 事件,hotplug_event_begin_apm 处理 APM 事件,hotplug_event_begin_pmu 处理 PMU 事件。要注意的是,后三者的事件源并非源于 udev,而是在 device_reprobe 时触发的(osspec_device_reprobe/hotplug_reprobe_tree/hotplug_reprobe_generate_add_events/acpi_generate_add_hotplug_event)。
  6、函数 hotplug_event_begin_sysfs 中,如果是插入设备,则创建一个设备对象,设置设备的属性,调用相关 callouts,然后放入设备列表中,并触发 signal 让 dbus 通知相关应用程序。如果是拔除设备,则调用相关 callouts,然后从设备列表中删除,并触发 signal 让 dbus 通知相关应用程序。
  7、应用程序可以主动调用 HAL 提供的 DBUS 接口函数,这些函数在 libhal.h 中有定义。应用程序也可以注册 HAL 的 signal,当设备变化时,HAL 通过 DBUS 上报事件给应用程序。
  8、callout 是 HAL 一种扩展方式,它在设备插入/拔除时执行。可以在设备信息文件中(/usr/share/hal 目录)指定。
  9、addon 也是 HAL 一种扩展方式,它与 callout 的不同之处在于 addon 往往是事件的触发者,而不是事件的消费者。HAL 的事件源主要源于 udev,而 udev 源于 kernel 的 hotplug,然而有的设备如电源设备、磁盘设备和特殊按键等,它们并不产生 hotplug 事件。HAL 就得不到通知,怎么办呢,addon 就是用于支持新事件源的扩展方式。比如 addon-acpi 从 /proc/acpi/event 或者 /var/run/acpid.socket 收到事件,然后转发成 HAL 事件。addon-storage 检测光盘或磁盘的状态,并设置设备的属性。addon-keyboard 检测一些特殊按键,并触发相应事件。
(access-check/ci-tracker/ck-tracker 负责权限的检查,里面提到的 PolicyKit/ConsoleKit 不是太熟悉,有时间再看看。)
  简单的说,HAL 就是一个设备数据库,它管理当前系统中所有的设备,你可以以多种灵活的方式去查询这些设备,可以获取指定设备的特性,可以注册设备变化事件。

Hal的功能:
  1、获取指定类型的设备列表。
  2、获取/更改设备的属性值。
  3、获取设备具有的能力描述。
  4、设备插入/拔除时,通知相关应用程序。
  5、设备属性或能力变化时,通知相关应用程序。


参考文章:
【1】 http://www.linuxidc.com/Linux/2011-01/31238.htm
【2】 http://blog.****.net/faithsws/article/details/5380710