jeans chen
we've got them by the balls

Android 4.2 BT系统之蓝牙关闭过程全跟踪

分类: android 2252人阅读 评论(10) 收藏 举报
代码位置:
      frameworks/base/services/java/com/android/server/BluetoothManagerService.java
      这部分代码,生成libandroid_runtime.so
完成功能,中转BluetoothAdapter和Bluetooth.apk,所有来自其他应用的请求,都通过IBluetooth接口,转发到Bluetooth.apk
     启动方式:
     Intent i = new Intent(IBluetooth.class.getName());
                if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,
                                          UserHandle.USER_CURRENT)) {
     这里IBluetooth.class.getName实际返回android.bluetooth.IBluetooth
     这个action正好是packages/app/Bluetooth/AdapterService要处理的action。
     
     BluetoothManagerService保持一个BluetoothServiceConnection的回调,当AdapterService启动时,就可以拿到IBluetooth接口了。

代码位置:
     packages/apps/Bluetooth
     这部分代码,生成Bluetooth.apk
完成功能:
1、IBluetooh.aidl的服务端,由AdapterService的内部类AdapterServiceBinder实现
2、在BluetoothManagerService调用IBluetooth接口时,实际上是在AdapterServiceBinder端来处理。
3、IBluetooth.enable -> AdapterServiceBinder->enable -> BluetoothManagerService.enable
     BluetoothManagerService初始化了一个蓝牙状态机AdapterState实例,mAdapterStateMachine,调用enable是给状态机发一个消息AdapterState.USER_TURN_ON
4、再往下层的调用是通过,AdapterService的JNI接口enableNative

代码位置:
      packages/apps/Bluetooth/jni
      这部分代码,是AdapterService的JNI实现
 完成功能:
1、获取bluetooth.default接口,这个接口是android获取HAL的通用方式,  
    err = hw_get_module(id, (hw_module_t const**)&module);
2、因此调用JNI enableNative实际是调用bluetooth.default的实现enable

蓝牙关闭过程:
1、客户端调用AdapterService.java的disable接口
2、AdapterService给AdapterStateMachine发送一个USER_TURN_OFF的Message
3、AdapterStateMachine调用AdapterProperties的onBluetoothDisable接口
4、AdapterProperties把scan mode设置为AbstractionLayer.BT_SCAN_MODE_NONE
5、AdapterProperties调用AdapterService的setAdapterPropertyNative接口,往底层调用
6、在JNI层com_android_bluetooth_btservice_AdapterServices的 setAdapterPropertyNative,调用蓝牙HAL接口 sBluetoothInterface->set_adapter_property(&prop);
7、蓝牙HAL接口的实现,在external/bluetooth/bluedroid/btif/src/bluetooth.c中
8、bluetooth.c :: set_adapter_property -> btif_core.c :: btif_set_adapter_property
9、btif_set_adapter_property对属性 BT_PROPERTY_ADAPTER_SCAN_MODE设置的处理,先保存discovery mode为BTA_DM_NON_DISC,表示不可发现,保存connecable mode为BTA_DM_NON_CONN,表示不可连接。然后,调用external/bluetooth/bluedroid/bta/dm /bta_dm_api.c :: BTA_DmSetVisibility方法
10、BTA_DmSetVisibility构造一个tBTA_DM_API_SET_VISIBILITY    *p_msg,填入discovery mode, connetiable mode等参数,然后调用external/bluetooth/bluedroid/bta/sys/bta_sys_main.c :: bta_sys_sendmsg
11、bta_sys_sendmsg调用external/bluetooth/bluedroid/gki /common/gki_buffer.c :: GKI_send_msg发送一条GKI信息到BTA,GKI_send_msg有三个参数,第一个参数是线程id,也作为task id, 通过bta_sys_init获得,第二个参数是mailbox id,第三个是上一步封装好的p_msg
12、GKI_send_msg首先对p_msg进一步封装成event,通过链表存到mailbox id对应的任务队列中,调用external/bluetooth/bluedroid/gki/ulinux/gki_ulinux.c :: GKI_send_event进行发送
13、GKI_send_event设置事件掩码gki_cb.com.OSWaitEvt[task_id] |= event;, 通过pthread_cond_signal(&gki_cb.os.thread_evt_cond[task_id]);通知另外线程。
14、这样,在另外一个等待线程函数中gki_ulinux.c :: GKI_wait可以返回了,现在来看这个等待线程是怎么起来的

在调用HAL接口bluetoothInterface集合中的init的时候,
1、btif/src/bluetooth.c :: init 会调用 btif/src/btif_core.c :: btif_init_bluetooth 启动一个BTIF任务
2、btif_init_bluetooth 调用gki/ulinux/gki_ulinux.c :: GKI_create_task(btif_task, BTIF_TASK, BTIF_TASK_STR,
                (UINT16 *) ((UINT8 *)btif_task_stack + BTIF_TASK_STACK_SIZE),
                sizeof(btif_task_stack)); 启动这个任务,第一个参数btif_task是任务处理函数,第二个参数是task id,第三个是对应string表示形式,第四个是任务列表的起始指针,第四个是任务栈最大深度。
3、GKI_create_task 启动一个线程,等待任务事件     ret = pthread_create( &gki_cb.os.thread_id[task_id], //保存了线程id
              &attr1,
              (void *)gki_task_entry,
              &gki_pthread_info[task_id]); //gki_pthread_info保存了任务信息:task_id,task_entry。

可向而知,刚刚创建的任务线程,就是那个等待线程,来看gki_task_entry,即是btif_task的实现:
btif/src/btif_core.c
1、因为我们已经要开始等待事件了,因此要通知JAVA/JNI层,记得刚刚我们有注册了回调,那么就通过宏HAL_CBACK(bt_hal_cbacks, thread_evt_cb, ASSOCIATE_JVM);来通知JNI
2、进入for(;;)
3、调用GKI_wait,等待一个事件的返回
4、判断事件 event == BT_EVT_TRIGGER_STACK_INIT,如果是,就调用BTA_EnableBluetooth(bte_dm_evt)初始化蓝牙芯片组
5、判断事件event & EVENT_MASK(GKI_SHUTDOWN_EVT,如果是,就对出任务循环
6、判断事件event & TASK_MBOX_1_EVT_MASK 判断是否是1好mbox里面的事件。
7、如果第6步满足判断事件,那么判断事件 event  & BT_EVT_CONTEXT_SWITCH_EVT,如果是,调用btif_context_switched(p_msg)切换上下文
8、回第三步

到这里,很奇怪,为什么没有我们要处理的事件,难道在另外的任务线程里面处理?
在回过头来,看GKI对TASK_MBOX, TASK_MBOX_EVT_MASK的规划
TIMER事件,TASK事件,APPL事件(应用程序请求事件?)

gki/common/gki.h
#define TASK_MBOX_0    0
#define TASK_MBOX_1    1
#define TASK_MBOX_2    2
#define TASK_MBOX_3    3
                   
#define NUM_TASK_MBOX  4

#define MAX_EVENTS              16
                   
#define TASK_MBOX_0_EVT_MASK   0x0001
#define TASK_MBOX_1_EVT_MASK   0x0002
#define TASK_MBOX_2_EVT_MASK   0x0004
#define TASK_MBOX_3_EVT_MASK   0x0008

/* Definitions of task IDs for inter-task messaging */
#ifndef BTU_TASK
#define BTU_TASK                0
#endif

#ifndef BTIF_TASK
#define BTIF_TASK               1
#endif

#ifndef A2DP_MEDIA_TASK
#define A2DP_MEDIA_TASK         2
#endif

/* The number of GKI tasks in the software system. */
#ifndef GKI_MAX_TASKS
#define GKI_MAX_TASKS               3
#endif

在第11步bta_sys_sendmsg调用GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
他的TASK_ID就是bta_sys_cb.task_id,现在看下这个task_id的初始化过程,也就是BTA系统的初始化过程
BTA的初始化,要从在BTU的任务处理函数(btu_task)中开始的,那么btu_task又是怎么起来的,
这就要从bt开启的时候说起了。
1、在开启蓝牙之时,JNI调用HAL接口bluetoothInterface的enable函数,即btif/src/btif_core.c :: btif_enable_bluetooth
2、btif_enable_bluetooth调用main/bte_main.c的BTE API函数bte_main_enable(btif_local_bd_addr.address); 其从bte task,这个address怎么来的?
3、bte_main_enable,首先,初始化BTE控制块(HCI相关回调)
4、调用hci接口,(替代4.1的hciattach进程?),给bt设备上电。
5、GKI_create_task((TASKPTR)btu_task, BTU_TASK, BTE_BTU_TASK_STR,
                    (UINT16 *) ((UINT8 *)bte_btu_stack + BTE_BTU_STACK_SIZE),
                    sizeof(bte_btu_stack)); //启动BTU任务
6、pthread_create( &timer_thread_id,
              &timer_attr,
              timer_thread,
              NULL); //根据NO_GKI_RUN_RETURN是否执行timer_thread线程,NO_GKI_RUN_RETURN是什么意思?LINUX是否需要定义此宏?

再来看btu_task的实现:
1、btu_init_core(); 初始化核心control block,比如BTU, BTM, L2CAP, and SDP
2、BTE_InitStack();初始化BTE控制块,比如RFCOMM, DUN, SPP, HSP2, HFP, OBX, BIP
3、#if (defined(BTU_BTA_INCLUDED) && BTU_BTA_INCLUDED == TRUE)  //初始化BTA
     bta_sys_init();
     #endif 
4、#if ( BT_USE_TRACES==TRUE )  //此宏用于调试,是否设置
     BTE_InitTraceLevels();  
     #endif
5、进入for(;;)
6、处理事件的列表://为什么不是全部?
     TASK_MBOX_0_EVT_MASK
     TIMER_0_EVT_MASK
     TIMER_1_EVT_MASK
     TIMER_2_EVT_MASK
     RPCGEN_MSG_EVT
     TASK_MBOX_2_EVT_MASK
     EVENT_MASK(APPL_EVT_7) //APPL_EVT_7事件
    
再来看bta_sys_init的实现
bta/sys/bta_sys_main.c
bta_sys_init //注意到这里并没有建一个bta_task
1、bta_sys_cb.task_id = GKI_get_taskid(); //获取task id,是什么?
这里的GKI_get_taskid()仅是调用pthread_self()获取pthread_t,那么这段代码很明显是跟btu_task是同一个pthread,因此发给bta_sys_cb.task_id自然而然的由btu_task来处理了。

再回过头来看bta_sys_sendmsg的实现
void bta_sys_sendmsg(void *p_msg)
{
    GKI_send_msg(bta_sys_cb.task_id, p_bta_sys_cfg->mbox, p_msg);
}
这里GKI_send_msg的第一个参数已经确定,第二个参数见BTA相关参数的映射:
     
BTA相关映射关系如下:
/* GKI task mailbox event for BTA. */
#ifndef BTA_MBOX_EVT
#define BTA_MBOX_EVT                TASK_MBOX_2_EVT_MASK
#endif

/* GKI task mailbox for BTA. */
#ifndef BTA_MBOX
#define BTA_MBOX                    TASK_MBOX_2
#endif

/* GKI timer id used for protocol timer for BTA. */
#ifndef BTA_TIMER
#define BTA_TIMER                   TIMER_1
#endif

const tBTA_SYS_CFG bta_sys_cfg =
{
    BTA_MBOX_EVT,               /* GKI mailbox event */
    BTA_MBOX,                   /* GKI mailbox id */
    BTA_TIMER,                  /* GKI timer id */
    APPL_INITIAL_TRACE_LEVEL    /* initial trace level */
}; 

tBTA_SYS_CFG *p_bta_sys_cfg = (tBTA_SYS_CFG *)&bta_sys_cfg;
          
那么第二个参数也确定下来了,就是TASK_MBOX_2


再回过头来看btu_task处理的时间列表,里面正包含了TASK_MBOX_2_EVT_MASK

这样,我们终于找到处理设置BT_PROPERTY_ADAPTER_SCAN_MODE的债主了,就是btu_task
再来看btu_task对TASK_MBOX_2_EVT_MASK的实现
        if (event & TASK_MBOX_2_EVT_MASK)
        {
            while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)  //取出p_msg
            {
                bta_sys_event(p_msg); //处理p_msg
            }
        }

也就是说bta_sys_event会调用子系统回调函数去处理p_msg,看怎么实现的。bta/sys/bta_sys_main.c ::  bta_sys_event
BTA_API void bta_sys_event(BT_HDR *p_msg)  //这里名字也正好与BTA对应上
1、UINT8 id = (UINT8) (p_msg->event >> 8); 获取id 右移8位
2、    if ((id < BTA_ID_MAX) && (bta_sys_cb.reg[id] != NULL))
         {
             freebuf = (*bta_sys_cb.reg[id]->evt_hdlr)(p_msg);
         } 
3、再看当初event的形成
     void BTA_DmSetVisibility(tBTA_DM_DISC disc_mode, tBTA_DM_CONN conn_mode, UINT8 pairable_mode, UINT8 conn_filter )
          p_msg->hdr.event = BTA_DM_API_SET_VISIBILITY_EVT;
4、BTA_DM_API_SET_VISIBILITY_EVT的取值定义在bta/dm/bta_dm_int.h
enum
{  
    /* device manager local device API events */
    BTA_DM_API_ENABLE_EVT = BTA_SYS_EVT_START(BTA_ID_DM),  //注意这里BTA_SYS_EVT_START(BTA_ID_DM)实现#define BTA_SERVICE_ID_TO_SERVICE_MASK(id)       (1 << (id));因为BTA_ID_DM是1,
    BTA_DM_API_DISABLE_EVT,
    BTA_DM_API_SET_NAME_EVT,
    BTA_DM_API_SET_VISIBILITY_EVT,
    BTA_DM_API_SET_AFH_CHANNELS_EVT,
    BTA_API_DM_SIG_STRENGTH_EVT,
    BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT, 
    BTA_DM_API_TX_INQPWR_EVT,
    BTA_DM_ACL_CHANGE_EVT,
    BTA_DM_API_ADD_DEVICE_EVT,
     ...
};
5、因此计算刚才的id,也是1

BTA_ID_DM的回调函数的注册的过程
1、还记得btif_task刚起来的时候,会等待一个BT_EVT_TRIGGER_STACK_INIT的事件,对那个事件的处理,就是调用BTA_EnableBluetooth进行初始化硬件。
        if (event == BT_EVT_TRIGGER_STACK_INIT)
        {
            BTIF_TRACE_DEBUG0("btif_task: received trigger stack init event");
            BTA_EnableBluetooth(bte_dm_evt);
        }
2、bta/dm/bta_dm_api.c :: tBTA_STATUS BTA_EnableBluetooth(tBTA_DM_SEC_CBACK *p_cback)
     在这里面,注册两个子系统处理回调
     bta_sys_register (BTA_ID_DM, &bta_dm_reg );
     bta_sys_register (BTA_ID_DM_SEARCH, &bta_dm_search_reg );
     那么,我们来看他的定义
     static const tBTA_SYS_REG bta_dm_reg =
     {
         bta_dm_sm_execute,
         bta_dm_sm_disable
     };
     那么,bta_dm_sm_execute正是bta_sys_event要调用的实现

bta_dm_sm_execute的实现:
1、UINT16  event = p_msg->event & 0x00ff; //获得event事件,BTA_DM_API_SET_VISIBILITY_EVT
2、 (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg); 调用这个函数来处理
3、bta_dm_action列表:
     const tBTA_DM_ACTION bta_dm_action[] =                                       
{                                                                            
   
    /* device manager local device API events */
    bta_dm_enable,            /* 0  BTA_DM_API_ENABLE_EVT */
    bta_dm_disable,           /* 1  BTA_DM_API_DISABLE_EVT */
    bta_dm_set_dev_name,      /* 2  BTA_DM_API_SET_NAME_EVT */
    bta_dm_set_visibility,    /* 3  BTA_DM_API_SET_VISIBILITY_EVT */
    bta_dm_set_afhchannels,   /* 4  BTA_DM_API_SET_AFH_CHANNELS_EVT */       
    bta_dm_signal_strength,   /* 5  BTA_API_DM_SIG_STRENGTH_EVT */
    bta_dm_vendor_spec_command,/* 6  BTA_DM_API_VENDOR_SPECIFIC_COMMAND_EVT */
    bta_dm_tx_inqpower,       /* 7  BTA_DM_API_SIG_STRENGTH_EVT */           
    bta_dm_acl_change,        /* 8  BTA_DM_ACL_CHANGE_EVT */
    bta_dm_add_device,        /* 9  BTA_DM_API_ADD_DEVICE_EVT */             
    ...
}
4、也就是说调用bta_dm_set_visibility来实现。

bta_dm_set_visibility的实现bta/dm/bta_dm_act.c
1、BTM_SetDiscoverability((UINT8)p_data->set_visibility.disc_mode,
                                bta_dm_cb.inquiry_scan_window,
                                bta_dm_cb.inquiry_scan_interval); //调用这个实现设置discovery mode
          BTM_SetDeviceClass (cod);//DEV_CLASS cod封装好discory mode
               btsnd_hcic_write_dev_class (dev_class); //stack/hcic/hcicmds.c
2、BTM_SetConnectability((UINT8)p_data->set_visibility.conn_mode,
                                bta_dm_cb.page_scan_window,
                                bta_dm_cb.page_scan_interval); //调用这个实现设置can mode
          btsnd_hcic_write_scan_enable (scan_mode);  //stack/hcic/hcicmds.c
3、btsnd_hcic_write_dev_class 和 btsnd_hcic_write_scan_enable 都会将参数封包,通过cmd方式,调用btu_hcif_send_cmd发送出去。

btu_hcif_send_cmd的实现:
1、首先取出命令控制块
     tHCI_CMD_CB * p_hci_cmd_cb = &(btu_cb.hci_cmd_cb[controller_id]);
2、p_hci_cmd_cb->cmd_window = p_hci_cmd_cb->cmd_xmit_q.count + 1; //打开发送窗口
3、while (p_hci_cmd_cb->cmd_window != 0) {
          ...
          p_buf = (BT_HDR *)GKI_dequeue (&(p_hci_cmd_cb->cmd_xmit_q)); //从链表中取出一个消息
          btu_hcif_store_cmd(controller_id, p_buf); //保存发出去的消息,用于超时机制
               GKI_enqueue(&(p_hci_cmd_cb->cmd_cmpl_q), p_cmd); // 拷贝到链表中
               btu_start_timer (&(p_hci_cmd_cb->cmd_cmpl_timer),
                         (UINT16)(BTU_TTYPE_BTU_CMD_CMPL + controller_id),
                         BTU_CMD_CMPL_TIMEOUT); //启动计时器,  cmd_cmpltimer与cmd_cmpl_q的关系?
            p_hci_cmd_cb->cmd_window--; //计数器减一
            if (controller_id == LOCAL_BR_EDR_CONTROLLER_ID)
            {
                HCI_CMD_TO_LOWER(p_buf); //发送到底层,是一个宏
            }
          ...
     }
4、HCI_CMD_TO_LOWER的宏定义
      bluedroid/include/bt_target.h:#define HCI_CMD_TO_LOWER(p)         bte_main_hci_send((BT_HDR *)(p), BT_EVT_TO_LM_HCI_CMD);
     
来看bte_main_hci_send的实现:
1、UINT16 sub_event = event & BT_SUB_EVT_MASK;//利用子事件掩码,BT_EVT_TO_LM_HCI_CMD & BT_SUB_EVT_MASK = 0
2、    if((sub_event == LOCAL_BR_EDR_CONTROLLER_ID) || \
       (sub_event == LOCAL_BLE_CONTROLLER_ID))
            bt_hc_if->transmit_buf((TRANSAC)p_msg, \
                                       (char *) (p_msg + 1), \
                                        p_msg->len);  //调用transmit_buf接口发送出去。
     
bt_hc_if是在HCI初始化的过程中得到的。

HCI初始化过程
在调用HAL接口bluetoothInterface集合中的init的时候,
1、btif/src/bluetooth.c :: init 会调用 btif/src/btif_core.c :: btif_init_bluetooth
2、btif_init_bluetooth 会调用main/bte_main.c ::  bte_main_boot_entry //初始化BT芯片的入口
3、bte_main_boot_entry 调用 bte_main_in_hw_init 或许HCI接口
          static bt_hc_interface_t * bt_hc_if = (bt_hc_interface_t *) bt_hc_get_interface();
          static const bt_hc_callbacks_t bt_hc_callbacks; //回调,跟bt_hc_if调用方向刚好相反
4、hci/src/bt_hci_bdroid.c中
     const bt_hc_interface_t *bt_hc_get_interface(void)
     {
         return &bluetoothHCLibInterface; //返回接口列表
     }
4、在使能蓝牙调用bte_main_enable的时候,开始btu_stack之前,会按顺序初始化蓝牙设备。
     bt_hc_if->init(&hc_callbacks, local_addr);  //hc_callbacks是hci回调
     bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);
     bt_hc_if->preload(NULL);
5、bt_hc_if->init也就是调用bluetoothHCLibInterface的init方法
     
来看bluetoothHCLibInterface的init方法 hci/src/bt_hci_bdroid.c
1、bt_hc_callbacks_t *bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb; //保存回调
2、init_vnd_if(local_bdaddr);//调用厂商库里面的bt_vendor_interface_t *接口,初始化蓝牙设备
3、p_hci_if = &hci_h4_func_table; //使用HCI H4接口回调
4、p_hci_if->init(); //调用hci_h4_func_table的init方法,初始化H4模块
5、userial_init();//初始化uart数据结构
6、lpm_init();//初始化低功耗模块,调用bt_vendor_interface_t的op接口
7、utils_queue_init(&tx_q); //初始化发送队列
8、pthread_create(&hc_cb.worker_thread, &thread_attr, \
                       bt_hc_worker_thread, NULL) != 0) //起工作线程

在回过头来看transmit_buf,其实就是调用bluetoothHCLibInterface的transmit_buf方法
看transmit_buf的实现:hci/src/bt_hci_bdroid.c
static int transmit_buf(TRANSAC transac, char *p_buf, int len)
{
    utils_enqueue(&tx_q, (void *) transac);  //链接到发送队列

    bthc_signal_event(HC_EVENT_TX); //广播事件

    return BT_HC_STATUS_SUCCESS;
}

另外一边的工作线程bt_hc_worker_thread,接收到上面的广播事件之后会判断事件类型,如果是HC_EVENT_TX,首先将目前所有的时间加入到数组sending_msg_que里面
      for(i = 0; i < sending_msg_count; i++)
                p_hci_if->send(sending_msg_que[i]); //调用p_hci_if的send接口发送出去。

上面已经提到p_hci_if的send接口在hci_h4_func_table中实现,hci/src/hci_h4.c
来看其send回调的实现
void hci_h4_send_msg(HC_BT_HDR *p_msg) {
     ...
     if (event == MSG_STACK_TO_HC_HCI_CMD)
        type = H4_TYPE_COMMAND; //设定cmd类型
     if (sub_event == LOCAL_BR_EDR_CONTROLLER_ID)
     {
        acl_data_size = h4_cb.hc_acl_data_size;
        acl_pkt_size = h4_cb.hc_acl_data_size + HCI_ACL_PREAMBLE_SIZE;  //设置数据大小
     }
     ...
     bytes_sent = userial_write(event,(uint8_t *) p, bytes_to_send);//写串口,是否会阻塞
     ...
     bt_hc_cbacks->tx_result((TRANSAC) p_msg, (char *) (p_msg + 1), \
                                        BT_HC_TX_SUCCESS); //将发送结果通过回调发回去,注意这里只是成功发送到串口,有没有成功,应该是从内核往上发,由userial_read_thread来完成。

来看读线程userial_read_thread的实现
static void *userial_read_thread(void *arg) {
    while (userial_running) {
         //调用回调申请一段消息BUFFER
              p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc( \
                                                BTHC_USERIAL_READ_MEM_SIZE);
        //select读取串口消息
        rx_length = select_read(userial_cb.fd, p, READ_LIMIT);
        //将消息发到rx队列,并广播出去
        utils_enqueue(&(userial_cb.rx_q), p_buf);
        bthc_signal_event(HC_EVENT_RX);
        //调用回调释放内存
        bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
   }
}

工作线程bt_hc_worker_thread得到广播之后
        if (events & HC_EVENT_RX)
        {
            p_hci_if->rcv(); //调用rcv,也就是hci_h4_func_table的hci_h4_receive_msg回调
        }
hci_h4_receive_msg有一个rcv_state变量,表征当前数据帧的收取状态
typedef enum {
    H4_RX_MSGTYPE_ST,
    H4_RX_LEN_ST,
    H4_RX_DATA_ST,
    H4_RX_IGNORE_ST
} tHCI_H4_RCV_STATE;
通过条件p_cb->rcv_msg_type和acl_rx_frame_end_chk()两个条件,判断当前是否收完一帧数据,如果是,则调用bt_hc_cbacks的data_ind回调把数据上发:
                bt_hc_cbacks->data_ind((TRANSAC) p_cb->p_rcv_msg, \
                                       (char *) (p_cb->p_rcv_msg + 1), \
                                       p_cb->p_rcv_msg->len + BT_HC_HDR_SIZE);

bt_hc_cbacks的data_ind回调,就是main/bte_main.c hc_callbacks的data_ind函数,来看它的实现
static int data_ind(TRANSAC transac, char *p_buf, int len)                 
{                                                                          
    BT_HDR *p_msg = (BT_HDR *) transac;                                   
    GKI_send_msg (BTU_TASK, BTU_HCI_RCV_MBOX, transac);  //发到btu task中去了,而且mbox为TASK_MBOX_0
    //因为如下宏
    //#define BTU_HCI_RCV_MBOX        TASK_MBOX_0     /* Messages from HCI  */
    return BT_HC_STATUS_SUCCESS;                                           
}                                                                          

那么在btu task中:
比较事件验码为BT_EVT_TO_BTU_HCI_EVT后,
进而调用btu_hcif.c的btu_hcif_process_event处理来自底层的事件上报,在
会取出event code,不同的code,调用不同的函数来处理,以HCI_PAGE_SCAN_REP_MODE_CHNG_EVT为例子,它的处理函数为btu_hcif_page_scan_rep_mode_chng_evt,这样,再一层层,
这里应该报上两个事件btif_adapter_properties_evt,一个是discovery mode一个是connectiable mode,是否保证到JAVA的通路是畅通的?


在写属性的过程中,往串口写是一方面,在写完串口之后,还需要更新本地数据库。(要是BT模块写拒绝怎么办?)
在btif/src/btif_core.c :: btif_set_adapter_property 中,最后一步
    if (storage_req_id != BTIF_CORE_STORAGE_NO_ACTION)  //判断是否需要更新数据库
    {
        int btif_status;
        /* pass on to storage for updating local database */

        memset(&(req.write_req.bd_addr), 0, sizeof(bt_bdaddr_t));
        memcpy(&(req.write_req.prop), property, sizeof(bt_property_t));
        // btif_transfer_context会将一个消息到BTU_BTIF_MBO,也就是TASK_MBOX_1信箱,并且这个消息
        // 由btif_task来处理
        return btif_transfer_context(execute_storage_request, 
                                     storage_req_id,
                                     (char*)&req,
                                     sizeof(btif_storage_req_t)+property->len,
                                     btif_in_storage_request_copy_cb);  
               btif_sendmsg(p_msg)
                    GKI_send_msg(BTIF_TASK, BTU_BTIF_MBOX, p_msg);
    }

来看btif的处理:
if(event & TASK_MBOX_1_EVT_MASK)  { //计算掩码,符合
     while((p_msg = GKI_read_mbox(BTU_BTIF_MBOX)) != NULL) { //取出消息
          switch (p_msg->event)
                {
                    case BT_EVT_CONTEXT_SWITCH_EVT:  //判断消息类型,符合
                        btif_context_switched(p_msg); //处理消息
                        break;
                    ...
               }
     }
}

来看btif_context_switched的实现:
static void btif_context_switched(void *p_msg)
{
    tBTIF_CONTEXT_SWITCH_CBACK *p = (tBTIF_CONTEXT_SWITCH_CBACK *) p_msg;
    /* each callback knows how to parse the data */
    if (p->p_cb)
        p->p_cb(p->event, p->p_param);  //取出事件处理回调函数,也就是execute_storage_request
}

来看execute_storage_request的实现
static void execute_storage_request(UINT16 event, char *p_param) {
    switch(event){
        case BTIF_CORE_STORAGE_ADAPTER_WRITE: //判断事件类型,符合
        {
            btif_storage_req_t *p_req = (btif_storage_req_t*)p_param;
            bt_property_t *p_prop = &(p_req->write_req.prop);
            status = btif_storage_set_adapter_property(p_prop);   //是否会阻塞?
            HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status, 1, p_prop);  //调用JNI测的回调
          }
          ...
      }
}

而在JAVA一侧,通过AdapterProperties.java的回调adapterPropertyChangedCallback,可以得知刚才property设置的结果(是否从串口发上来的?):
case: AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE:
      mService.startBluetoothDisable
1、调用AdapterService的startBluetoothDisable方法
2、AdapterService给AdapterStateMachine发送AdaterState.BEGIN_DISABLE的Message
3、AdapterStateMachine调用AdapterService的disableNative接口

adapterPropertyChangedCallback回调,通过com_android_bluetooth_btservice_AdapterService.cpp调用JAVA的方式,调用
在JNI一层,有一组回调接口,是通过Android HAL层组织的
bt_callbacks_t sBluetoothCallbacks = {                                       
    sizeof(sBluetoothCallbacks),                                             
    adapter_state_change_callback,                                           
    adapter_properties_callback,                                             
    remote_device_properties_callback,                                       
    device_found_callback,                                                   
    discovery_state_changed_callback,                                        
    pin_request_callback,                                                    
    ssp_request_callback,                                                    
    bond_state_changed_callback,                                             
    acl_state_changed_callback,                                              
    callback_thread_event,                                                   
}; 
这组回调,通过sBluetoothInterface->init(&sBluetoothCallbacks);注册。
而sBluetoothInterface的实现,在external/bluetooth/bluedroid/btif/src
const bt_interface_t* bluetooth__get_bluetooth_interface ()
{
    return &bluetoothInterface;
}
static const bt_interface_t bluetoothInterface = {
    sizeof(bt_interface_t),
    init,
    enable,
    disable,
    cleanup,
    get_adapter_properties,
    get_adapter_property,
    set_adapter_property,
    get_remote_device_properties,
    get_remote_device_property,
    set_remote_device_property,
    get_remote_service_record,
    get_remote_services,
    start_discovery,
    cancel_discovery,
    create_bond,
    remove_bond,
    cancel_bond,
    pin_reply,
    ssp_reply,
    get_profile_interface,
    dut_mode_configure,
    dut_mode_send
};
在init里面,会将sBluetoothInterface保存在bluetoothInterface中,

因此,反响调用的顺序是这样的
1、bluetoothInterface->adapter_properties_cb也就是com_android_bluetooth_btservice_AdapterService的adapter_properties_cb
2、adapter_properties_callback调用AdapterProperties的adapterPropertyChangedCallback方法

现在看btif_storage_set_adapter_property的实现,研究一下事件是怎么写入NVRAM中去。
btif/src/btif_storage.c
bt_status_t btif_storage_set_adapter_property(bt_property_t *property)
{                             
    return prop2cfg(NULL, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL;
}           
btif/src/btif_storage.c
static int prop2cfg(bt_bdaddr_t *remote_bd_addr, bt_property_t *prop)
{
     switch(prop->type)
    {
        case BT_PROPERTY_ADAPTER_SCAN_MODE:
            btif_config_set_int("Local", "Adapter",
                                BTIF_STORAGE_KEY_ADAPTER_SCANMODE, *(int*)prop->val);  
            break;
          ...
     }
     ...
}
btif/src/btif_config.c
int btif_config_set_int(const char* section, const char* key, const char* name, int value)
{  
    return btif_config_set(section, key, name, (char*)&value, sizeof(value), BTIF_CFG_TYPE_INT); //加上config类型
}  
btif/src/btif_config.c
int btif_config_set(const char* section, const char* key, const char* name, const char*  value, int bytes, int type)
{
    ...
    set_node(section, key, name, value, (short)bytes, (short)type); //找到一个cfg_node*(配置节点)
    btsock_thread_post_cmd(pth, CFG_CMD_SAVE, NULL, 0, 0); // pth是线程槽(thread slots)的序号。
    ...
}
config node数据结构,root节点是所有配置的起始节点。
typedef struct cfg_node_s
{
    const char* name;
    union
    {
        struct cfg_node_s* child;
        char* value;
    };
    short bytes;
    short type;
    short used;
    short flag;
} cfg_node;

我理解的线程槽,BT中有很多业务,每一类的业余需要一个(或多个)额外的线程来处理一些事情,可以通过写线程槽的socket一端,那么读端在获取消息后,可以处理这些事情。
btif_init_bluetooth在创建btif_task之前,先会调用btif_config_init,初始config相关数据结构

btif/src/btif_config.c
1、stat(CFG_PATH, &st)  //确认配置文件,路径:/data/misc/bluedroid/
2、btsock_thread_init();  //初始化thread_slogt ts数组
3、init_slot_lock(&slot_lock);//初始化线程锁
4、   root.name = "Bluedroid";
        alloc_node(&root, CFG_GROW_SIZE);
        dump_node("root", &root);
        pth = btsock_thread_create(NULL, cfg_cmd_callback);
     创建一个跟配置节点,并创捷一个取用一个线程槽,pth为ts数组里面对应的序号。
5、load_cfg(); //导入配置文件,读取xml文件到内存,以config_node形式组织起来。

先看btsock_thread_create的线程创建过程:
int btsock_thread_create(btsock_signaled_cb callback, btsock_cmd_cb cmd_callback)
1、int h = alloc_thread_slot(); //获取一个空闲槽,卧槽,这是什么节奏
2、init_poll(h);  //初始化这个槽点,创建一个socketpair,读写端分别是ts[h].cmd_fdr和ts[h].cmd_fdw,并且将cmd_fdr放入监听槽...
3、ts[h].thread_id = create_thread(sock_poll_thread, (void*)h); //给这个槽点创建线程,线程函数为sock_poll_thread
4、ts[h].callback = callback;
     ts[h].cmd_callback = cmd_callback; //sock_poll_thread将会调用它来处理写config

那么先来看写端的处理,也就是btsock_thread_post_cmd是怎么做的
btif/src/btif_sock_thread.c
int btsock_thread_post_cmd(int h, int type, const unsigned char* data, int size, uint32_t user_id)
     sock_cmd_t cmd = {CMD_USER_PRIVATE, 0, type, size, user_id};
     //将cmd包装到sock_cmd_t* cmd_send中
     send(ts[h].cmd_fdw, cmd_send, size_send, 0)  //直接往cmd_fdw写

再看来cmd_fdr,也就是sock_poll_thread的处理
btif/src/btif_sock_thread.c
{
    for(;;)
    {
        prepare_poll_fds(h, pfds);
        int ret = poll(pfds, ts[h].poll_count, -1); //开始监听
        if(ret != 0)
        {
            int need_process_data_fd = TRUE;
            if(pfds[0].revents) //cmd fd always is the first one
            {
                asrt(pfds[0].fd == ts[h].cmd_fdr);
                if(!process_cmd_sock(h))  //先尝试处理cmd命令,即上面提到的CMD_USER_PRIVATE
                {
                    APPL_TRACE_DEBUG1("h:%d, process_cmd_sock return false, exit...", h);
                    break;
                }
                if(ret == 1)
                    need_process_data_fd = FALSE;
                else ret--; //exclude the cmd fd
            }
            if(need_process_data_fd)
                process_data_sock(h, pfds, ret); //再处理数据。
        }
        else {APPL_TRACE_DEBUG1("no data, select ret: %d", ret)};
    }
    ts[h].thread_id = -1;
}

看process_cmd_sock的实现
btif/src/btif_sock_thread.c
static int process_cmd_sock(int h)
{
    sock_cmd_t cmd = {-1, 0, 0, 0, 0};
    int fd = ts[h].cmd_fdr;
    if(recv(fd, &cmd, sizeof(cmd), MSG_WAITALL) != sizeof(cmd))
    {
        APPL_TRACE_ERROR1("recv cmd errno:%d", errno);
        return FALSE;
    }
    switch(cmd.id)
    {
        case CMD_USER_PRIVATE:
            asrt(ts[h].cmd_callback);
            if(ts[h].cmd_callback)
                ts[h].cmd_callback(fd, cmd.type, cmd.flags, cmd.user_id);  //调用回调处理,即上文的cfg_cmd_callback
            break;
        ...
    }
    return TRUE;
}

再来看cfg_cmd_callback的实现:
static void cfg_cmd_callback(int cmd_fd, int type, int size, uint32_t user_id)
{
  //BTIF_TRACE_DEBUG2("cmd type:%d, size:%d", type, size);
    switch(type)
    {
        case CFG_CMD_SAVE:
            lock_slot(&slot_lock);
            save_cfg();    //保存所有的config到配置文件中,从根config node:root开始遍历
            unlock_slot(&slot_lock);
            break;
    }
}

到目前为止蓝牙的关闭过程,才进行一般不到。
来看AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE被JNI调用到AdapterProperties.java的adapterPropertyChangedCallback之后怎么处理的
AdapterProperties.java
adapterPropertyChangedCallback
                    case AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE:
                        int mode = Utils.byteArrayToInt(val, 0);
                        mScanMode = mService.convertScanModeFromHal(mode);
                        intent = new Intent(BluetoothAdapter.ACTION_SCAN_MODE_CHANGED);
                        intent.putExtra(BluetoothAdapter.EXTRA_SCAN_MODE, mScanMode);
                        intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
                        mService.sendBroadcast(intent, mService.BLUETOOTH_PERM); 
                        debugLog("Scan Mode:" + mScanMode);
                        if (mBluetoothDisabling) {
                            mBluetoothDisabling=false;
                            mService.startBluetoothDisable();  //调用服务的startBluetoothDisable停掉蓝牙设备
                        }
                        break;
AdapterService——com_android_bluetooth_btservice_AdapterService.cpp——bluetooth.c——btif_core.c
最终调用到btif_core.c的btif_disable_bluetooth,看btif_disable_bluetooth的实现
bt_status_t btif_disable_bluetooth(void)
{
     btif_dm_on_disable();//终止配对
     btif_core_state = BTIF_CORE_STATE_DISABLING; //将状态设置为BTIF_CORE_STATE_DISABLING
     btif_sock_cleanup();  //清理rfcomm & l2cap 
     btif_pan_cleanup(); 
     BTA_DisableBluetooth()//关闭蓝牙
     btif_config_flush();//保存配置
}
先看btif_dm_on_disable的实现
btif/src/btif_sock.c
void btif_dm_on_disable()
{
    if (pairing_cb.state == BT_BOND_STATE_BONDING)
    {
        bt_bdaddr_t bd_addr;
        bdcpy(bd_addr.address, pairing_cb.bd_addr);
        btif_dm_cancel_bond(&bd_addr);  如果正在配对,则取消配对
    }
}
btif_sock_cleanup和btif_pan_cleanup略过,
来看BTA_DisableBluetooth的实现:
tBTA_STATUS BTA_DisableBluetooth(void)
{
   
    BT_HDR    *p_msg;
   
    if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL)  //太暴力了,直接从BTA中拿出一条消息,
    {
        p_msg->event = BTA_DM_API_DISABLE_EVT; //然后改写事件。
        bta_sys_sendmsg(p_msg);
    }
    else
    {  
        return BTA_FAILURE;
    }  
   
    return BTA_SUCCESS;
}   

这个消息按照之前介绍过的,最终会被btu_task处理。来看处理过程
        if (event & TASK_MBOX_2_EVT_MASK)
        {
            while ((p_msg = (BT_HDR *) GKI_read_mbox(TASK_MBOX_2)) != NULL)
            {
                bta_sys_event(p_msg);
            }
        }
上面依然讲过,bta_sys_event的消息处理回调是bta_dm_reg 的bta_dm_sm_execute,
BOOLEAN bta_dm_sm_execute(BT_HDR *p_msg)
{
    UINT16  event = p_msg->event & 0x00ff;

    APPL_TRACE_EVENT1("bta_dm_sm_execute event:0x%x", event);

    /* execute action functions */
    if(event < BTA_DM_NUM_ACTIONS)
    {
        (*bta_dm_action[event])( (tBTA_DM_MSG*) p_msg); //BTA_DM_API_DISABLE_EVT对应的处理函数是bta_dm_disable
    }

    return TRUE;
}

来看bta_dm_disable的实现
void bta_dm_disable (tBTA_DM_MSG *p_data)
{  
    /* Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after last channel is closed) */
    L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0);    //设置L2CAP通道超时时间
   
    /* disable all active subsystems */
    bta_sys_disable(BTA_SYS_HW_BLUETOOTH);  //停掉BTA DM 子系统
   
    BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0); 
    BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0); //这两者上文解析过了

    bta_dm_disable_pm();  
   
    bta_dm_cb.disabling = TRUE;
   
    bta_dm_search_cancel(NULL);  //停止搜寻设备
   
    if(BTM_GetNumAclLinks()==0)
    {
#if (defined(BTA_DISABLE_DELAY) && BTA_DISABLE_DELAY > 0)
        /* If BTA_DISABLE_DELAY is defined and greater than zero, then delay the shutdown by
         * BTA_DISABLE_DELAY milliseconds
         */
        APPL_TRACE_WARNING2("%s BTA_DISABLE_DELAY set to %d ms",
                            __FUNCTION__, BTA_DISABLE_DELAY);
        bta_sys_stop_timer(&bta_dm_cb.disable_timer);
        bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_conn_down_timer_cback;
        bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, BTA_DISABLE_DELAY);
#else
        bta_dm_disable_conn_down_timer_cback(NULL);
#endif
    }
    else
    {
        bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback;
        bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000);   //终止所有定时器的操作。
    }
}

先看 bta_sys_disable(BTA_SYS_HW_BLUETOOTH)的实现,它调用子系统回调的 bta_sys_cb.reg[bta_id]->disable方法,也就是上文的bta_dm_reg的其中的 bta_dm_sm_disable方法
static const tBTA_SYS_REG bta_dm_reg =
{
    bta_dm_sm_execute,
    bta_dm_sm_disable
};
来看它的实现:
void bta_dm_sm_disable( )
{
    bta_sys_deregister( BTA_ID_DM );
}   
void bta_sys_deregister(UINT8 id)
{
    bta_sys_cb.is_reg[id] = FALSE;//只是简单的将is_reg赋值为FALSE
}   

再来看bta_dm_search_cancel的实现
void bta_dm_search_cancel (tBTA_DM_MSG *p_data)
{

    tBTA_DM_MSG * p_msg;

    if(BTM_IsInquiryActive())  
    {
        BTM_CancelInquiry();   //取消搜寻
        bta_dm_search_cancel_notify(NULL);

        if ((p_msg = (tBTA_DM_MSG *) GKI_getbuf(sizeof(tBTA_DM_MSG))) != NULL)
        {
            p_msg->hdr.event = BTA_DM_SEARCH_CMPL_EVT;
            p_msg->hdr.layer_specific = BTA_DM_API_DISCOVER_EVT;
            bta_sys_sendmsg(p_msg);  //给btu_task发消息

        }
    }
    /* If no Service Search going on then issue cancel remote name in case it is active */
    else if (!bta_dm_search_cb.name_discover_done)
    {
        BTM_CancelRemoteDeviceName();
    }
#if ((BLE_INCLUDED == TRUE) && (defined BTA_GATT_INCLUDED) && (BTA_GATT_INCLUDED == TRUE))
    if (bta_dm_search_cb.gatt_disc_active)
    {
        bta_dm_cancel_gatt_discovery(bta_dm_search_cb.peer_bdaddr);
    }
#endif
}

上面几步掠过,因为都是一些写过的消息线程间转发,到此为止停止蓝牙设备的工作已经接近尾声了
最后一步,是收尾工作,也就是btif_config_flush,来看它的实现:
void btif_config_flush()
{
    lock_slot(&slot_lock);
    if(cached_change > 0)
        save_cfg();  //保存配置到文件
    unlock_slot(&slot_lock);
}

static int save_cfg()
{
    const char* file_name = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT;
    const char* file_name_new = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_NEW;
    const char* file_name_old = CFG_PATH CFG_FILE_NAME CFG_FILE_EXT_OLD;
    int ret = FALSE;
    if(access(file_name_old,  F_OK) == 0)
        unlink(file_name_old);  //删除缓存文件
    if(access(file_name_new, F_OK) == 0)
        unlink(file_name_new);
   if(btif_config_save_file(file_name_new))  //保存最新配置到file_name_new,上文讲过了,就是根节点遍历config node数据结构,然后写入xml文件中。
    {
        cached_change = 0;
        chown(file_name_new, -1, AID_NET_BT_STACK);
        chmod(file_name_new, 0660);
        rename(file_name, file_name_old);
        rename(file_name_new, file_name);   //更新配置到file_name
        ret = TRUE;
    }
    else BTIF_TRACE_ERROR0("btif_config_save_file failed");
    return ret;
}







更多 1
 
查看评论
9楼 andger032 2013-11-12 09:52发表 [回复]
上面:“4、调用hci接口,(替代4.1的hciattach进程?),给bt设备上电。”
我觉得应该不是调用hci接口,bt_hc_if->set_power这类的应该是调用蓝牙芯片厂商自己定义的接口。
Re: woyaoxiazaibiefanwo 2013-12-28 17:03发表 [回复]
回复andger032:9楼理解的是对的bt_hc_if->set_power会进入芯片厂商给的一个.so的库文件,有的人能够拿到,能够跟到。
8楼 xyp5299 2013-10-12 16:28发表 [回复]
重新又看了一次,写的太好了。请问还会有蓝牙的继续更新吗?

谢谢。
7楼 xyp5299 2013-09-26 21:57发表 [回复]
还会继续 更新 吗?
6楼 gordon1986 2013-09-17 09:38发表 [回复]
希望继续更新,谢谢
5楼 Limit87 2013-09-13 16:18发表 [回复]
楼主分析的很透彻,但是你能继续分析btstack到驱动的过程吗,中间还有一段路
4楼 xyp5299 2013-09-08 23:16发表 [回复]
写的精辟,需要多读几次才能完整的看明白。

希望继续分享。
谢谢。
3楼 xyp5299 2013-09-01 15:01发表 [回复]
非常精彩,请问还有后续文章吗?
谢谢。
2楼 xyp5299 2013-08-17 12:57发表 [回复]
非常不错,请继续分享,谢谢。
1楼 dearpenguin 2013-08-06 16:55发表 [回复]
博主,请教下bluedroid的transport layer 只能用H4吗?如果要用BCSP的话应该从何下手呢?多谢分享
posted on 2014-02-15 18:23  jeans chen  阅读(2674)  评论(0编辑  收藏  举报