[android源码分析]bluetoothd service的启动的总体流程分析

本文解析了bluetoothd服务启动过程,包括权限设置、命令行参数解析、后台运行、日志初始化、信号处理、配置文件加载及解析等步骤,并介绍了D-Bus连接、SDP服务器启动和插件初始化等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇文章将会从总体流程上解释一下每一个函数的意义,具体的每一个函数的解释将是一个很长的过程,后面的文章中我将会针对每一个有意义的函数来具体分析。

在具体分析bluetoothdservice的启动之前,我们先来看一下bluetoothd service究竟是什么,他同样定义在init.rc中:

servicebluetoothd /system/bin/bluetoothd -n

         所以,很清楚,他就是执行bluetoothd这个应用。那么bluetoothd是由哪个文件编译出来的呢,搜索一下就会在bluez下面的src中的Android.mk发现其踪迹:

[plain]  view plain copy
  1. #  
  2. # bluetoothd  
  3. #  
  4.   
  5. include $(CLEAR_VARS)  
  6.   
  7. LOCAL_SHARED_LIBRARIES := \  
  8.     libbluetoothd  
  9.   
  10. LOCAL_MODULE:=bluetoothd  

所以,很清楚了,我们就在src目录下面看一下了,作为一个应用程序,第一个映入我们眼帘的肯定就是main了,正好下面有一个main.c,然后里面还有一个main函数,哈哈,你懂的:

[cpp]  view plain copy
  1. int main(int argc, char *argv[])  
  2. {  
  3.     GOptionContext *context;  
  4.     GError *err = NULL;  
  5.     struct sigaction sa;  
  6.     uint16_t mtu = 0;  
  7.     GKeyFile *config;  
  8. //这个函数就是用来设置uid和capability的,他主要是使得该应用在访问kernel的时候能够有权限  
  9. //从注册可以看到,说目前的android init rc并不支持权限的赋予,所以只能出此下策,毫无疑问,我们需要走到这个ifdef中  
  10. //当然我们也可以从理论上去check一下,在Android.mk中是有这个宏的define的  
  11. #ifdef ANDROID_SET_AID_AND_CAP  
  12.     /* Unfortunately Android's init.rc does not yet support applying 
  13.      * capabilities. So we must do it in-process. */  
  14.     void *android_set_aid_and_cap(void);  
  15.     //这个就是设置uid为AID_BLUETOOTH,  
  16.     //设置capbility为CAP_NET_RAW| CAP_NET_ADMIN| CAP_NET_BIND_SERVICE  
  17.     android_set_aid_and_cap();  
  18. #endif  
  19.     //默认的初始化,详细分析见2.2.1  
  20.     init_defaults();  
  21. //既然我们上面已经想法设法得到权限了,这里就必然不会再把权限释放了。  
  22. //这个ifdef是不会进去了  
  23. #ifdef HAVE_CAPNG  
  24.     /* Drop capabilities */  
  25.     capng_clear(CAPNG_SELECT_BOTH);  
  26.     capng_updatev(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED,  
  27.                     CAP_NET_BIND_SERVICE, CAP_NET_ADMIN,  
  28.                         CAP_NET_RAW, CAP_IPC_LOCK, -1);  
  29.     capng_apply(CAPNG_SELECT_BOTH);  
  30. #endif  
  31.     //这里是解析命令项  
  32.     //使用的是glib命令行解析库  
  33.     context = g_option_context_new(NULL);  
  34.     //就是根据options定义的内容,自动解析到对应的变量中了  
  35.     //详细见2.2.2  
  36.     g_option_context_add_main_entries(context, options, NULL);  
  37.   
  38.     if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {  
  39.         if (err != NULL) {  
  40.             g_printerr("%s\n", err->message);  
  41.             g_error_free(err);  
  42.         } else  
  43.             g_printerr("An unknown error occurred\n");  
  44.         exit(1);  
  45.     }  
  46.   
  47.     g_option_context_free(context);  
  48.     //下面就是根据上面解析得到的值来看是否需要做一些对应的操作  
  49.     //从init rc中,我们可以看到只有一个-n的参数,但是,我们看是G_OPTION_FLAG_REVERS,猜猜看吧,是的,就是反转的意思,所以option_detach还是false,其它的就都可以忽略了  
  50.     if (option_version == TRUE) {  
  51.         printf("%s\n", VERSION);  
  52.         exit(0);  
  53.     }  
  54.   
  55.     if (option_udev == TRUE) {  
  56.         int err;  
  57.   
  58.         option_detach = TRUE;  
  59.         err = connect_dbus();  
  60.         if (err < 0) {  
  61.             if (err == -EALREADY)  
  62.                 exit(0);  
  63.             exit(1);  
  64.         }  
  65.     }  
  66.     //后台运行,这里也就不去  
  67.     if (option_detach == TRUE && option_udev == FALSE) {  
  68.         if (daemon(0, 0)) {  
  69.             perror("Can't start daemon");  
  70.             exit(1);  
  71.         }  
  72.     }  
  73.     //重新设置权限  
  74.     umask(0077);  
  75.     //bt log的初始化,这里就不关心了,android中若想打印log需要重新修改  
  76.     __btd_log_init(option_debug, option_detach);  
  77.     //设置一个signal的处理函数,不一一看了,关系不大  
  78.     memset(&sa, 0, sizeof(sa));  
  79.     sa.sa_flags = SA_NOCLDSTOP;  
  80.     sa.sa_handler = sig_term;  
  81.     sigaction(SIGTERM, &sa, NULL);  
  82.     sigaction(SIGINT,  &sa, NULL);  
  83.   
  84.     sa.sa_handler = sig_debug;  
  85.     sigaction(SIGUSR2, &sa, NULL);  
  86.   
  87.     sa.sa_handler = SIG_IGN;  
  88.     sigaction(SIGPIPE, &sa, NULL);  
  89.     //加载配置文件  
  90.     config = load_config(CONFIGDIR "/main.conf");  
  91.     //解析配置文件,这里就是根据main.conf中的配置进行相应的设置  
  92.     //详细分析见2.2.3  
  93.     parse_config(config);  
  94.     //这里就是初始化dbus  
  95.     agent_init();  
  96.   
  97.     if (option_udev == FALSE) {  
  98.         //连接dbus  
  99.         if (connect_dbus() < 0) {  
  100.             error("Unable to get on D-Bus");  
  101.             exit(1);  
  102.         }  
  103.     } else {  
  104.         if (daemon(0, 0)) {  
  105.             perror("Can't start daemon");  
  106.             exit(1);  
  107.         }  
  108.     }  
  109.     //启动sdp server,详细分析见2.2.4  
  110.     start_sdp_server(mtu, main_opts.deviceid, SDP_SERVER_COMPAT);  
  111.     //在main.conf中attrib_server=false,所以这里就不进入了  
  112.     if (main_opts.attrib_server) {  
  113.         if (attrib_server_init() < 0)  
  114.             error("Can't initialize attribute server");  
  115.     }  
  116.     /* Loading plugins has to be done after D-Bus has been setup since 
  117.      * the plugins might wanna expose some paths on the bus. However the 
  118.      * best order of how to init various subsystems of the Bluetooth 
  119.      * daemon needs to be re-worked. */  
  120. //从注释来看,plugins的加载最好是在D-Bus已经建立完成的基础上。  
  121. //他们也认为这个地方做好再重写一下,我们就先将就着看看吧  
  122. //这里的option_plugin和option_noplugin都是null,因为我们的bluetoothd中并没有他们的参数  
  123. //包含了hciops,audio,input,network,health  
  124. //具体参见2.2.5中  
  125.     plugin_init(config, option_plugin, option_noplugin);  
  126.     //创建主循环  
  127.     event_loop = g_main_loop_new(NULL, FALSE);  
  128.     //adapter的ops的建立,详细分析见2.2.6  
  129.     if (adapter_ops_setup() < 0) {  
  130.         error("adapter_ops_setup failed");  
  131.         exit(1);  
  132.     }  
  133.     //会根据remember_powered参数来决定是否需要做什么,我们这里是是false,所以,没有做什么,直接ruturn。  
  134.     rfkill_init();  
  135.   
  136.     DBG("Entering main loop");  
  137.     //进入主循环,就卡在这边了。  
  138.     //对主循环的影响都在上面的那些signal的处理函数中,我们可以理解,没有什么异常就会卡在这边了,知道蓝牙关闭才会退出了  
  139.     g_main_loop_run(event_loop);  
  140.     //之后的内容就不再详细分析了  
  141.     ……  
  142. }  
<think>我们正在处理用户关于在Android源码中设置蓝牙MAC地址的流程的问题。根据用户的问题,我们需要提供在Android源码中设置蓝牙MAC地址的步骤。 在Android系统中,蓝牙MAC地址通常由硬件决定,但有时需要在系统层面进行设置(例如,在工厂测试或特定定制中)。设置蓝牙MAC地址的流程通常涉及修改系统属性或配置文件,并在系统启动时由蓝牙服务读取。 根据Android系统的不同版本,设置方法可能略有不同,但一般步骤如下: 1. **获取蓝牙MAC地址**:首先需要有一个合法的蓝牙MAC地址(12个十六进制字符,如`11:22:33:44:55:66`或`112233445566`)。 2. **修改系统属性文件**:在Android系统中,蓝牙MAC地址通常存储在`/persist`分区(或`/data/misc/bluetooth`等)的一个文件中,以确保在重启后仍然保留。但为了在源码中预设,我们需要在构建时包含这个地址。 3. **在构建系统中设置**:在设备特定的makefile中,可以设置一个构建属性来指定蓝牙MAC地址。例如,在`device/<manufacturer>/<device>/system.prop`文件中添加: ``` ro.bt.bdaddr_path=/persist/bluetooth/bdaddr ``` 然后,在构建时将预设的MAC地址写入到该路径。 4. **在init脚本中设置**:在设备的init脚本中(通常是`device/<manufacturer>/<device>/init.<device>.rc`),添加一个服务来在启动时设置蓝牙MAC地址。例如: ``` service set_bt_addr /system/bin/sh /system/bin/set_bt_addr.sh class main user root group root oneshot ``` 5. **创建设置脚本**:在`/system/bin/`下放置一个脚本(如`set_bt_addr.sh`),该脚本将预设的MAC地址写入到蓝牙配置文件。注意,这个脚本需要有执行权限。脚本内容可能如下: ```bash #!/system/bin/sh BT_ADDR_FILE="/persist/bluetooth/bdaddr" if [ ! -f "$BT_ADDR_FILE" ]; then echo "11:22:33:44:55:66" > $BT_ADDR_FILE chmod 644 $BT_ADDR_FILE fi ``` 6. **确保权限**:确保`/persist`分区在第一次启动时可写,并且脚本有执行权限。这需要在设备的makefile中将脚本复制到系统镜像中,并设置权限。 7. **蓝牙服务读取地址**:Android的蓝牙服务(如bluetoothd)在启动时会从预设的文件中读取MAC地址。 注意:在Android 6.0(API 23)之后,设置蓝牙MAC地址的方式可能有所变化。另外,由于硬件限制,某些设备可能无法通过软件更改蓝牙MAC地址。 另一种方法是在内核启动参数中设置蓝牙MAC地址,这取决于蓝牙芯片的驱动支持。 由于用户要求的是在Android源码中的流程,因此我们主要关注在构建时预设MAC地址的方法。 另外,请注意,修改系统属性可能需要root权限,并且在生产设备中,MAC地址通常由制造商写入,且不可更改。 参考引用: [^1]:Android官方文档中,蓝牙相关的配置通常通过系统属性进行,但具体设置MAC地址的方法并没有公开文档,因此我们参考了常见的做法。 [^2]: 在蓝牙服务中,MAC地址的读取和设置通常在初始化阶段完成,例如在A2DP控制通道初始化之前。 下面是一个更具体的步骤(以高通平台为例): 1. 在设备树文件(如`device/<manufacturer>/<device>/device.mk`)中,添加一个复制预设MAC地址的步骤: ```makefile PRODUCT_COPY_FILES += \ device/<manufacturer>/<device>/bdaddr:$(TARGET_COPY_OUT_PERSIST)/bluetooth/bdaddr ``` 2. 在`device/<manufacturer>/<device>/`目录下创建一个名为`bdaddr`的文件,内容为预设的MAC地址(不带冒号,例如:112233445566)。 3. 确保蓝牙服务配置为从该文件读取。在Android系统中,蓝牙服务通常由`bluetooth.default.so`实现,它默认会从`/persist/bluetooth/bdaddr`读取MAC地址。 4. 如果设备使用不同的路径,可以在`init.<device>.rc`中通过设置`ro.bt.bdaddr_path`属性来指定路径: ``` setprop ro.bt.bdaddr_path /persist/bluetooth/bdaddr ``` 5. 在蓝牙服务启动之前,确保该文件已经存在。因此,上述复制步骤在第一次启动时就会将文件复制到指定位置。 注意:`/persist`分区是持久化分区,不会被系统升级清除,因此MAC地址会一直保留。 如果用户需要动态生成MAC地址,则需要在初始化脚本中动态生成并写入文件,但这样需要确保每次生成的MAC地址符合规范(比如是本地管理的MAC地址,且不与其他设备冲突)。 由于用户问题涉及源码修改,我们假设用户有设备树的访问权限。 相关问题: 1. 如何验证蓝牙MAC地址是否设置成功? 2. 在Android设备上,如何通过adb命令获取蓝牙MAC地址? 3. 如果蓝牙MAC地址设置失败,可能的原因有哪些?</think>### Android源码中设置蓝牙MAC地址的流程Android源码中设置蓝牙MAC地址的流程主要涉及底层蓝牙栈的初始化和配置。以下是关键步骤: #### 1. **MAC地址存储位置** 蓝牙MAC地址通常存储在设备的**非易失性存储区**(如`/persist`分区或`/data/misc/bluetooth`目录)。首次启动时,系统会生成或读取该地址: ```bash /persist/bluetooth/bt_nv.bin # 常见存储路径 ``` #### 2. **蓝牙服务初始化流程** 当蓝牙服务(`bluetoothd`)启动时: 1. 通过`hal_ipc`通信接口向蓝牙芯片发送初始化命令 2. 芯片固件从NV存储中读取MAC地址 3. 若未找到有效地址,则使用芯片默认地址或生成随机地址 #### 3. **源码修改关键点** 在AOSP中修改MAC地址需要关注以下模块: - **HCI初始化层** `system/bt/stack/btu/btu_hcif.cc`中的`btu_hcif_process_event()`函数处理HCI命令: ```cpp case HCI_READ_BD_ADDR: bd_addr = read_from_persistent_storage(); // 从存储读取MAC send_response_to_controller(bd_addr); // 发送给蓝牙控制器 ``` - **NV存储管理** `system/bt/btif/src/btif_nv.c`中的`btif_nv_get_bd_addr()`函数: ```cpp bool btif_nv_get_bd_addr(uint8_t *bd_addr) { FILE* fp = fopen("/persist/bluetooth/bt_nv.bin", "rb"); fread(bd_addr, 1, 6, fp); // 读取6字节MAC地址 fclose(fp); } ``` #### 4. **自定义MAC地址方法** 若要硬编码特定MAC地址: 1. 修改NV读取函数(需重新编译固件): ```cpp // 在btif_nv.c中覆盖默认行为 bool btif_nv_get_bd_addr(uint8_t *bd_addr) { uint8_t custom_addr[6] = {0x11,0x22,0x33,0x44,0x55,0x66}; memcpy(bd_addr, custom_addr, 6); return true; } ``` 2. 或通过**工厂模式工具**写入(推荐): ```bash adb shell setprop persist.vendor.bt.addr 11:22:33:44:55:66 adb reboot ``` #### 5. **硬件依赖注意事项** - 高通平台:需修改`vendor/qcom/proprietary/bt/hci_qcomm_init`中的初始化脚本 - 博通平台:需检查`vendor/broadcom/bluetooth/firmware/`的固件配置 - **合法性验证**:MAC地址需满足: $$ \text{第二字节的LSB} = 1 \quad (\text{表示本地管理地址}) $$ 例如:`x2:x:x:x:x`(十六进制) #### 6. **验证方法** ```bash adb shell dumpsys bluetooth_manager | grep "Address" # 输出示例:Bluetooth Address: 11:22:33:44:55:66 ``` > **注意**:修改MAC地址可能违反区域无线电法规,仅限研发/测试使用。生产设备需遵循IEEE MAC地址分配规范[^1]。 --- ### 相关问题 1. Android蓝牙服务启动时如何加载HCI层配置? 2. 如何通过SELinux策略允许蓝牙服务访问`/persist`分区的NV存储文件? 3. 在Android 13+的Treble架构下,Vendor HAL层如何处理MAC地址请求? 4. 蓝牙芯片固件如何与Android蓝牙栈交互以获取MAC地址? 5. 如何在不重新编译系统的情况下,通过Fastboot工具写入蓝牙MAC地址? [^1]: IEEE标准要求MAC地址需全球唯一,自定义地址需确保符合本地管理地址规范(LAA)。 [^2]: Android蓝牙HCI层通过`UIPC_Read()`等函数与底层芯片通信实现配置加载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值