蓝牙disable流程简述
蓝牙关闭的流程比打开流程要简单,主要就是一些profile的断连以及协议栈相关结构的释放。
这里简单说一下其流程,就直接从协议栈的disable的接口说起了。
static int disable(void) { if (!interface_ready())//检查hal层的callback return BT_STATUS_NOT_READY; stack_manager_get_interface()->shut_down_stack_async(); return BT_STATUS_SUCCESS; }
简单看下stack_manager_get_interface :
static const stack_manager_t interface = { init_stack, start_up_stack_async, shut_down_stack_async, clean_up_stack_async, get_stack_is_running }; const stack_manager_t *stack_manager_get_interface() { ensure_manager_initialized(); return &interface; }
看shut_down_stack_async的具体实现:
static void shut_down_stack_async(void) { thread_post(management_thread, event_shut_down_stack, NULL); }
这里就是把关闭的函数 post 到management_thread 里面来执行。继续执行的函数还是event_shut_down_stack
// Synchronous function to shut down the stack static void event_shut_down_stack(UNUSED_ATTR void *context) { ... hack_future = future_new();//为了同步用的 stack_is_running = false; btif_disable_bluetooth();//真正的disable的接口 module_shut_down(get_module(BTIF_CONFIG_MODULE));//释放btif模块 future_await(hack_future);//获得了信号量之后才能执行到这里 module_shut_down(get_module(CONTROLLER_MODULE)); // Doesn't do any work, just puts it in a restartable state LOG_DEBUG("%s finished.", __func__); btif_thread_post(event_signal_stack_down, NULL);//通知上层stack down }
这里简单说一下这个hack_future,其在这里的用途类似二值信号量,如果这个信号量不可用,就会一直等在future_await 这里,和其对应的一个函数叫future_ready,
void future_ready(future_t *future, void *value) { assert(future != NULL); assert(future->ready_can_be_called); future->ready_can_be_called = false; future->result = value; semaphore_post(future->semaphore); }
这个函数会让这个信号量变得可读,future_await 就可以顺利返回继续执行。其实就是为了disable 过程的同步性。看了一下,其会在btif_disable_bluetooth_evt 这个函数中释放信号量,看函数名字应该是disable 完成的一个事件,这也符合我们的预期。关于这个信号量,就分析到这里。
下面主要看btif_disable_bluetooth :
/******************************************************************************* ** ** Function btif_disable_bluetooth ** ** Description Inititates shutdown of Bluetooth system. ** Any active links will be dropped and device entering ** non connectable/discoverable mode ** ** Returns void ** *******************************************************************************/ bt_status_t btif_disable_bluetooth(void) { BTIF_TRACE_DEBUG("BTIF DISABLE BLUETOOTH"); btif_dm_on_disable(); /* cleanup rfcomm & l2cap api */ btif_sock_cleanup(); btif_pan_cleanup(); BTA_DisableBluetooth(); return BT_STATUS_SUCCESS; }
这里的注释非常重要,可以帮助我们很好的理解函数,其语义是:关闭蓝牙系统,所有的link 都要断开,设备进入不可发现和不可连接的状态。
我这里的分析的case 就是当前蓝牙还连接着一个hid 设备的时候的disable 流程。
这里的重点是BTA_DisableBluetooth();,我这里先简单分析下其他的几个函数:
void btif_dm_on_disable() { /* cancel any pending pairing requests */ 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);//如果设备处于配对状态,那么取消配对 } }
这个很简单,如果设备处于配对状态,这个时候关闭设备,它的确应该取消配对,符合预期。
另外两个函数 一个和sock有关,另一个和pan有关,暂时都没有用到这些模块,暂时不分析。那么重点还是看BTA_DisableBluetooth();
/******************************************************************************* ** ** Function BTA_DisableBluetooth ** ** Description Disables bluetooth service. This function is called when ** the application no longer needs bluetooth service ** ** Returns void ** *******************************************************************************/ tBTA_STATUS BTA_DisableBluetooth(void) { BT_HDR *p_msg; if ((p_msg = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { p_msg->event = BTA_DM_API_DISABLE_EVT;//向DM模块发送disable bta_sys_sendmsg(p_msg); } ... return BTA_SUCCESS; }
这个函数就是向设备管理模块发送BTA_DM_API_DISABLE_EVT ,然后由设备管理模块继续进一步的操作。这里使用bta_sys_sendmsg,涉及到进程间通信,其他的文章中已经讲过,这里不赘述。最终调用的函数是在bta_dm_act.c中的bta_dm_disable:
/******************************************************************************* ** ** Function bta_dm_disable ** ** Description Disables the BT device manager ** ** ** Returns void ** *******************************************************************************/ void bta_dm_disable (tBTA_DM_MSG *p_data) { UNUSED(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, BT_TRANSPORT_BR_EDR);//设置idletimeout时间,设置为0 L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, 0, BT_TRANSPORT_LE); /* disable all active subsystems */ bta_sys_disable(BTA_SYS_HW_BLUETOOTH);//关闭蓝牙相关的各个子模块。这里涉及到短线等操作 BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, 0, 0);//不可发现 BTM_SetConnectability(BTM_NON_CONNECTABLE, 0, 0);//不可连接 bta_dm_disable_pm();//电源管理相关 bta_dm_disable_search_and_disc();//disable 搜索和服务发现的工作 bta_dm_cb.disabling = TRUE;//设置正在断开的标志位 #if BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE BTM_BleClearBgConnDev();//清除whitelist #endif if(BTM_GetNumAclLinks()==0)//如果已经没有link存在了,那么调用回调函数报告上层 { #if (defined(BTA_DISABLE_DELAY) && BTA_DISABLE_DELAY > 0) 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//如果还有link存在,启动一个定时器,如果5s之后还有link存在,那么执行定时器回调函数 { bta_dm_cb.disable_timer.p_cback = (TIMER_CBACK*)&bta_dm_disable_timer_cback; bta_dm_cb.disable_timer.param = 0; bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 5000); } }
上面的函数的重点是蓝牙关闭各个子模块的函数bta_sys_disable(BTA_SYS_HW_BLUETOOTH) ,简单分析下另外的函数。
首先看L2CA_SetIdleTimeoutByBdAddr这里的参数是任何设备,timeout 时间是0,其语义就像其注释“Set l2cap idle timeout to 0 (so BTE immediately disconnects ACL link after last channel is closed) ”当l2cap上面没有channel存在的时候,acl link会被立即断开。
BTM_SetDiscoverability和BTM_SetConnectability,这两个函数也是比较简单,告诉蓝牙控制器不要被发现,也不可被连接,最终控制器的做法是关闭scan。
bta_dm_disable_search_and_disc,这个函数的作用也和它的名字一样,肯定是有disable search和disable discovery两步。简单说一下,如果当前设备在搜索,那么调用bta_dm_search_cancel 来把这个行为cancel掉,根据具体情况,这里涉及到的可能的case包括:cancel 掉inquiry、cancel掉获取名字的流程、cancel掉GATT的流程以及向Bluetooth 应用汇报底层状态的行为。
下面我们看下BTM_BleClearBgConnDev:
/******************************************************************************* ** ** Function BTM_BleClearBgConnDev ** ** Description This function is called to clear the whitelist, ** end any pending whitelist connections, * and reset the local bg device list. ** ** Parameters void ** ** Returns void ** *******************************************************************************/ void BTM_BleClearBgConnDev(void) { btm_ble_start_auto_conn(FALSE); btm_ble_clear_white_list(); gatt_reset_bgdev_list(); }
我们还是看一下其注释,可知这个函数的主要作用就是清除whitelist,以及pending的连接,并且清空了bg device list
/******************************************************************************* ** ** Function btm_ble_start_auto_conn ** ** Description This function is to start/stop auto connection procedure. ** ** Parameters start: TRUE to start; FALSE to stop. ** ** Returns void ** *******************************************************************************/ BOOLEAN btm_ble_start_auto_conn(BOOLEAN start) { tBTM_BLE_CB *p_cb = &btm_cb.ble_ctr_cb; BD_ADDR dummy_bda = {0}; BOOLEAN exec = TRUE; UINT16 scan_int; UINT16 scan_win; UINT8 own_addr_type = p_cb->addr_mgnt_cb.own_addr_type; UINT8 peer_addr_type = BLE_ADDR_PUBLIC; if (start) { ... } else { if (p_cb->conn_state == BLE_BG_CONN) { btsnd_hcic_ble_create_conn_cancel();//如果已经init了BG conn,那么就取消 btm_ble_set_conn_st (BLE_CONN_CANCEL);//清除init状态 p_cb->wl_state &= ~BTM_BLE_WL_INIT;//清楚wl的init状态 } else { BTM_TRACE_DEBUG("conn_st = %d, not in auto conn state, cannot stop", p_cb->conn_state); exec = FALSE; } } return exec; }
注释里面的“end any pending whitelist connections” 对应的就是btm_ble_start_auto_conn(FALSE); 函数的行为,下面我们看看btm_ble_clear_white_list:
void btm_ble_clear_white_list (void) { BTM_TRACE_EVENT ("btm_ble_clear_white_list"); btsnd_hcic_ble_clear_white_list(); background_connections_clear(); }
这个很简单,就是下了一个HCI命令告知控制器要把wl清除掉,另外其把本地的BG connection list也清除了。关于BTM_BleClearBgConnDev 就说到这里。
接下来看一下BTM_GetNumAclLinks,这个函数是统计当前的ACL link的数量,如果是已经没有acl link了,那么BTA_DISABLE_DELAY 时间之后就可以调用bta_dm_disable_conn_down_timer_cback 来向上层汇报BTA_SYS_API_DISABLE_EVT这个行为。该文章分析的是有link存在的情况,是不走这个流程,但是我们可以猜想,等link 断开之后,应该还会走bta_dm_disable_conn_down_timer_cback 这个流程来上报事件。
最后说一下bta_dm_disable_timer_cback,这个函数 当超过5s,还有link没有断开的时候就会执行该函数来断开,其核心流程就是btm_remove_acl ,这里不做详细分析了。(只有当所有的link都断开了,这个定时器才会被取消)
我们现在看一下disable 的重点:关闭各个子模块:bta_sys_disable(BTA_SYS_HW_BLUETOOTH);
/******************************************************************************* ** ** Function bta_sys_disable ** ** Description For each registered subsystem execute its disable function. ** ** Returns void ** *******************************************************************************/ void bta_sys_disable(tBTA_SYS_HW_MODULE module) { int bta_id = 0; int bta_id_max = 0; switch( module ) { case BTA_SYS_HW_BLUETOOTH: bta_id = BTA_ID_DM; bta_id_max = BTA_ID_BLUETOOTH_MAX; break; default: APPL_TRACE_WARNING("bta_sys_disable: unkown module"); return; } for ( ; bta_id <= bta_id_max; bta_id++) { if (bta_sys_cb.reg[bta_id] != NULL) { if (bta_sys_cb.is_reg[bta_id] == TRUE && bta_sys_cb.reg[bta_id]->disable != NULL) { (*bta_sys_cb.reg[bta_id]->disable)(); } } } }
这个函数虽然执行的任务非常的多,但是其很好理解,就是调用每一个每一个子模块先前注册的handler的disable 函数,主要是做一些清理的工作。
下面对这些模块做一个简单的说明:
总共有哪些模块呢?如下:
/* SW sub-systems */ #define BTA_ID_SYS 0 /* system manager */ /* BLUETOOTH PART - from 0 to BTA_ID_BLUETOOTH_MAX */ #define BTA_ID_DM 1 /* device manager */ #define BTA_ID_DM_SEARCH 2 /* device manager search */ #define BTA_ID_DM_SEC 3 /* device manager security */ #define BTA_ID_DG 4 /* data gateway */ #define BTA_ID_AG 5 /* audio gateway */ #define BTA_ID_OPC 6 /* object push client */ #define BTA_ID_OPS 7 /* object push server */ #define BTA_ID_FTS 8 /* file transfer server */ #define BTA_ID_CT 9 /* cordless telephony terminal */ #define BTA_ID_FTC 10 /* file transfer client */ #define BTA_ID_SS 11 /* synchronization server */ #define BTA_ID_PR 12 /* Printer client */ #define BTA_ID_BIC 13 /* Basic Imaging Client */ #define BTA_ID_PAN 14 /* Personal Area Networking */ #define BTA_ID_BIS 15 /* Basic Imaging Server */ #define BTA_ID_ACC 16 /* Advanced Camera Client */ #define BTA_ID_SC 17 /* SIM Card Access server */ #define BTA_ID_AV 18 /* Advanced audio/video */ #define BTA_ID_AVK 19 /* Audio/video sink */ #define BTA_ID_HD 20 /* HID Device */ #define BTA_ID_CG 21 /* Cordless Gateway */ #define BTA_ID_BP 22 /* Basic Printing Client */ #define BTA_ID_HH 23 /* Human Interface Device Host */ #define BTA_ID_PBS 24 /* Phone Book Access Server */ #define BTA_ID_PBC 25 /* Phone Book Access Client */ #define BTA_ID_JV 26 /* Java */ #define BTA_ID_HS 27 /* Headset */ #define BTA_ID_MSE 28 /* Message Server Equipment */ #define BTA_ID_MCE 29 /* Message Client Equipment */ #define BTA_ID_HL 30 /* Health Device Profile*/ #define BTA_ID_GATTC 31 /* GATT Client */ #define BTA_ID_GATTS 32 /* GATT Client */ #define BTA_ID_SDP 33 /* SDP Client */ #define BTA_ID_BLUETOOTH_MAX 34 /* last BT profile */
前面几个是系统相关的:system manager、device manager、device manager search等,后面都是BT 的profile 模块。
那这些模块在哪里注册的呢?这里也简单介绍几个实例:
首先看看系统管理模块:
/******************************************************************************* ** ** Function bta_sys_init ** ** Description BTA initialization; called from task initialization. ** ** ** Returns void ** *******************************************************************************/ void bta_sys_init(void) { ... appl_trace_level = APPL_INITIAL_TRACE_LEVEL; /* register BTA SYS message handler */ bta_sys_register( BTA_ID_SYS, &bta_sys_hw_reg); ... }
发现系统管理模块在bta_sys_init 的时候就注册了,这也符合预期,看看其handler实现:
static const tBTA_SYS_REG bta_sys_hw_reg = { bta_sys_sm_execute, NULL //disable函数为NULL };
再看看device manager和device manager search模块的注册情况:
/******************************************************************************* ** ** Function BTA_EnableBluetooth ** ** Description Enables bluetooth service. This function must be ** called before any other functions in the BTA API are called. ** ** ** Returns tBTA_STATUS ** *******************************************************************************/ 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 ); ... }
这两个是蓝牙enable的时候注册的BTA_EnableBluetooth,看看他们的handler:
static const tBTA_SYS_REG bta_dm_reg = { bta_dm_sm_execute, bta_dm_sm_disable }; static const tBTA_SYS_REG bta_dm_search_reg = { bta_dm_search_sm_execute, bta_dm_search_sm_disable };
他们的disable函数也非常的简单,就是一个deregister的过程:
void bta_dm_search_sm_disable( ) { bta_sys_deregister( BTA_ID_DM_SEARCH ); }
下面我们找两个profile 看看:A2dp、GATT和HID
void BTA_AvEnable(tBTA_SEC sec_mask, tBTA_AV_FEAT features, tBTA_AV_CBACK *p_cback) { tBTA_AV_API_ENABLE *p_buf; /* register with BTA system manager */ bta_sys_register(BTA_ID_AV, &bta_av_reg);在AVenable的时候注册
static const tBTA_SYS_REG bta_av_reg = { bta_av_hdl_event, BTA_AvDisable };
看看disable的内容:
/******************************************************************************* ** ** Function BTA_AvDisable ** ** Description Disable the advanced audio/video service. ** ** Returns void ** *******************************************************************************/ void BTA_AvDisable(void) { BT_HDR *p_buf; bta_sys_deregister(BTA_ID_AV); if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { p_buf->event = BTA_AV_API_DISABLE_EVT;//会继续处理这个事件相关的东西 bta_sys_sendmsg(p_buf); } }
看看GATT的情况:
void BTA_GATTC_AppRegister(tBT_UUID *p_app_uuid, tBTA_GATTC_CBACK *p_client_cb) { tBTA_GATTC_API_REG *p_buf; if (bta_sys_is_register(BTA_ID_GATTC) == FALSE) { bta_sys_register(BTA_ID_GATTC, &bta_gattc_reg); }
static const tBTA_SYS_REG bta_gattc_reg = { bta_gattc_hdl_event, BTA_GATTC_Disable };
/******************************************************************************* ** ** Function BTA_GATTC_Disable ** ** Description This function is called to disable GATTC module ** ** Parameters None. ** ** Returns None ** *******************************************************************************/ void BTA_GATTC_Disable(void) { BT_HDR *p_buf; if (bta_sys_is_register(BTA_ID_GATTC) == FALSE) { APPL_TRACE_WARNING("GATTC Module not enabled/already disabled"); return; } if ((p_buf = (BT_HDR *) GKI_getbuf(sizeof(BT_HDR))) != NULL) { p_buf->event = BTA_GATTC_API_DISABLE_EVT; bta_sys_sendmsg(p_buf); } bta_sys_deregister(BTA_ID_GATTC); }
这边我们发现套路是一样的,都会去bta_sys_deregister,然后会发送事件相应的disable事件。
下面重点分析一下HID的情况:
/******************************************************************************* ** ** Function BTA_HhEnable ** ** Description Enable the HID host. This function must be called before ** any other functions in the HID host API are called. When the ** enable operation is complete the callback function will be ** called with BTA_HH_ENABLE_EVT. ** ** ** Returns void ** *******************************************************************************/ void BTA_HhEnable(tBTA_SEC sec_mask, tBTA_HH_CBACK *p_cback) { tBTA_HH_API_ENABLE *p_buf; /* register with BTA system manager */ bta_sys_register(BTA_ID_HH, &bta_hh_reg); ...
static const tBTA_SYS_REG bta_hh_reg = { bta_hh_hdl_event, BTA_HhDisable };
/******************************************************************************* ** ** Function BTA_HhDisable ** ** Description Disable the HID host. If the server is currently ** connected, the connection will be closed. ** ** Returns void ** *******************************************************************************/ void BTA_HhDisable(void) { BT_HDR *p_buf; bta_sys_deregister(BTA_ID_HH); if ((p_buf = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR))) != NULL) { p_buf->event = BTA_HH_API_DISABLE_EVT; bta_sys_sendmsg(p_buf); } }
这里注意一下,函数的注释,“如果当前的hid server是已经连接的,那么连接会被中断”,那我们可以想象,蓝牙都关闭了,和它连着的设备肯定也会断开的。
/******************************************************************************* ** ** Function bta_hh_hdl_event ** ** Description HID host main event handling function. ** ** ** Returns void ** *******************************************************************************/ BOOLEAN bta_hh_hdl_event(BT_HDR *p_msg) { UINT8 index = BTA_HH_IDX_INVALID; tBTA_HH_DEV_CB *p_cb = NULL; switch (p_msg->event) { case BTA_HH_API_ENABLE_EVT: bta_hh_api_enable((tBTA_HH_DATA *) p_msg); break; case BTA_HH_API_DISABLE_EVT: bta_hh_api_disable(); break;
继续看bta_hh_api_disable:
/******************************************************************************* ** ** Function bta_hh_api_disable ** ** Description Perform necessary operations to disable HID host. ** ** ** Returns void ** *******************************************************************************/ void bta_hh_api_disable(void) { UINT8 xx; /* service is not enabled */ if (bta_hh_cb.p_cback == NULL) return; /* no live connection, signal DISC_CMPL_EVT directly */ if (!bta_hh_cb.cnt_num) { bta_hh_disc_cmpl(); } else /* otherwise, disconnect all live connections */ //如果有连接断开所有的连接 { bta_hh_cb.w4_disable = TRUE; for(xx = 0; xx < BTA_HH_MAX_DEVICE; xx ++) { /* send API_CLOSE event to every connected device */ if ( bta_hh_cb.kdev[xx].state == BTA_HH_CONN_ST ) { /* disconnect all connected devices */ bta_hh_sm_execute(&bta_hh_cb.kdev[xx], BTA_HH_API_CLOSE_EVT, NULL); } } } return; }
这里分析的重点 就是bta_hh_sm_execute(&bta_hh_cb.kdev[xx],BTA_HH_API_CLOSE_EVT,NULL); 的流程
/******************************************************************************* ** ** Function bta_hh_sm_execute ** ** Description State machine event handling function for HID Host ** ** ** Returns void ** *******************************************************************************/ void bta_hh_sm_execute(tBTA_HH_DEV_CB *p_cb, UINT16 event, tBTA_HH_DATA * p_data) { tBTA_HH_ST_TBL state_table; UINT8 action; tBTA_HH cback_data; tBTA_HH_EVT cback_event = 0; #if BTA_HH_DEBUG == TRUE tBTA_HH_STATE in_state ; UINT16 debug_event = event; #endif memset(&cback_data, 0, sizeof(tBTA_HH)); ... else { if ((p_cb->state == BTA_HH_NULL_ST) || (p_cb->state >= BTA_HH_INVALID_ST)) { APPL_TRACE_ERROR("bta_hh_sm_execute: Invalid state State = 0x%x, Event = %d", p_cb->state,event); return; } state_table = bta_hh_st_tbl[p_cb->state - 1]; event &= 0xff; p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ; if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE) { (*bta_hh_action[action])(p_cb, p_data); } } return; }
上面的函数涉及到状态机,看似复杂,其实就是根据当前状态找到状态转换表,根据这张表就可以知道下一步做什么动作,然后根据这个动作就可以找到相应的函数:
当前状态是已经连接状态:
const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] = { /* Event Action Next state */ /* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, /* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST }, /* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST }, /* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, /* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST }, /* BTA_HH_INT_CTRL_DATA */ {BTA_HH_CTRL_DAT_ACT, BTA_HH_CONN_ST }, /* BTA_HH_INT_HANDSK_EVT */ {BTA_HH_HANDSK_ACT, BTA_HH_CONN_ST }, /* BTA_HH_SDP_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, /* BTA_HH_API_WRITE_DEV_EVT */ {BTA_HH_WRITE_DEV_ACT, BTA_HH_CONN_ST }, /* BTA_HH_API_GET_DSCP_EVT */ {BTA_HH_GET_DSCP_ACT, BTA_HH_CONN_ST }, /* BTA_HH_API_MAINT_DEV_EVT */ {BTA_HH_MAINT_DEV_ACT, BTA_HH_CONN_ST }, /* BTA_HH_OPEN_CMPL_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST } #if (defined BTA_HH_LE_INCLUDED && BTA_HH_LE_INCLUDED == TRUE) /* BTA_HH_GATT_CLOSE_EVT */ ,{BTA_HH_GATT_CLOSE, BTA_HH_IDLE_ST } /* BTA_HH_GATT_OPEN_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } /* BTA_HH_START_ENC_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } /* BTA_HH_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } /* READ_CHAR_CMPL_EVT */ ,{BTA_HH_LE_READ_CHAR, BTA_HH_CONN_ST } /* WRITE_CHAR_CMPL_EVT*/ ,{BTA_HH_LE_WRITE, BTA_HH_CONN_ST } /* READ_DESCR_CMPL_EVT */ ,{BTA_HH_LE_READ_DESCR, BTA_HH_CONN_ST } /* do not currently read any descr when connection up */ /* WRITE_DESCR_CMPL_EVT */ ,{BTA_HH_WRITE_DESCR, BTA_HH_CONN_ST } /* do not currently write any descr when connection up */ /* SCPP_UPDATE_EVT */ ,{BTA_HH_LE_UPDATE_SCPP, BTA_HH_CONN_ST } /* BTA_HH_GATT_ENC_CMPL_EVT */ ,{BTA_HH_IGNORE, BTA_HH_CONN_ST } #endif }
根据这张表我们知道,下一个状态依然是已连接状态,下一个要执行的行为是BTA_HH_API_DISC_ACT,看这个行为对应的函数 :
/******************************************************************************* ** ** Function bta_hh_api_disc_act ** ** Description HID Host initiate a disconnection. ** ** ** Returns void ** *******************************************************************************/ void bta_hh_api_disc_act(tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) { tBTA_HH_CBDATA disc_dat; tHID_STATUS status; if (p_cb->is_le_device) bta_hh_le_api_disc_only_act(p_cb);//这里le 没有active else { /* found an active connection */ disc_dat.handle = p_data ?(UINT8)p_data->hdr.layer_specific :p_cb->hid_handle; disc_dat.status = BTA_HH_ERR; status = HID_HostCloseDev(disc_dat.handle);断开连接 if (status) (* bta_hh_cb.p_cback)(BTA_HH_CLOSE_EVT, (tBTA_HH *)&disc_dat);//成功之后上报close事件 } return; }
这里看看HID_HostCloseDev的实现:
/******************************************************************************* ** ** Function HID_HostCloseDev ** ** Description This function disconnects the device. ** ** Returns void ** *******************************************************************************/ tHID_STATUS HID_HostCloseDev( UINT8 dev_handle ) { if( !hh_cb.reg_flag ) return (HID_ERR_NOT_REGISTERED); if( (dev_handle >= HID_HOST_MAX_DEVICES) || (!hh_cb.devices[dev_handle].in_use) ) return HID_ERR_INVALID_PARAM; hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1; btu_stop_timer( &(hh_cb.devices[dev_handle].conn.timer_entry) ) ; if( hh_cb.devices[dev_handle].state != HID_DEV_CONNECTED ) return HID_ERR_NO_CONNECTION; hh_cb.devices[dev_handle].conn_tries = HID_HOST_MAX_CONN_RETRY+1; return hidh_conn_disconnect( dev_handle );//执行这里 }
/******************************************************************************* ** ** Function hidh_conn_disconnect ** ** Description This function disconnects a connection. ** ** Returns TRUE if disconnect started, FALSE if already disconnected ** *******************************************************************************/ tHID_STATUS hidh_conn_disconnect (UINT8 dhandle) { tHID_CONN *p_hcon = &hh_cb.devices[dhandle].conn; if ((p_hcon->ctrl_cid != 0) || (p_hcon->intr_cid != 0)) { p_hcon->conn_state = HID_CONN_STATE_DISCONNECTING; /* Set l2cap idle timeout to 0 (so ACL link is disconnected * immediately after last channel is closed) */ L2CA_SetIdleTimeoutByBdAddr(hh_cb.devices[dhandle].addr, 0, BT_TRANSPORT_BR_EDR); /* Disconnect both interrupt and control channels */ if (p_hcon->intr_cid) L2CA_DisconnectReq (p_hcon->intr_cid); else if (p_hcon->ctrl_cid) L2CA_DisconnectReq (p_hcon->ctrl_cid); } else { p_hcon->conn_state = HID_CONN_STATE_UNUSED; } return (HID_SUCCESS); }
我们可以看出主要执行的函数是hidh_conn_disconnect ,发现这个 hid host应该是有两个通道,一个中断通道,一个控制通道
这边结合btsnoop 看了一下发现,中断通道是用来传播数据的。控制通道是用来传输控制信令的。具体可能还要研究下hid profile
我们继续看,这里通过L2CA_SetIdleTimeoutByBdAddr设置了设备的idle timeout时间 为0,其实这个在一开始的disable 的函数的入口就已经设置过了。
从代码的逻辑可以看出,是优先释放中断通道,这个也好理解,因为中断通道是传输数据的。传输信令的通道肯定是后释放。下面看l2cap 层面channel的释放过程:
以下简述l2cap的释放过程,不感兴趣的可以直接略过。
这里已经走到了l2cap层:
/******************************************************************************* ** ** Function L2CA_DisconnectReq ** ** Description Higher layers call this function to disconnect a channel. ** ** Returns TRUE if disconnect sent, else FALSE ** *******************************************************************************/ BOOLEAN L2CA_DisconnectReq (UINT16 cid) { tL2C_CCB *p_ccb; counter_add("l2cap.disconn.req", 1); /* Find the channel control block. We don't know the link it is on. */ if ((p_ccb = l2cu_find_ccb_by_cid (NULL, cid)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no CCB for L2CA_disc_req, CID: %d", cid); return (FALSE); } l2c_csm_execute (p_ccb, L2CEVT_L2CA_DISCONNECT_REQ, NULL);对于该channel 执行操作 return (TRUE); }
这里会先根据cid 来找这个channel control block,然后 调用l2c_csm_execute 继续执行:
/******************************************************************************* ** ** Function l2c_csm_execute ** ** Description This function executes the state machine. ** ** Returns void ** *******************************************************************************/ void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data) { switch (p_ccb->chnl_state) { case CST_CLOSED: l2c_csm_closed (p_ccb, event, p_data); break; ... case CST_OPEN: l2c_csm_open (p_ccb, event, p_data);//当前是open状态 break; ...
继续看l2c_csm_open:
static void l2c_csm_open (tL2C_CCB *p_ccb, UINT16 event, void *p_data) { UINT16 local_cid = p_ccb->local_cid; tL2CAP_CFG_INFO *p_cfg; tL2C_CHNL_STATE tempstate; UINT8 tempcfgdone; UINT8 cfg_result; ... switch (event) { ... case L2CEVT_L2CA_DISCONNECT_REQ: /* Upper wants to disconnect */ /* Make sure we are not in sniff mode */ { tBTM_PM_PWR_MD settings; memset((void*)&settings, 0, sizeof(settings)); settings.mode = BTM_PM_MD_ACTIVE; BTM_SetPowerMode (BTM_PM_SET_ONLY_ID, p_ccb->p_lcb->remote_bd_addr, &settings);//HCI_Exit_Sniff_Mode } l2cu_send_peer_disc_req (p_ccb);//发送给对端设备 p_ccb->chnl_state = CST_W4_L2CAP_DISCONNECT_RSP;//设置当前状态 btu_start_timer (&p_ccb->timer_entry, BTU_TTYPE_L2CAP_CHNL, L2CAP_CHNL_DISCONNECT_TOUT); break; ...
接下来就会收到对端设备对于断开channel 的回复,我们执行的函数还是
void l2c_csm_execute (tL2C_CCB *p_ccb, UINT16 event, void *p_data) { switch (p_ccb->chnl_state) { case CST_CLOSED: l2c_csm_closed (p_ccb, event, p_data); break; ... case CST_W4_L2CAP_DISCONNECT_RSP: l2c_csm_w4_l2cap_disconnect_rsp (p_ccb, event, p_data); break; ...
static void l2c_csm_w4_l2cap_disconnect_rsp (tL2C_CCB *p_ccb, UINT16 event, void *p_data) { tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb; UINT16 local_cid = p_ccb->local_cid; switch (event) { case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */ l2cu_release_ccb (p_ccb); if (disconnect_cfm) { (*disconnect_cfm)(local_cid, L2CAP_DISC_OK); } break; ...
接收到对端的回复之后,可以直接调用l2cu_release_ccb (p_ccb);来释放掉channel 了,
我们看看具体的处理:
/******************************************************************************* ** ** Function l2cu_release_ccb ** ** Description This function releases a Channel Control Block. The timer ** is stopped, any attached buffers freed, and the CCB is removed ** from the link control block. ** ** Returns void ** *******************************************************************************/ void l2cu_release_ccb (tL2C_CCB *p_ccb) { tL2C_LCB *p_lcb = p_ccb->p_lcb; tL2C_RCB *p_rcb = p_ccb->p_rcb; if (p_rcb && (p_rcb->psm != p_rcb->real_psm)) { btm_sec_clr_service_by_psm(p_rcb->psm); } if (p_ccb->should_free_rcb) { osi_free(p_rcb); p_ccb->p_rcb = NULL; p_ccb->should_free_rcb = false; } btm_sec_clr_temp_auth_service (p_lcb->remote_bd_addr); /* Stop the timer */ btu_stop_timer (&p_ccb->timer_entry); while (!GKI_queue_is_empty(&p_ccb->xmit_hold_q)) GKI_freebuf (GKI_dequeue (&p_ccb->xmit_hold_q)); l2c_fcr_cleanup (p_ccb); /* Channel may not be assigned to any LCB if it was just pre-reserved */ if ( (p_lcb) && ( (p_ccb->local_cid >= L2CAP_BASE_APPL_CID) #if (L2CAP_UCD_INCLUDED == TRUE) ||(p_ccb->local_cid == L2CAP_CONNECTIONLESS_CID) #endif ) ) { l2cu_dequeue_ccb (p_ccb);//通过ccb找到lcb里面的ccb队列,并移除 /* Delink the CCB from the LCB */ p_ccb->p_lcb = NULL;//ccb不再保存指向lcb的指针 } /* Put the CCB back on the free pool */ if (!l2cb.p_free_ccb_first)//把ccb放到l2cb.p_free_ccb_queue 队列 { l2cb.p_free_ccb_first = p_ccb; l2cb.p_free_ccb_last = p_ccb; p_ccb->p_next_ccb = NULL; p_ccb->p_prev_ccb = NULL; } else { p_ccb->p_next_ccb = NULL; p_ccb->p_prev_ccb = l2cb.p_free_ccb_last; l2cb.p_free_ccb_last->p_next_ccb = p_ccb; l2cb.p_free_ccb_last = p_ccb; } /* Flag as not in use */ p_ccb->in_use = FALSE; /* If no channels on the connection, start idle timeout */ if ((p_lcb) && p_lcb->in_use && (p_lcb->link_state == LST_CONNECTED)) { if (!p_lcb->ccb_queue.p_first_ccb)//如果没有ccb 存在 { l2cu_no_dynamic_ccbs (p_lcb);//这里主要是断开link } else { /* Link is still active, adjust channel quotas. */ l2c_link_adjust_chnl_allocation (); } } }
做的事情主要就是从lcb里面移除ccb,如果link上面没有ccb存在了,那么断开link。简单看一下l2cu_no_dynamic_ccbs的实现:
/******************************************************************************* ** ** Function l2cu_no_dynamic_ccbs ** ** Description Handles the case when there are no more dynamic CCBs. If there ** are any fixed CCBs, start the longest of the fixed CCB timeouts, ** otherwise start the default link idle timeout or disconnect. ** ** Returns void ** *******************************************************************************/ void l2cu_no_dynamic_ccbs (tL2C_LCB *p_lcb) { tBTM_STATUS rc; UINT16 timeout = p_lcb->idle_timeout; #if (L2CAP_NUM_FIXED_CHNLS > 0) int xx; for (xx = 0; xx < L2CAP_NUM_FIXED_CHNLS; xx++)//在p_fixed_ccbs中找idletimeout最大的 { if ( (p_lcb->p_fixed_ccbs[xx] != NULL) && (p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout > timeout) ) timeout = p_lcb->p_fixed_ccbs[xx]->fixed_chnl_idle_tout; } #endif /* If the link is pairing, do not mess with the timeouts */ if (p_lcb->is_bonding) return; if (timeout == 0) { rc = btm_sec_disconnect (p_lcb->handle, HCI_ERR_PEER_USER);//直接断开 if (rc == BTM_CMD_STARTED) { l2cu_process_fixed_disc_cback(p_lcb); p_lcb->link_state = LST_DISCONNECTING; timeout = L2CAP_LINK_DISCONNECT_TOUT; } else if (rc == BTM_SUCCESS) { l2cu_process_fixed_disc_cback(p_lcb); /* BTM SEC will make sure that link is release (probably after pairing is done) */ p_lcb->link_state = LST_DISCONNECTING; timeout = 0xFFFF; } else if ( (p_lcb->is_bonding) && (btsnd_hcic_disconnect (p_lcb->handle, HCI_ERR_PEER_USER)) ) { l2cu_process_fixed_disc_cback(p_lcb); p_lcb->link_state = LST_DISCONNECTING; timeout = L2CAP_LINK_DISCONNECT_TOUT; } else { /* probably no buffer to send disconnect */ timeout = BT_1SEC_TIMEOUT; } } if (timeout != 0xFFFF) { btu_start_timer (&p_lcb->timer_entry, BTU_TTYPE_L2CAP_LINK, timeout); } else { btu_stop_timer(&p_lcb->timer_entry); } }
这里我们还要回到l2c_csm_w4_l2cap_disconnect_rsp函数中,我们已经分析了:l2cu_release_ccb的流程
case L2CEVT_L2CAP_DISCONNECT_RSP: /* Peer disconnect response */ l2cu_release_ccb (p_ccb); if (disconnect_cfm) { (*disconnect_cfm)(local_cid, L2CAP_DISC_OK); } break;
下面我们继续分析一下disconnect_cfm 的流程:
tL2CA_DISCONNECT_CFM_CB *disconnect_cfm = p_ccb->p_rcb->api.pL2CA_DisconnectCfm_Cb; 从该语句,我们可以猜想到这个函数是从l2cap的上层注册到l2cap的,那具体是在哪里注册的呢?
是在bta_hh_api_enable 里面一步一步注册的:
/***************************************************************************** ** Action Functions *****************************************************************************/ /******************************************************************************* ** ** Function bta_hh_api_enable ** ** Description Perform necessary operations to enable HID host. ** ** ** Returns void ** *******************************************************************************/ void bta_hh_api_enable(tBTA_HH_DATA *p_data) { tBTA_HH_STATUS status = BTA_HH_ERR; UINT8 xx; /* initialize BTE HID */ HID_HostInit(); memset(&bta_hh_cb, 0, sizeof(tBTA_HH_CB)); HID_HostSetSecurityLevel("", p_data->api_enable.sec_mask); /* Register with L2CAP */ if ( HID_HostRegister (bta_hh_cback) == HID_SUCCESS) //注册到l2cap ...
Register with L2CAP使用的是hidh_conn_reg,另外注意到这里还传入了一个参数,注册了一个hh_cb.callback = bta_hh_cback ; 后面上报事件的时候会调用到
/******************************************************************************* ** ** Function HID_HostRegister ** ** Description This function registers HID-Host with lower layers ** ** Returns tHID_STATUS ** *******************************************************************************/ tHID_STATUS HID_HostRegister (tHID_HOST_DEV_CALLBACK *dev_cback) { tHID_STATUS st; if( hh_cb.reg_flag ) return HID_ERR_ALREADY_REGISTERED; if( dev_cback == NULL ) return HID_ERR_INVALID_PARAM; /* Register with L2CAP */ if( (st = hidh_conn_reg()) != HID_SUCCESS ) {
return st;
}
hh_cb.callback = dev_cback ;
hh_cb.reg_flag = TRUE;
return (HID_SUCCESS);
/******************************************************************************* ** ** Function hidh_l2cif_reg ** ** Description This function initializes the SDP unit. ** ** Returns void ** *******************************************************************************/ tHID_STATUS hidh_conn_reg (void) { int xx; /* Initialize the L2CAP configuration. We only care about MTU and flush */ memset(&hh_cb.l2cap_cfg, 0, sizeof(tL2CAP_CFG_INFO)); hh_cb.l2cap_cfg.mtu_present = TRUE; hh_cb.l2cap_cfg.mtu = HID_HOST_MTU; hh_cb.l2cap_cfg.flush_to_present = TRUE; hh_cb.l2cap_cfg.flush_to = HID_HOST_FLUSH_TO; /* Now, register with L2CAP */ if (!L2CA_Register (HID_PSM_CONTROL, (tL2CAP_APPL_INFO *) &hst_reg_info)) { HIDH_TRACE_ERROR ("HID-Host Control Registration failed"); return (HID_ERR_L2CAP_FAILED) ; } if (!L2CA_Register (HID_PSM_INTERRUPT, (tL2CAP_APPL_INFO *) &hst_reg_info)) { ...
这里我们看到了L2CA_Register了,
/******************************************************************************* ** ** Function L2CA_Register ** ** Description Other layers call this function to register for L2CAP ** services. ** ** Returns PSM to use or zero if error. Typically, the PSM returned ** is the same as was passed in, but for an outgoing-only ** connection to a dynamic PSM, a "virtual" PSM is returned ** and should be used in the calls to L2CA_ConnectReq(), ** L2CA_ErtmConnectReq() and L2CA_Deregister() ** *******************************************************************************/ UINT16 L2CA_Register (UINT16 psm, tL2CAP_APPL_INFO *p_cb_info) { tL2C_RCB *p_rcb; UINT16 vpsm = psm; L2CAP_TRACE_API ("L2CAP - L2CA_Register() called for PSM: 0x%04x", psm); /* Verify that the required callback info has been filled in ** Note: Connection callbacks are required but not checked ** for here because it is possible to be only a client ** or only a server. */ if ((!p_cb_info->pL2CA_ConfigCfm_Cb) || (!p_cb_info->pL2CA_ConfigInd_Cb) || (!p_cb_info->pL2CA_DataInd_Cb) || (!p_cb_info->pL2CA_DisconnectInd_Cb)) { L2CAP_TRACE_ERROR ("L2CAP - no cb registering PSM: 0x%04x", psm); return (0); } /* Verify PSM is valid */ if (L2C_INVALID_PSM(psm)) { L2CAP_TRACE_ERROR ("L2CAP - invalid PSM value, PSM: 0x%04x", psm); return (0); } /* Check if this is a registration for an outgoing-only connection to */ /* a dynamic PSM. If so, allocate a "virtual" PSM for the app to use. */ if ( (psm >= 0x1001) && (p_cb_info->pL2CA_ConnectInd_Cb == NULL) ) { for (vpsm = 0x1002; vpsm < 0x8000; vpsm += 2) { if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL) break; } L2CAP_TRACE_API ("L2CA_Register - Real PSM: 0x%04x Virtual PSM: 0x%04x", psm, vpsm); } /* If registration block already there, just overwrite it */ if ((p_rcb = l2cu_find_rcb_by_psm (vpsm)) == NULL) { if ((p_rcb = l2cu_allocate_rcb (vpsm)) == NULL) { L2CAP_TRACE_WARNING ("L2CAP - no RCB available, PSM: 0x%04x vPSM: 0x%04x", psm, vpsm); return (0); } } p_rcb->api = *p_cb_info; p_rcb->real_psm = psm; return (vpsm); }
我们看看hst_reg_info这个结构:
static const tL2CAP_APPL_INFO hst_reg_info = { hidh_l2cif_connect_ind, hidh_l2cif_connect_cfm, NULL, hidh_l2cif_config_ind, hidh_l2cif_config_cfm, hidh_l2cif_disconnect_ind, hidh_l2cif_disconnect_cfm, NULL, hidh_l2cif_data_ind, hidh_l2cif_cong_ind, NULL /* tL2CA_TX_COMPLETE_CB */ }
现在我们知道disconnect_cfm = hidh_l2cif_disconnect_cfm
/******************************************************************************* ** ** Function hidh_l2cif_disconnect_cfm ** ** Description This function handles a disconnect confirm event from L2CAP. ** ** Returns void ** *******************************************************************************/ static void hidh_l2cif_disconnect_cfm (UINT16 l2cap_cid, UINT16 result) { UINT8 dhandle; tHID_CONN *p_hcon = NULL; UNUSED(result); /* Find CCB based on CID */ if( (dhandle = find_conn_by_cid(l2cap_cid)) < HID_HOST_MAX_DEVICES ) p_hcon = &hh_cb.devices[dhandle].conn; if (p_hcon == NULL) { HIDH_TRACE_WARNING ("HID-Host Rcvd L2CAP disc cfm, unknown CID: 0x%x", l2cap_cid); return; } if (l2cap_cid == p_hcon->ctrl_cid) p_hcon->ctrl_cid = 0; else { p_hcon->intr_cid = 0; if (p_hcon->ctrl_cid) { L2CA_DisconnectReq (p_hcon->ctrl_cid);//控制通道没有断开,继续断开 } } if ((p_hcon->ctrl_cid == 0) && (p_hcon->intr_cid == 0)) { hh_cb.devices[dhandle].state = HID_DEV_NO_CONN; p_hcon->conn_state = HID_CONN_STATE_UNUSED; hh_cb.callback( dhandle, hh_cb.devices[dhandle].addr, HID_HDEV_EVT_CLOSE, p_hcon->disc_reason, NULL ) ;//调用回调上报事件 } }
接下来的断开控制channel 和断开中断channel的流程是一样的。这里就不赘述了,通道都断开之后,link就会被断开。
link全部断开之后会调用hh_cb.callback向上汇报事情:这个回调函数就是bta_hh_cback,看看其做的事情:
/***************************************************************************** ** Static Function *****************************************************************************/ /******************************************************************************* ** ** Function bta_hh_cback ** ** Description BTA HH callback function. ** ** ** Returns void ** *******************************************************************************/ static void bta_hh_cback (UINT8 dev_handle, BD_ADDR addr, UINT8 event, UINT32 data, BT_HDR *pdata) { tBTA_HH_CBACK_DATA *p_buf = NULL; UINT16 sm_event = BTA_HH_INVALID_EVT; UINT8 xx = 0; #if BTA_HH_DEBUG APPL_TRACE_DEBUG("bta_hh_cback::HID_event [%s]", bta_hh_hid_event_name(event)); #endif switch (event) { case HID_HDEV_EVT_OPEN: sm_event = BTA_HH_INT_OPEN_EVT; break; case HID_HDEV_EVT_CLOSE: sm_event = BTA_HH_INT_CLOSE_EVT; break; ... } if (sm_event != BTA_HH_INVALID_EVT && (p_buf = (tBTA_HH_CBACK_DATA *)GKI_getbuf(sizeof(tBTA_HH_CBACK_DATA) + sizeof(BT_HDR))) != NULL) { p_buf->hdr.event = sm_event; p_buf->hdr.layer_specific = (UINT16)dev_handle; p_buf->data = data; bdcpy(p_buf->addr, addr); p_buf->p_data = pdata; bta_sys_sendmsg(p_buf);//发送事件到bt_work_queue } }
从代码中可以看到这里发送的事件 是BTA_HH_INT_CLOSE_EVT:看看其处理:
HH的event 会交给bta_hh_hdl_event 来处理,然后根据事件类型路由到bta_hh_sm_execute,在这里处理的也很简单,都是一样的套路:
state_table = bta_hh_st_tbl[p_cb->state - 1];//找到状态转换表 event &= 0xff;//取出子事件 p_cb->state = state_table[event][BTA_HH_NEXT_STATE] ;//设置下一个状态 if ((action = state_table[event][BTA_HH_ACTION]) != BTA_HH_IGNORE) { (*bta_hh_action[action])(p_cb, p_data);//执行action }
现在处于已经连接状态:
const UINT8 bta_hh_st_connected[][BTA_HH_NUM_COLS] = { /* Event Action Next state */ /* BTA_HH_API_OPEN_EVT */ {BTA_HH_IGNORE, BTA_HH_CONN_ST }, /* BTA_HH_API_CLOSE_EVT */ {BTA_HH_API_DISC_ACT, BTA_HH_CONN_ST }, /* BTA_HH_INT_OPEN_EVT */ {BTA_HH_OPEN_ACT, BTA_HH_CONN_ST }, /* BTA_HH_INT_CLOSE_EVT */ {BTA_HH_CLOSE_ACT, BTA_HH_IDLE_ST }, /* BTA_HH_INT_DATA_EVT */ {BTA_HH_DATA_ACT, BTA_HH_CONN_ST },
我们发现下一个状态是BTA_HH_IDLE_ST ,当前要执行的操作是BTA_HH_CLOSE_ACT:对应的行为是bta_hh_close_act
/******************************************************************************* ** ** Function bta_hh_close_act ** ** Description HID Host process a close event ** ** ** Returns void ** *******************************************************************************/ void bta_hh_close_act (tBTA_HH_DEV_CB *p_cb, tBTA_HH_DATA *p_data) { tBTA_HH_CONN conn_dat ; tBTA_HH_CBDATA disc_dat = {BTA_HH_OK, 0}; UINT32 reason = p_data->hid_cback.data; /* Reason for closing (32-bit) */ UINT16 event = p_cb->vp ? BTA_HH_VC_UNPLUG_EVT : BTA_HH_CLOSE_EVT; disc_dat.handle = p_cb->hid_handle; disc_dat.status = p_data->hid_cback.data; /* Check reason for closing */ if ((reason & (HID_L2CAP_CONN_FAIL|HID_L2CAP_REQ_FAIL)) || /* Failure to initialize connection (page timeout or l2cap error) */ (reason == HID_ERR_AUTH_FAILED) || /* Authenication error (while initiating) */ (reason == HID_ERR_L2CAP_FAILED)) /* Failure creating l2cap connection */ { ... } /* otherwise report CLOSE/VC_UNPLUG event */ else { /* finaliza device driver */ bta_hh_co_close(p_cb->hid_handle, p_cb->app_id);//close /* inform role manager */ bta_sys_conn_close( BTA_ID_HH ,p_cb->app_id, p_cb->addr); /* update total conn number */ bta_hh_cb.cnt_num --; if (disc_dat.status) disc_dat.status = BTA_HH_ERR; (*bta_hh_cb.p_cback)(event, (tBTA_HH *)&disc_dat); ... } /* clean up control block, but retain SDP info and device handle */ p_cb->vp = FALSE; p_cb->w4_evt = 0; /* if no connection is active and HH disable is signaled, disable service */ if (bta_hh_cb.cnt_num == 0 && bta_hh_cb.w4_disable) { bta_hh_disc_cmpl(); } return; }
上面的过程主要做了 bta_hh_co_close 和 bta_hh_cb.p_cback 以及bta_hh_disc_cmpl()
bta_hh_co_close 主要做的是close 通信的节点,以及一些和driver 有关的事情,和结束poll线程的行为btif_hh_close_poll_thread
bta_hh_cb.p_cback 这个是一个回调函数,从这个函数的名字上来看,应该是应用层传下来的callback,这边搜索了一下代码,是bte_hh_evt这个函数,他是在哪里注册的呢?
bt_status_t btif_hh_execute_service(BOOLEAN b_enable) { if (b_enable) { /* Enable and register with BTA-HH */ BTA_HhEnable(BTUI_HH_SECURITY, bte_hh_evt);
这个回调函数做的事情也就是 向上层汇报disable的事件:
/******************************************************************************* ** ** Function bte_hh_evt ** ** Description Switches context from BTE to BTIF for all HH events ** ** Returns void ** *******************************************************************************/ static void bte_hh_evt(tBTA_HH_EVT event, tBTA_HH *p_data) { bt_status_t status; int param_len = 0; if (BTA_HH_ENABLE_EVT == event) param_len = sizeof(tBTA_HH_STATUS); else if (BTA_HH_OPEN_EVT == event) param_len = sizeof(tBTA_HH_CONN); else if (BTA_HH_DISABLE_EVT == event) param_len = sizeof(tBTA_HH_STATUS); else if (BTA_HH_CLOSE_EVT == event) param_len = sizeof(tBTA_HH_CBDATA); else if (BTA_HH_GET_DSCP_EVT == event) param_len = sizeof(tBTA_HH_DEV_DSCP_INFO); else if ((BTA_HH_GET_PROTO_EVT == event) || (BTA_HH_GET_RPT_EVT == event)|| (BTA_HH_GET_IDLE_EVT == event)) param_len = sizeof(tBTA_HH_HSDATA); else if ((BTA_HH_SET_PROTO_EVT == event) || (BTA_HH_SET_RPT_EVT == event) || (BTA_HH_VC_UNPLUG_EVT == event) || (BTA_HH_SET_IDLE_EVT == event)) param_len = sizeof(tBTA_HH_CBDATA); else if ((BTA_HH_ADD_DEV_EVT == event) || (BTA_HH_RMV_DEV_EVT == event) ) param_len = sizeof(tBTA_HH_DEV_INFO); else if (BTA_HH_API_ERR_EVT == event) param_len = 0; /* switch context to btif task context (copy full union size for convenience) */ status = btif_transfer_context(btif_hh_upstreams_evt, (uint16_t)event, (void*)p_data, param_len, NULL);//通过btif_hh_upstreams_evt 上报 /* catch any failed context transfers */ ASSERTC(status == BT_STATUS_SUCCESS, "context transfer failed", status); }
简单看下:
static void btif_hh_upstreams_evt(UINT16 event, char* p_param) { tBTA_HH *p_data = (tBTA_HH *)p_param; btif_hh_device_t *p_dev = NULL; int i; int len, tmplen; switch (event) { ... case BTA_HH_CLOSE_EVT: p_dev = btif_hh_find_connected_dev_by_handle(p_data->dev_status.handle); if (p_dev != NULL) { if(p_dev->vup_timer_active) btif_hh_stop_vup_timer(&(p_dev->bd_addr)); if (p_dev->fd >= 0) { bta_hh_co_destroy(p_dev->fd);//销毁节点 p_dev->fd = -1; } btif_hh_cb.status = BTIF_HH_DEV_DISCONNECTED; p_dev->dev_status = BTHH_CONN_STATE_DISCONNECTED; HAL_CBACK(bt_hh_callbacks, connection_state_cb,&(p_dev->bd_addr), p_dev->dev_status);继续向上汇报状态 } ...
这是定义在JNI层的函数com_android_bluetooth_hid.cpp;
static bthh_callbacks_t sBluetoothHidCallbacks = { sizeof(sBluetoothHidCallbacks), connection_state_callback,//会一直调用到java层 NULL, get_protocol_mode_callback, NULL, get_report_callback, virtual_unplug_callback, handshake_callback };
bta_hh_disc_cmpl()的 实现很简单:
/******************************************************************************* ** ** Function bta_hh_disc_cmpl ** ** Description All connections have been closed, disable service. ** ** ** Returns void ** *******************************************************************************/ void bta_hh_disc_cmpl(void) { tBTA_HH_STATUS status = BTA_HH_OK; /* Deregister with lower layer */ if (HID_HostDeregister() != HID_SUCCESS) status = BTA_HH_ERR; #if (BTA_HH_LE_INCLUDED == TRUE) bta_hh_le_deregister(); UNUSED(status); #else bta_hh_cleanup_disable(status);//会再次发送一个事件BTA_HH_DISABLE_EVT到btif_hh_upstreams_evt
#endif }
做的事情就是清空各种结构体:
case BTA_HH_DISABLE_EVT: btif_hh_cb.status = BTIF_HH_DISABLED; if (p_data->status == BTA_HH_OK) { int i; //Clear the control block memset(&btif_hh_cb, 0, sizeof(btif_hh_cb)); for (i = 0; i < BTIF_HH_MAX_HID; i++){ btif_hh_cb.devices[i].dev_status = BTHH_CONN_STATE_UNKNOWN; } }
到此,关于hid 设备的在蓝牙disable 过程中所走的流程就分析完了。
最后说一下 bta_dm_disable_conn_down_timer_cback 的执行时机,在disable 的初期,如果没有蓝牙link存在,那么会直接执行,如果有蓝牙link,那么会将所有的蓝牙link断开,然后去执行。
当蓝牙link 全部断开,会有断开完成事件上来,然后通过l2cu_release_lcb清除lcb,然后告诉BTM Acl management 这个link的已经被移除了(btm_acl_removed),接着通过btm_cb.p_bl_changed_cb = bta_dm_bl_change_cback 的回调,
/******************************************************************************* ** ** Function bta_dm_bl_change_cback ** ** Description Callback from btm when acl connection goes up or down ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_bl_change_cback (tBTM_BL_EVENT_DATA *p_data) { tBTA_DM_ACL_CHANGE * p_msg; if ((p_msg = (tBTA_DM_ACL_CHANGE *) GKI_getbuf(sizeof(tBTA_DM_ACL_CHANGE))) != NULL) { p_msg->event = p_data->event; p_msg->is_new = FALSE;//不是new switch(p_msg->event) { case BTM_BL_CONN_EVT: p_msg->is_new = TRUE; bdcpy(p_msg->bd_addr, p_data->conn.p_bda); #if BLE_INCLUDED == TRUE p_msg->transport = p_data->conn.transport; p_msg->handle = p_data->conn.handle; #endif break; case BTM_BL_DISCN_EVT: bdcpy(p_msg->bd_addr, p_data->discn.p_bda); #if BLE_INCLUDED == TRUE p_msg->transport = p_data->discn.transport; p_msg->handle = p_data->discn.handle; #endif break; case BTM_BL_UPDATE_EVT: p_msg->busy_level = p_data->update.busy_level; p_msg->busy_level_flags = p_data->update.busy_level_flags; break; ... } p_msg->hdr.event = BTA_DM_ACL_CHANGE_EVT;//发送event bta_sys_sendmsg(p_msg); } }
最终会处理两个事件BTM_BL_DISCN_EVT和BTM_BL_UPDATE_EVT,看该函数的注释也可以看出,它会在link 状态改变的时候被调用。最终会发送一个BTA_DM_ACL_CHANGE_EVT 到device manager
执行函数实现在bta_dm_act.c里面的bta_dm_acl_change ,
/******************************************************************************* ** ** Function bta_dm_acl_change ** ** Description Process BTA_DM_ACL_CHANGE_EVT ** ** ** Returns void ** *******************************************************************************/ void bta_dm_acl_change(tBTA_DM_MSG *p_data) { UINT8 i; UINT8 *p; tBTA_DM_SEC conn; BOOLEAN is_new = p_data->acl_change.is_new; BD_ADDR_PTR p_bda = p_data->acl_change.bd_addr; BOOLEAN need_policy_change = FALSE; BOOLEAN issue_unpair_cb = FALSE; tBTA_DM_PEER_DEVICE *p_dev; memset(&conn, 0, sizeof(tBTA_DM_SEC)); ... if(is_new) { ... } else { for(i=0; i<bta_dm_cb.device_list.count; i++) { if (bdcmp( bta_dm_cb.device_list.peer_device[i].peer_bdaddr, p_bda) #if BLE_INCLUDED == TRUE ||bta_dm_cb.device_list.peer_device[i].transport != p_data->acl_change.transport #endif ) continue; if( bta_dm_cb.device_list.peer_device[i].conn_state == BTA_DM_UNPAIRING )//如果解配状态,那么开始解配相关的操作 { if (BTM_SecDeleteDevice(bta_dm_cb.device_list.peer_device[i].peer_bdaddr)){ issue_unpair_cb = TRUE; } } conn.link_down.is_removed = bta_dm_cb.device_list.peer_device[i].remove_dev_pending; for(; i<bta_dm_cb.device_list.count ; i++) { memcpy(&bta_dm_cb.device_list.peer_device[i], &bta_dm_cb.device_list.peer_device[i+1], sizeof(bta_dm_cb.device_list.peer_device[i])); } break; } if(bta_dm_cb.device_list.count) bta_dm_cb.device_list.count--; #if BLE_INCLUDED == TRUE if ((p_data->acl_change.transport == BT_TRANSPORT_LE) && (bta_dm_cb.device_list.le_count)) bta_dm_cb.device_list.le_count--; conn.link_down.link_type = p_data->acl_change.transport; #endif if(bta_dm_search_cb.wait_disc && !bdcmp(bta_dm_search_cb.peer_bdaddr, p_bda)) { bta_dm_search_cb.wait_disc = FALSE; if(bta_dm_search_cb.sdp_results) { bta_sys_stop_timer(&bta_dm_search_cb.search_timer); bta_dm_discover_next_device(); } }
if(bta_dm_cb.disabling) { if(!BTM_GetNumAclLinks()) { 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;//如果没有link,那么1s之后执行回调 /* * Start a timer to make sure that the profiles * get the disconnect event. */ bta_sys_start_timer(&bta_dm_cb.disable_timer, 0, 1000); } } if (conn.link_down.is_removed) { BTM_SecDeleteDevice(p_bda); #if (BLE_INCLUDED == TRUE && BTA_GATT_INCLUDED == TRUE) /* need to remove all pending background connection */ BTA_GATTC_CancelOpen(0, p_bda, FALSE); /* remove all cached GATT information */ BTA_GATTC_Refresh(p_bda); #endif } bdcpy(conn.link_down.bd_addr, p_bda); conn.link_down.status = (UINT8) btm_get_acl_disc_reason_code(); if( bta_dm_cb.p_sec_cback ) { bta_dm_cb.p_sec_cback(BTA_DM_LINK_DOWN_EVT, &conn);//向上层汇报状态 if( issue_unpair_cb ) bta_dm_cb.p_sec_cback(BTA_DM_DEV_UNPAIRED_EVT, &conn); } } bta_dm_adjust_roles(TRUE); }
这里需要分析的点有处:
1.bta_dm_disable_conn_down_timer_cback
2.bta_dm_cb.p_sec_cback = bte_dm_evt(BTA_DM_LINK_DOWN_EVT, &conn) 的执行流程
首先看看.bta_dm_disable_conn_down_timer_cback 的执行
/******************************************************************************* ** ** Function bta_dm_disable_conn_down_timer_cback ** ** Description Sends disable event to application ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_disable_conn_down_timer_cback (TIMER_LIST_ENT *p_tle) { UNUSED(p_tle); tBTA_SYS_HW_MSG *sys_enable_event; /* disable the power managment module */ bta_dm_disable_pm(); /* register our callback to SYS HW manager */ bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback );//注册callback /* send a message to BTA SYS */ if ((sys_enable_event = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) { sys_enable_event->hdr.event = BTA_SYS_API_DISABLE_EVT;//发送系统管理模块disable的事件 sys_enable_event->hw_module = BTA_SYS_HW_BLUETOOTH; bta_sys_sendmsg(sys_enable_event); } bta_dm_cb.disabling = FALSE; }
看看这个 disable event 在 系统管理模块中是怎么处理的:
BOOLEAN bta_sys_sm_execute(BT_HDR *p_msg) { BOOLEAN freebuf = TRUE; tBTA_SYS_ST_TBL state_table; UINT8 action; int i; /* look up the state table for the current state */ state_table = bta_sys_st_tbl[bta_sys_cb.state]; /* update state */ bta_sys_cb.state = state_table[p_msg->event & 0x00ff][BTA_SYS_NEXT_STATE]; /* execute action functions */ for (i = 0; i < BTA_SYS_ACTIONS; i++) { if ((action = state_table[p_msg->event & 0x00ff][i]) != BTA_SYS_IGNORE) { (*bta_sys_action[action])( (tBTA_SYS_HW_MSG*) p_msg); } else { break; } } return freebuf; }
这里发现 下一个状态还是BTA_SYS_HW_ON ,执行的动作是BTA_SYS_HW_API_DISABLE,执行的函数是bta_sys_hw_api_disable ,这里发现它的先一个状态不少stopped,说明还有事件要交互,先看disable的动作:
/******************************************************************************* ** ** Function bta_sys_hw_disable ** ** Description if no other module is using the HW, this function will call ( if defined ) a user-macro to turn off the HW ** ** ** Returns success or failure ** *******************************************************************************/ void bta_sys_hw_api_disable(tBTA_SYS_HW_MSG *p_sys_hw_msg) { /* make sure the related SW blocks were stopped */ bta_sys_disable( p_sys_hw_msg->hw_module );//再次确认已经关闭子模块 /* register which module we turn off */ bta_sys_cb.sys_hw_module_active &= ~((UINT32)1 << p_sys_hw_msg->hw_module );//清除标志 /* if there are still some SW modules using the HW, just provide an answer to the calling */ if( bta_sys_cb.sys_hw_module_active != 0 ) { /* if there are still some SW modules using the HW, directly notify the caller */ if( bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]!= NULL ) bta_sys_cb.sys_hw_cback[p_sys_hw_msg->hw_module ]( BTA_SYS_HW_OFF_EVT ); } else { /* manually update the state of our system */ bta_sys_cb.state = BTA_SYS_HW_STOPPING;//设置状态 tBTA_SYS_HW_MSG *p_msg; if ((p_msg = (tBTA_SYS_HW_MSG *) GKI_getbuf(sizeof(tBTA_SYS_HW_MSG))) != NULL) { p_msg->hdr.event = BTA_SYS_EVT_DISABLED_EVT;//继续发送disabled的消息 p_msg->hw_module = p_sys_hw_msg->hw_module; bta_sys_sendmsg(p_msg); } } }
当前的状态已经是 bta_sys_cb.state = BTA_SYS_HW_STOPPING;,其状态转换图也不同:
const UINT8 bta_sys_hw_stopping[][BTA_SYS_NUM_COLS] = { /* Event Action 1 Action 2 Next State */ /* API_ENABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STARTING}, /* change state, and wait for completion event to enable */ /* EVT_ENABLED */ {BTA_SYS_HW_EVT_ENABLED, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: finish the enable before disabling */ /* STACK_ENABLED */ {BTA_SYS_HW_EVT_STACK_ENABLED, BTA_SYS_HW_API_DISABLE, BTA_SYS_HW_STOPPING}, /* successive enable/disable: notify, then stop */ /* API_DISABLE */ {BTA_SYS_IGNORE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING}, /* wait for completion event */ /* EVT_DISABLED */ {BTA_SYS_HW_EVT_DISABLED, BTA_SYS_IGNORE, BTA_SYS_HW_OFF}, /* EVT_ERROR */ {BTA_SYS_HW_API_DISABLE, BTA_SYS_IGNORE, BTA_SYS_HW_STOPPING} };
可知下一个状态是BTA_SYS_HW_OFF,另外执行的action是BTA_SYS_HW_EVT_DISABLED,执行的函数 是
void bta_sys_hw_evt_disabled(tBTA_SYS_HW_MSG *p_sys_hw_msg) { UINT8 hw_module_index; for (hw_module_index = 0; hw_module_index < BTA_SYS_MAX_HW_MODULES; hw_module_index++) { if (bta_sys_cb.sys_hw_cback[hw_module_index] != NULL) bta_sys_cb.sys_hw_cback[hw_module_index] (BTA_SYS_HW_OFF_EVT); } }
这里执行之前注册到HW manager的函数 bta_sys_hw_register( BTA_SYS_HW_BLUETOOTH, bta_dm_sys_hw_cback ),看其实现:
/******************************************************************************* ** ** Function bta_dm_sys_hw_cback ** ** Description callback register to SYS to get HW status updates ** ** ** Returns void ** *******************************************************************************/ static void bta_dm_sys_hw_cback( tBTA_SYS_HW_EVT status ) { DEV_CLASS dev_class; tBTA_DM_SEC_CBACK *temp_cback; #if BLE_INCLUDED == TRUE UINT8 key_mask = 0; BT_OCTET16 er; tBTA_BLE_LOCAL_ID_KEYS id_key; #endif ... if( status == BTA_SYS_HW_OFF_EVT ) { if( bta_dm_cb.p_sec_cback != NULL ) bta_dm_cb.p_sec_cback(BTA_DM_DISABLE_EVT, NULL);//继续向上层汇报事件 /* reinitialize the control block */ memset(&bta_dm_cb, 0, sizeof(bta_dm_cb)); /* unregister from SYS */ bta_sys_hw_unregister( BTA_SYS_HW_BLUETOOTH ); /* notify BTA DM is now unactive */ bta_dm_cb.is_bta_dm_active = FALSE; } ...
这边主要分析bta_dm_cb.p_sec_cback 的两个事件 BTA_DM_LINK_DOWN_EVT和BTA_DM_DISABLE_EVT
static void btif_dm_upstreams_evt(UINT16 event, char* p_param) { tBTA_DM_SEC *p_data = (tBTA_DM_SEC*)p_param; tBTA_SERVICE_MASK service_mask; uint32_t i; bt_bdaddr_t bd_addr; switch (event) { ... case BTA_DM_DISABLE_EVT: /* for each of the enabled services in the mask, trigger the profile * disable */ service_mask = btif_get_enabled_services_mask(); for (i=0; i <= BTA_MAX_SERVICE_ID; i++) { if (service_mask & (tBTA_SERVICE_MASK)(BTA_SERVICE_ID_TO_SERVICE_MASK(i))) { btif_in_execute_service_request(i, FALSE);//关闭没有关闭的服务 } } btif_disable_bluetooth_evt();//继续向上汇报状态 break; ... case BTA_DM_BUSY_LEVEL_EVT: { if (p_data->busy_level.level_flags & BTM_BL_INQUIRY_PAGING_MASK) { if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_STARTED) { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STARTED); btif_dm_inquiry_in_progress = TRUE; } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_CANCELLED) { HAL_CBACK(bt_hal_cbacks, discovery_state_changed_cb, BT_DISCOVERY_STOPPED); btif_dm_inquiry_in_progress = FALSE; } else if (p_data->busy_level.level_flags == BTM_BL_INQUIRY_COMPLETE) { btif_dm_inquiry_in_progress = FALSE; } } }break; ... case BTA_DM_LINK_DOWN_EVT: bdcpy(bd_addr.address, p_data->link_down.bd_addr); btm_set_bond_type_dev(p_data->link_down.bd_addr, BOND_TYPE_UNKNOWN); BTIF_TRACE_DEBUG("BTA_DM_LINK_DOWN_EVT. Sending BT_ACL_STATE_DISCONNECTED"); HAL_CBACK(bt_hal_cbacks, acl_state_changed_cb, BT_STATUS_SUCCESS, &bd_addr, BT_ACL_STATE_DISCONNECTED); break; ...
这里简单分析下btif_disable_bluetooth_evt:
/******************************************************************************* ** ** Function btif_disable_bluetooth_evt ** ** Description Event notifying BT disable is now complete. ** Terminates main stack tasks and notifies HAL ** user with updated BT state. ** ** Returns void ** *******************************************************************************/ void btif_disable_bluetooth_evt(void) { #if (defined(HCILP_INCLUDED) && HCILP_INCLUDED == TRUE) bte_main_enable_lpm(FALSE); #endif #if (BLE_INCLUDED == TRUE) BTA_VendorCleanup(); #endif bte_main_disable();//关闭hci模块和btsnoop模块,关闭BTU, /* callback to HAL */ future_ready(stack_manager_get_hack_future(), FUTURE_SUCCESS);//发送信号量 }
还记得在文章的开头event_shut_down_stack 里面会等待一个信号量,这里,这个信号量终于发出来了,那么event_shut_down_stack这个函数也得以继续执行:
static void event_shut_down_stack(UNUSED_ATTR void *context) { ... hack_future = future_new(); stack_is_running = false; btif_disable_bluetooth();//文章从这里分析 module_shut_down(get_module(BTIF_CONFIG_MODULE)); future_await(hack_future);//获得信号量继续执行 module_shut_down(get_module(CONTROLLER_MODULE)); // Doesn't do any work, just puts it in a restartable state btif_thread_post(event_signal_stack_down, NULL); }
static void event_signal_stack_down(UNUSED_ATTR void *context) { HAL_CBACK(bt_hal_cbacks, adapter_state_changed_cb, BT_STATE_OFF); }
最后的这个函数 就是往上层汇报BT_STATE_OFF的状态的。
关于蓝牙disable的流程就先分析到这里。
最后说一点,蓝牙关闭的流程还包括各个profile的关闭,这里只是介绍了协议栈对于各个模块的关闭流程。