蓝牙关闭的流程比打开流程要简单,主要就是一些profile的断连以及协议栈相关结构的释放。

这里简单说一下其流程,就直接从协议栈的disable的接口说起了。

static int disable(void) {if (!interface_ready())//检查hal层的callbackreturn 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时间,设置为0L2CA_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 == TRUEBTM_BleClearBgConnDev();//清除whitelist
#endifif(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);
#elsebta_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 == TRUEtBTA_HH_STATE   in_state ;UINT16          debug_event = event;
#endifmemset(&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 没有activeelse{/* 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_DEBUGAPPL_TRACE_DEBUG("bta_hh_cback::HID_event [%s]", bta_hh_hid_event_name(event));
#endifswitch (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);
#elsebta_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 blockmemset(&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;//不是newswitch(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 == TRUEp_msg->transport = p_data->conn.transport;p_msg->handle = p_data->conn.handle;
#endifbreak;case BTM_BL_DISCN_EVT:bdcpy(p_msg->bd_addr, p_data->discn.p_bda);
#if BLE_INCLUDED == TRUEp_msg->transport = p_data->discn.transport;p_msg->handle = p_data->discn.handle;
#endifbreak;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 == TRUEif ((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;
#endifif(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 == TRUEUINT8                   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();
#endifbte_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的关闭,这里只是介绍了协议栈对于各个模块的关闭流程。

转载于:https://www.cnblogs.com/libs-liu/p/9314267.html

蓝牙disable流程简述相关推荐

  1. SAP MM UB类型的退货STO流程简述

    SAP MM UB类型的退货STO流程简述 SAP系统中,UB类型的采购订单(STO)用于公司内2个工厂之间的货物调拨场景.对于这个场景里的退货业务,UB类型的STO也是可以支持的.本文就是简述一下这 ...

  2. 常见算子使用_spark快速入门(二)spark粗略流程简述及常见名词解释

    大家元旦快乐,牛年发发发~~牛气冲天o(* ̄︶ ̄*)o spark粗略流程简述 (1)有算子触发Action,Driver端和hdfs的namenode进行通信,询问元数据信息.根据元数据信息 及相应 ...

  3. 蓝牙配对码配置错误_安卓系统蓝牙配对流程分析

    安卓系统蓝牙配对流程分析 配对流程基本上始于首次连接一个蓝牙设备的过程中,本端的搜索流程结束获取到该设备的BluetoothDevice信息,就可以开启配对流程. 配对,顾名思义就是将两个设备通过相关 ...

  4. 安卓application_安卓系统蓝牙配对流程分析

    安卓系统蓝牙配对流程分析 配对流程基本上始于首次连接一个蓝牙设备的过程中,本端的搜索流程结束获取到该设备的BluetoothDevice信息,就可以开启配对流程. 配对,顾名思义就是将两个设备通过相关 ...

  5. Android wifi carlife,carlife可以无线连接吗?carlife蓝牙连接流程

    Carlife可以无线连接.目前无线连接支持iPhone手机使用,而安卓手机只有少部分可以使用.连接方法如下: 1.打开手机设置启用蜂窝移动数据,再打开手机WiFi,并且开一个无线热点. 2.找到车机 ...

  6. Pacbio测序原理以及SMRT bell文库构建流程简述

    ​ 2018年发的老文章了,文章不错,所以决定再捞一下.文中有3段视频,如需观看请大家移步"基因Share"观看. Pacbio测序原理及SMRT bell文库构建流程简述(二)​ ...

  7. PX4源码分析2:飞控系统控制流程简述

    飞控系统控制流程简述 Created with Raphaël 2.2.0采集遥控指令,计算期望位置采集GPS数据,计算此刻实际位置计算位置差,经PID计算并输出期望角度采集IMU数据,计算此刻实际角 ...

  8. 微信小程序使用蓝牙连接设备流程

    微信小程序使用蓝牙连接设备流程 小程序使用蓝牙连接设备介绍 使用到的api 流程: 初始化蓝牙模块 wx.openBluetoothAdapter wx.openBluetoothAdapter({ ...

  9. HDFS 读写流程简述

    参考:https://blog.csdn.net/litianxiang_kaola/article/details/70984777 https://blog.csdn.net/zhanglh046 ...

最新文章

  1. strcpy与strncpy的区别
  2. (三)Amazon Lightsail 部署LAMP应用程序之连接到Lightsail数据库
  3. 机器学习:多分类的logistic回归
  4. selinux 的管理
  5. Oracle 数据类型 选择自 tjandy 的 Blog
  6. [转载]MySQL事务隔离级别
  7. 【转】 C#泛型集合—Dictionary使用技巧
  8. CMM,CMMI 软件全面质量管理的思想体系
  9. 上位机和下位机的区别是什么
  10. 陈强老师公开课笔记1——如何区别中介效应、调节效应与交互效应?
  11. 一些特殊字符(如:←↑→↓等箭头符号)的Unicode码值
  12. 守望先锋地图英文和英雄英文
  13. 软件开发工具的使用与开发
  14. GGGGGGithub
  15. kerberos 之TGS_REQ、TGS_REP
  16. Velocity模板语言(VTL):说明
  17. 启用计算机无线网络连接,无线网络连接未启用DHCP是怎么回事?如何解决?
  18. An unknown server-side error occurred while processing the command. Original error: Error executing
  19. Windows平台下搭建Qt编译环境(VS2008)
  20. python语音处理_python处理语音

热门文章

  1. libc、glibc和glib的关系
  2. mysql入门_高洛峰_简介_linux安装_远程连接配置_sql语句初始
  3. miss工作室官宣加盟新公司是真的吗
  4. android部分代码片段(例:判断设备为手机,获取mac地址,软键盘,唤醒屏幕等)
  5. 新春送祝福,直接发红包。现金红包等你来拿~
  6. 计算机概论易错题总结:概念类
  7. ESP8266/ESP32/nodeMcu/wemos D1 MINI开发板用TFT_eSPI库驱动ST7789(240*240)TFT显示屏
  8. 对接支付通道如何收费?支付接口收费标准
  9. Markdown 小技巧之图片左对齐
  10. 在线教育项目【老师服务】