Android 4.2 BT系統之藍牙關閉過程全跟蹤

代碼位置:
      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;
}







發佈了102 篇原創文章 · 獲贊 35 · 訪問量 40萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章