bluez5.50源码分析

    网上查找资料,没有找到详细的bluez协议栈源码分析的文档,只能自己硬着头皮看bluez的源码,这里记下我自己对源码的理解,供后来者参考。

1、bluez5源码下载地址

   https://git.kernel.org/pub/scm/bluetooth/bluez.git/tree/

2、bluez5源代码组织架构

(注:该部分是网上抄来的)

  BlueZ5源代码中有很多目录和文件:

   android/ - 用于替代android中bluedroid的android版本bluez源码。

   attrib/ - 包含gatttool 源码以及与gatt attribute相关的代码,gatttool程序入口为gatttool.c。   

   btio/ - 通过的标准socket接口与BlueZ5 kernel模块通信?。

   client/ - bluetoothctl源码,程序入口为main.c。

   doc/ - BlueZ5 API文档。

   emulator/ - 与bluetooth虚拟controller工具相关的代码?。

   gdbus/ - BlueZ5自带的内部gdbus库源码。

   gobex/ - Blue5自带的内部gobex库源码。

   lib/ - libbluetooth.so 源码,提供BlueZ4 API,用来支持某些第三方应用。

   monitor/ - btmon源码, 程序入口为main.c。

   obexd/ - obexd源码,程序入口为src/main.c。

   peripheral/ - 与蓝牙ble的GATT相关的代码?。

   plugins/ - BlueZ5插件源码(neard,autopair等插件)。

   profiles/ - BlueZ5蓝牙上层协议(a2dp,hid等)源码。

   src/ - bluetoothd源码,程序入口为main.c。

   test/ - Bluez5测试脚本。

   tools/ - Bluez5测试工具集源码。

   unit/ - PTS测试相关的一些代码?。

   README / INSTALL - 配置,编译,安装Bluez5的说明。

   Makefile.obexd - 定义obexd编译规则,此文件被include于Makefile.am中。

   Makefile.plugins - 定义BlueZ5的plugins(neard,autopair等)的编译规则, 此文件被include于Makefile.am中。

   Makefile.tools - 定义BlueZ5测试工具集的编译规则,此文件被include于 Makefile.am中。

   Makefile.am - 定义了Bluez5的编译规则。用于automake工具,生成 Makefile.in文件。

   Makefile.in - 用于configure脚本,生成最终的Makefile文件。

   configure.ac - 用于autoconf工具,生成configure脚本。

   configure - 配置编译选项,生成最终的Makefile文件,以及config.h文件

3、bluez核心代码分析

  bluez核心代码在src目录下,入口函数是main.c,bluez5编译后会生成bluetoothd可执行文件,该可执行文件在linux系统启动时自动加载,加载配置文件放在/etc/init/bluetooth.conf,下面进入main.c函数开始分析(注:bluez源码很多地方是异步操作的,看源码时经常需要根据关键词到处搜索注册的回调函数在哪里被触发)

(1)bluez5.50/src/main.c/main函数分析

int main(int argc, char *argv[])

{

         ……

         //glib库函数创建一个死循环线程用于处理事件

         event_loop = g_main_loop_new(NULL, FALSE);

         //注册信号接收处理ctrl+c等中断信号

         signal = setup_signalfd();

         ……

         //gbus总线注册bluez服务端,该函数很重要,后面详细分析

         if (connect_dbus() < 0) {

                   error("Unable to get on D-Bus");

                   exit(1);

         }

         ……

         //bluez控制器初始化,该函数很重要,后面详细分析

         if (adapter_init() < 0) {

                   error("Adapter handling initialization failed");

                   exit(1);

         }

         //bluez设备及应用层协议注册,具体用处我没有看

         btd_device_init();

         btd_agent_init();

         btd_profile_init();

         ……

         //开始死循环并处理事件

         g_main_loop_run(event_loop);

         ……

}

(2)bluez5.50/src/main.c/connect_dbus函数分析

static int connect_dbus(void)

{

         ……

         //dbus是linux多进程通信的一种方式,bluez在dbus守护进程上注册了一个连接,用于接收其它bluez用户进程的消息,处理后并返回应答消息。具体的dbus实现原理需要同志们自己找资料理解,因为bluez源码依赖dbus编程。

         //清除dbus错误标志

         dbus_error_init(&err);

         //向总线型dbus守护进程申请名为BLUEZ_NAME ("org.bluez")的连接,其它进程可以使用dbus的dbus_message_new_method_call函数发消息给这个名为BLUEZ_NAME的连接。该函数很重要,后面详细分析

         conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, BLUEZ_NAME, &err);

         ……

         //申请的连接的指针赋值给全局的连接指针

         set_dbus_connection(conn);

         //向dbus总线注册监听连接断开的信号,当连接断开时守护进程会发信号给这个已经注册的监听信号,然后回调disconnected_dbus函数处理断开连接

         g_dbus_set_disconnect_function(conn, disconnected_dbus, NULL, NULL);

         //向dbus总线注册bluez的管理对象,该对象的对象路径是”/”,用户可以编程调用该接口下面的方法获取bluez创建的所有对象以及每个对象下面的所有方法,该函数很重要,后面详细分析

         g_dbus_attach_object_manager(conn);

         ……

}

(3)bluez5.50/gdbus/mainloop.c/g_dbus_setup_bus函数分析

DBusConnection *g_dbus_setup_bus(DBusBusType type, const char *name,

                                                                 DBusError *error)

{

         ……

         //向dbus总线申请一个连接

         conn = dbus_bus_get(type, error);

         ……

         //向dbus总线申请给该连接起一个名字,其它进程就可以向改名字的连接发送dbus消息了。另外注册了一些dbus的观察函数,具体用处不是特别清楚

         if (setup_bus(conn, name, error) == FALSE) {

         ……

}

(4)bluez5.50/gdbus/object.c/g_dbus_attach_object_manager函数分析

gboolean g_dbus_attach_object_manager(DBusConnection *connection)

{

         ……

         //向dbus总线的”/”路径的对象注册一个包含该对象的所有数据存放地址的指针,便于程序在其它地方使用dbus_connection_get_object_path_data函数通过”/”路径获取指针。该函数很重要,后面详细分析

         data = object_path_ref(connection, "/");

         ……

         //该对象添加名为DBUS_INTERFACE_OBJECT_MANAGER宏定义的接口,接口注册了一个方法和一个信号,当其它进程使用dbus_message_new_method_call函数发消息给该对象的该接口方法时,generic_table里的generic_message会被调用,然后manager_methods会被调用,具体的调用流程后面会详细介绍

         add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,

                                               manager_methods, manager_signals,

                                               NULL, data, NULL);

     ……

}

(5)bluez5.50/gdbus/object.c/object_path_ref函数分析

static struct generic_data *object_path_ref(DBusConnection *connection,

                                                                 const char *path)

{

         ……

         //判断”/”路径的对象有没有已经申请存放该对象的存储空间,如果已经申请了,返回的data指针不为空

         if (dbus_connection_get_object_path_data(connection, path,

                                                        (void *) &data) == TRUE) {

         ……

         //向dbus总线注册该对象,当其它进程使用dbus_message_new_method_call函数发消息给该对象时,generic_table里的generic_message会被调用

         if (!dbus_connection_register_object_path(connection, path,

                                                        &generic_table, data)) {

         ……

         //把对象添加到对象链表data->objects里,便于程序在其它地方查找所有对象

         invalidate_parent_data(connection, path);

         ……

}

(6)bluez5.50/gdbus/object.c/generic_message函数分析

static DBusHandlerResult generic_message(DBusConnection *connection,

                                               DBusMessage *message, void *user_data)

{

         ……

         Dbus接收从其他进程发来的消息,过滤出消息的接口名字

         interface = dbus_message_get_interface(message);

         //根据接口名字查找之前已经注册的对应接口

         iface = find_interface(data->interfaces, interface);

         ……

         //检查完参数后开始处理消息

         return process_message(connection, message, method,

                                                                 iface->user_data);

}

(7)bluez5.50/gdbus/object.c/process_message函数分析

static DBusHandlerResult process_message(DBusConnection *connection,

                            DBusMessage *message, const GDBusMethodTable *method,

                                                                 void *iface_user_data)

{

         ……

         //回调已经注册的接口对应的方法,具体使用例子在后面详细介绍

         reply = method->function(connection, message, iface_user_data);

         ……

         //发送应答消息

         g_dbus_send_message(connection, reply);

         ……

}

(8)bluez5.50/src/adapter.c/adapter_init函数分析

int adapter_init(void)

{

         ……

         //构造访问hci接口的结构体,该函数很重要,后面详细分析

         mgmt_master = mgmt_new_default();

……

//hci接口向内核注册的蓝牙控制器发送命令,收到对应返回命令时调用read_version_complete回调函数进行处理。

if (mgmt_send(mgmt_master, MGMT_OP_READ_VERSION,

                                     MGMT_INDEX_NONE, 0, NULL,

                                     read_version_complete, NULL, NULL) > 0)

}

(9)bluez5.50/src/shared/mgmt.c/mgmt_new_default函数分析

struct mgmt *mgmt_new_default(void)

{

         ……

         //使用socket打开hci驱动接口,和open访问驱动设备类似。明白这个需要自己去了解linux蓝牙驱动的相关知识,这里不介绍

         fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,

                                                                           BTPROTO_HCI);

         ……

         //构造发送hci命令的结构体。该函数很重要,后面详细分析

         mgmt = mgmt_new(fd);

}

(10)bluez5.50/src/shared/mgmt.c/mgmt_new函数分析

struct mgmt *mgmt_new(int fd)

{

         ……

         //使用glib库的io注册功能把fd描述符添加监控列表里,详情看bluez5.50/src/shared/io-glib.c/io_new函数的实现

         mgmt->io = io_new(fd);

         ……

         //使用glib库的io功能添加监控fd读变化的功能,当hci接口有应答数据时,fd读操作状态改变,can_read_data回调函数被调用。详情看bluez5.50/src/shared/io-glib.c/ io_set_read_handler函数的实现

         if (!io_set_read_handler(mgmt->io, can_read_data, mgmt, NULL)) {

}

(11)bluez5.50/src/shared/mgmt.c/can_read_data函数分析

static bool can_read_data(struct io *io, void *user_data)

{

         ……

         //根据hci接口返回的应答数据的事件类型进行不同处理

         switch (event) {

         ……

         //当返回的事件类型是命令完成时执行如下函数

         request_complete(mgmt, cc->status, opcode, index, length - 3,

                                                        mgmt->buf + MGMT_HDR_SIZE + 3);

         ……

         //当返回的事件类型是命令状态时执行如下函数

         request_complete(mgmt, cs->status, opcode, index, 0, NULL);

         ……

         //其它事件时执行如下的通知函数,作用是通知已经注册到mgmt->notify_list链表的通知操作

         process_notify(mgmt, event, index, length,

                                                        mgmt->buf + MGMT_HDR_SIZE);

}

(12)bluez5.50/src/shared/mgmt.c/request_complete函数分析

static void request_complete(struct mgmt *mgmt, uint8_t status,

                                               uint16_t opcode, uint16_t index,

                                               uint16_t length, const void *param)

{

         ……

         //执行在hci接口发送命令时已经注册的命令完成回调函数,例如read_version_complete就是一个注册的回调函数

         request->callback(status, length, param,

                                                                 request->user_data);

         ……

         //使用glib的io功能把fd的写功能添加进去,当fd能写时,把需要发送的hci命令发送给驱动

         wakeup_writer(mgmt);

}

(13)bluez5.50/src/adapter.c/read_version_complete函数分析

static void read_version_complete(uint8_t status, uint16_t length,

                                               const void *param, void *user_data)

{

         ……

         //注册蓝牙控制器个数增加时的通知信号,当驱动发现蓝牙控制器被插入时,发送事件通知命令,process_notify函数会被执行,在该函数中会调用已经注册的index_added函数申请新的适配器存储空间

         mgmt_register(mgmt_master, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,

                                                        index_added, NULL, NULL);

         ……

         //发送hci命令获取蓝牙适配器(蓝牙控制器)的个数,收到响应命令时回调read_index_list_complete函数

         if (mgmt_send(mgmt_master, MGMT_OP_READ_INDEX_LIST,

                                     MGMT_INDEX_NONE, 0, NULL,

                                     read_index_list_complete, NULL, NULL) > 0)

         ……

}

(14)bluez5.50/src/adapter.c/read_index_list_complete函数分析

static void read_index_list_complete(uint8_t status, uint16_t length,

                                               const void *param, void *user_data)

{

         ……

         //获取适配器的个数,然后根据index值注册所有的适配器

         index_added(index, 0, NULL, NULL);

         ……

}

(15)bluez5.50/src/adapter.c/index_added函数分析

static void index_added(uint16_t index, uint16_t length, const void *param,

                                                                 void *user_data)

{

         ……

         //查找适配器链表adapter_list里有没有编号为index的适配器存在

         adapter = btd_adapter_lookup(index);

         ……

         //根据index创建新的适配器

         adapter = btd_adapter_new(index);

         ……

         //把新创建的适配器指针添加到适配器链表里,方便其它地方查询

         adapter_list = g_list_append(adapter_list, adapter);

         ……

         //发送hci接口命令给驱动层,获取index对应的适配器的详细信息,读取到结果后会回调read_info_complete函数

         if (mgmt_send(mgmt_master, MGMT_OP_READ_INFO, index, 0, NULL,

                                               read_info_complete, adapter, NULL) > 0)

         ……

}

(16)bluez5.50/src/adapter.c/read_info_complete函数分析

static void read_info_complete(uint8_t status, uint16_t length,

                                               const void *param, void *user_data)

{

         ……

         //设置适配器的bdaddr等,然后为适配器注册dbus对象,对象路径为"/org/bluez/hci%d",对象接口名为"org.bluez.Adapter1",接口方法为adapter_methods

         err = adapter_register(adapter);

         ……

         //注册设备发现函数,当驱动层扫描到新的蓝牙设备时,发送通知给应用层,应用层会触发can_read_data函数,然后调用到process_notify函数,然后调用到mgmt->notify_list链表,而device_found_callback函数是添加在mgmt->notify_list链表上的,所以会被执行

         mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_FOUND,

                                                        adapter->dev_id,

                                                        device_found_callback,

                                                        adapter, NULL);

         ……

}

(17)bluez5.50/src/adapter.c/adapter_register函数分析

static int adapter_register(struct btd_adapter *adapter)

{

         ……

         //指定适配器注册到dbus总线上的对象的路径

         adapter->path = g_strdup_printf("/org/bluez/hci%d", adapter->dev_id);

         //为适配器注册dbus对象,对象路径为"/org/bluez/hci%d",对象接口名为"org.bluez.Adapter1",接口方法为adapter_methods,接口属性为adapter_properties

         if (!g_dbus_register_interface(dbus_conn,

                                               adapter->path, ADAPTER_INTERFACE,

                                               adapter_methods, NULL,

                                               adapter_properties, adapter,

                                               adapter_free)) {

         ……

         //把当前适配器添加到adapters链表

         adapters = g_slist_append(adapters, adapter);

         ……

}

4、bluetoothctl工具代码分析

Bluetoothctl工具的入口程序是bluez5.50/client/main.c中的main函数,现在跳到main函数开始分析

(1)bluez5.50/client/main.c/main函数分析

int main(int argc, char *argv[])

{

         ……

         //命令行输入初始化,该函数里面调用rl_init函数,这是linux的命令行功能,里面的rl_handler函数在键盘输入字符是会被调用,从而解析出命令

         bt_shell_init(argc, argv, &opt);

         ……

         //向dbus系统总线注册一个连接

         dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);

         //绑定管理对象,这个好像没什么用

         g_dbus_attach_object_manager(dbus_conn);

         //申请一个client结构体存储空间,并注册接收其它dbus总线发来的信号的回调函数,g_dbus_client_new里面调用了g_dbus_client_new_full函数,后面直接分析该函数

         client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");

         ……

         //注册代理,bluez核心代码里向dbus系统总线注册了多个对象,例如”/”、” /org/bluez/hci%d”对象等,每个对象里有多个接口,例如” /org/bluez/hci%d”对象里提供了名字为” org.bluez.Adapter1”的接口,该接口下面有"StartDiscovery"方法等。每个接口放在一个代理存储空间里,代理里存放了接口的名字,接口有哪些方法,有哪些属性,接口的对象路径地址等,这样便于程序通过代理链表查找。该函数里面调用了get_managed_objects函数,后面直接分析该函数

         g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,

                                                                 property_changed, NULL);

         ……

}

(2)bluez5.50/client/client.c/g_dbus_client_new_full函数分析

GDBusClient *g_dbus_client_new_full(DBusConnection *connection,

                                                                 const char *service,

                                                                 const char *path,

                                                                 const char *root_path)

{

         ……

         //dbus总线的注册方法,当其它进程广播dbus信号时,message_filter函数会被调用

if (dbus_connection_add_filter(connection, message_filter,

                                                        client, NULL) == FALSE) {

         ……

}

(3)bluez5.50/client/client.c/message_filter函数分析

static DBusHandlerResult message_filter(DBusConnection *connection,

                                               DBusMessage *message, void *user_data)

{

         ……

         //用g_dbus_client_set_signal_watch函数注册的信号的回调函数会被调用

         client->signal_func(connection, message, client->signal_data);

}

(4)bluez5.50/client/client.c/get_managed_objects函数分析

static void get_managed_objects(GDBusClient *client)

{

         ……

         //使用dbus库函数向bluez核心代码发送获取所有被管理的对象。调用时传入的参数是bluez核心进程dbus连接名称”"org.bluez",对象名称是”/”,接口方法是DBUS_INTERFACE_OBJECT_MANAGER的宏定义名称,接口方法的名字是"GetManagedObjects"。我们在bluez5.50/src/mian.c/main函数中调用connect_dbus->g_dbus_attach_object_manager->add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,manager_methods, manager_signals,NULL, data, NULL);在这个函数中注册了manager_methods方法。当bluez核心进程收到当前进程的GetManagedObjects方法时,manager_methods方法列表中的get_objects函数会被调用

         msg = dbus_message_new_method_call(client->service_name,

                                                        client->root_path,

                                                        DBUS_INTERFACE_OBJECT_MANAGER,

                                                        "GetManagedObjects");

         ……

         //当收到bluez核心进程的应答消息是改注册函数里的get_managed_objects_reply方法会被调用

         dbus_pending_call_set_notify(client->get_objects_call,

                                                        get_managed_objects_reply,

                                                        client, NULL);

}

(5)bluez5.50/gdbus/object.c/get_objects函数分析

static DBusMessage *get_objects(DBusConnection *connection,

                                     DBusMessage *message, void *user_data)

{

         ……

         //搜索data->objects链表上所有的dbus对象,对每个对象调用append_object回调函数处理。例如创建的根目录对象”/”和蓝牙适配器对象"/org/bluez/hci%d"都添加在data->objects链表上。data->objects链表中的数据是注册dbus对象时调用invalidate_parent_data函数添加到链表上的。append_object函数里面调用append_interfaces函数,接着调用append_interface,接着调用append_properties,接着调用append_property

         g_slist_foreach(data->objects, append_object, &array);

}

(6)bluez5.50/gdbus/object.c/append_property函数分析

static void append_property(struct interface_data *iface,

                            const GDBusPropertyTable *p, DBusMessageIter *dict)

{

         ……

         //适配器注册dbus时添加了adapter_properties,所以p->get会逐个调用adapter_properties列表里的property_get_address函数,一直调用到property_get_modalias函数,也就是适配器的属性信息都将被读取并返回给用户。当扫描到蓝牙设备后,蓝牙设备注册到dbus里的device_properties列表下的get函数也会被调用

         p->get(p, &value, iface->user_data);

         ……

}

(7)bluez5.50/gdbus/client.c/get_managed_objects_reply函数分析

static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)

{

         ……

         //解析所有的管理对象及对象下所有的接口,给每个对象申请一个代理。该函数里调用parse_managed_objects->parse_interfaces->parse_properties

         parse_managed_objects(client, reply);

         ……

         //获取每个接口下的所有属性

         refresh_properties(client->proxy_list);

         ……

}

(8)bluez5.50/gdbus/client.c/parse_properties函数分析

static void parse_properties(GDBusClient *client, const char *path,

                                     const char *interface, DBusMessageIter *iter)

{

         ……

         //查看proxy_list链表里有没有名字为interface的接口代理,初始化时默认是没有的

         proxy = g_dbus_proxy_lookup(client->proxy_list, NULL,

                                                        path, interface);

         ……

         //申请接口代理,并把代理添加到proxy_list链表上

         proxy = proxy_new(client, path, interface);

         ……

         //获取每个接口的属性信息,并把第一个适配器接口设置为默认适配器,第一个扫描到的设备作为默认设备

         update_properties(proxy, iter, FALSE);

         //根据接口类型把接口代理进行分类。例如接口是适配器接口,就把接口代理添加到适配器链表,设备接口就把接口代理添加到扫描它的适配器链表下的设备链表上。该函数里调用client->proxy_added(proxy, client->user_data),又client->proxy_added=proxy_added

         proxy_added(client, proxy);

}

(9)bluez5.50/client/main.c/proxy_added函数分析

static void proxy_added(GDBusProxy *proxy, void *user_data)

{

         ……

         //获取代理的接口名

         interface = g_dbus_proxy_get_interface(proxy);

         ……

         //接口名字是"org.bluez.Device1"时,把该代理添加到扫描它的适配器的设备链表上

         device_added(proxy);

         ……

         //接口名字是"org.bluez.Adapter1"时,把代理添加到适配器链表

         adapter_added(proxy);

}

5、bluetoothctl工具部分命令实现分析

(1)bluez5.50/client/main.c/ cmd_list函数分析

static void cmd_list(int argc, char *argv[])

{

         ……

         // 打印所有的适配器地址,ctrl_list链表存放所有适配器代理,在adapter_new函数中把适配器加入ctrl_list链表

         for (list = g_list_first(ctrl_list); list; list = g_list_next(list))

}

(2)bluez5.50/client/main.c/ cmd_scan函数分析

static void cmd_scan(int argc, char *argv[])

{

         ……

         //发送设置扫描过滤消息给bluez核心进程,主要设置扫描到有效设备的信号强度阈值等

         set_discovery_filter();

         ……

         //发送启动扫描设备消息给bluez核心进程,bluez核心进程会调用bluez5.50/src/adapter.c/start_discovery函数,当调用收到响应消息后start_discovery_reply函数会被调用

         if (g_dbus_proxy_method_call(default_ctrl->proxy, method,

                                     NULL, start_discovery_reply,

                                     GUINT_TO_POINTER(enable), NULL) == FALSE) {

}

(3)bluez5.50/src/adapter.c/start_discovery函数分析

static DBusMessage *start_discovery(DBusConnection *conn,

                                               DBusMessage *msg, void *user_data)

{

         ……

         //触发开始扫描设备,设置扫描超时时间,该函数里调用trigger_start_discovery函数,当超时时间到了会调用start_discovery_timeout函数

         err = update_discovery_filter(adapter);

         ……

}

(4)bluez5.50/src/adapter.c/start_discovery_timeout函数分析

static gboolean start_discovery_timeout(gpointer user_data)

{

         ……

         //调用hci接口发送启动扫描命令给指定蓝牙适配器,当适配器启动扫描设备时,会通过hci接口发送响应命令,这时bluez5.50/src/mgmt.c/can_read_data被调用,里面调用request_complete,里面调用request->callback,而start_discovery_complete函数就注册在request->callback里。start_discovery_complete-> g_dbus_emit_property_changed-> g_dbus_emit_property_changed_full-> add_pending。该函数里注册了 process_changes函数,在主循环空闲时,process_changes函数被调用。process_changes函数里调用emit_interfaces_added函数,里面调用dbus_message_new_signal(root->path,

                                               DBUS_INTERFACE_OBJECT_MANAGER,

                                               "InterfacesAdded");这个函数把增加的接口通过dbus信号广播给bluetoothctl进程。

         mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,

                                     adapter->dev_id, sizeof(cp), &cp,

                                     start_discovery_complete, adapter, NULL);

}

(5)bluez5.50/src/adapter.c/ device_found_callback函数分析

static void device_found_callback(uint16_t index, uint16_t length,

                                               const void *param, void *user_data)

{

         ……

         //启动扫描设备后,当适配器扫描到设备后,驱动程序会通过hci接口发设备信息响应包给bluez核心进程。Bluez核心进程里can_read_data会被触发,最后调用到device_found_callback函数。该函数目的是为扫描到的设备在dbus总线上添加一个设备对象,并把该设备所有的信息绑定到给设备对象上,方便其它进程通过dbus消息获取设备信息

         update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,

                                               ev->rssi, confirm_name, legacy,

                                               flags & MGMT_DEV_FOUND_NOT_CONNECTABLE,

                                               eir, eir_len);

}

(6)bluez5.50/src/adapter.c/ update_found_devices函数分析

static void update_found_devices(struct btd_adapter *adapter,

                                               const bdaddr_t *bdaddr,

                                               uint8_t bdaddr_type, int8_t rssi,

                                               bool confirm, bool legacy,

                                               bool not_connectable,

                                               const uint8_t *data, uint8_t data_len)

{

         ……

         //查看当前适配器的设备链表adapter->devices上有没有设备地址是bdaddr的设备存在,默认是不存在该设备的

         dev = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);

         ……

         //把新设备作为一个新的dbus对象添加到dbus总线上

         dev = adapter_create_device(adapter, bdaddr, bdaddr_type);

         ……

}

(7)bluez5.50/src/adapter.c/ adapter_create_device函数分析

static struct btd_device *adapter_create_device(struct btd_adapter *adapter,

                                                        const bdaddr_t *bdaddr,

                                                        uint8_t bdaddr_type)

{

         ……

         //创建新的设备dbus对象,device_create-> device_new

         device = device_create(adapter, bdaddr, bdaddr_type);

         ……

         //把设备添加到适配器的设备链表adapter->devices上

         adapter->devices = g_slist_append(adapter->devices, device);

}

(8)bluez5.50/src/device.c/ device_new函数分析

static struct btd_device *device_new(struct btd_adapter *adapter,

                                     const char *address)

{

         ……

         //给设备赋值一个dbus对象的路径

         device->path = g_strdup_printf("%s/dev_%s", adapter_path, address_up);

         ……

         //给设备注册dbus对象,对象路径是device->path,对象下面注册一个接口名为DEVICE_INTERFACE,接口提供了方法集合device_methods,属性集合device_properties

         if (g_dbus_register_interface(dbus_conn,

                                               device->path, DEVICE_INTERFACE,

                                               device_methods, NULL,

                                               device_properties, device,

                                               device_free) == FALSE)

         ……

}

(9)bluez5.50/gdbus/client.c/ g_dbus_client_new_full函数分析

GDBusClient *g_dbus_client_new_full(DBusConnection *connection,

                                                                 const char *service,

                                                                 const char *path,

                                                                 const char *root_path)

{

         ……

         //在main初始化过程中在这给函数中注册了一个接口增加回调函数,当bluez核心进程发送"InterfacesAdded"该信号时,bluetoothctl进程会触发调用interfaces_added函数。interfaces_added-> parse_interfaces-> parse_properties-> proxy_added,最后把新增的接口根据类型添加到适配器列表、设备列表或其他列表

         client->added_watch = g_dbus_add_signal_watch(connection, service,

                                                        client->root_path,

                                                        DBUS_INTERFACE_OBJECT_MANAGER,

                                                        "InterfacesAdded",

                                                        interfaces_added,

                                                        client, NULL);

         ……

}

到这里,终于解释完了cmd_scan

(10)bluez5.50/client/main.c/ cmd_connect函数分析

static void cmd_connect(int argc, char *argv[])

{

         ……

         //发送连接设备消息给bluez核心进程,bluez核心进程收到消息后会调用bluez5.50/src/device.c/dev_connect函数。dev_connect->device_connect_le->bt_io_connect->l2cap_connect->connect最终发起设备连接

         if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,

                                                                 proxy, NULL) == FALSE) {

         ……

}

到此结束,其它的还没看明白。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章