蓝牙关闭的流程比打开流程要简单,主要就是一些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, , BT_TRANSPORT_BR_EDR);//设置idletimeout时间,设置为0
L2CA_SetIdleTimeoutByBdAddr((UINT8 *)BT_BD_ANY, , BT_TRANSPORT_LE); /* disable all active subsystems */
bta_sys_disable(BTA_SYS_HW_BLUETOOTH);//关闭蓝牙相关的各个子模块。这里涉及到短线等操作 BTM_SetDiscoverability(BTM_NON_DISCOVERABLE, , );//不可发现
BTM_SetConnectability(BTM_NON_CONNECTABLE, , );//不可连接 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()==)//如果已经没有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, , 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 = ;
bta_sys_start_timer(&bta_dm_cb.disable_timer, , );
} }

上面的函数的重点是蓝牙关闭各个子模块的函数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 = {};
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 = ;
int bta_id_max = ;
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 = ; 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 = ;
#if BTA_HH_DEBUG == TRUE
tBTA_HH_STATE in_state ;
UINT16 debug_event = event;
#endif memset(&cback_data, , 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 - ];
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+;
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+;
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 != ) || (p_hcon->intr_cid != ))
{
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, , 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", );
/* 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, , 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 = ; 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 == )
{
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, , 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, , 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 ();
} /* Verify PSM is valid */
if (L2C_INVALID_PSM(psm))
{
L2CAP_TRACE_ERROR ("L2CAP - invalid PSM value, PSM: 0x%04x", psm);
return ();
} /* 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 += )
{
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 ();
}
} 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 = ;
else
{
p_hcon->intr_cid = ;
if (p_hcon->ctrl_cid)
{
L2CA_DisconnectReq (p_hcon->ctrl_cid);//控制通道没有断开,继续断开
}
} if ((p_hcon->ctrl_cid == ) && (p_hcon->intr_cid == ))
{
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 = ; #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 - ];//找到状态转换表
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, };
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 = ; /* if no connection is active and HH disable is signaled, disable service */
if (bta_hh_cb.cnt_num == && 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 = ; 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 = ;
/* 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 >= ) {
bta_hh_co_destroy(p_dev->fd);//销毁节点
p_dev->fd = -;
}
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, , sizeof(btif_hh_cb));
for (i = ; 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, , sizeof(tBTA_DM_SEC));
...
if(is_new)
{
...
} else {
for(i=; 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+], 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, , );
}
}
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(, 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 = ; 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) << 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 != )
{
/* 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 = ; 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 = ;
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, , 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=; 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的关闭,这里只是介绍了协议栈对于各个模块的关闭流程。

蓝牙disable流程简述的更多相关文章

  1. iOS蓝牙连接流程介绍-1

    蓝牙连接流程介绍 1.1-程序员找女朋友流程介绍 0.程序员找女朋友参与者 1.你 2.受害者(女性同胞)  (1)她的性格1 性格的特点 (2)她的性格2  分析性格的特点 1.寻找女性 寻尽身边一 ...

  2. 蓝牙简单配对(Simple Pairing)协议及代码流程简述

    kangear注: 文章转自:http://blog.csdn.net/myxmu/article/details/12217135 原文把图给搞丢了.可是文章太好了,这个时候我就发挥多年的Googl ...

  3. Android 8 设置蓝牙名称 流程

    记录android 8设置蓝牙名称的流程. packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDeviceRenam ...

  4. 蓝牙inquiry流程之命令下发

    Android 上面的蓝牙inquiry 是在设置界面,打开蓝牙就会自动搜索周边的蓝牙设备,其最终调用到协议栈的start_discovery接口,此篇文章分析该接口的调用流程以及与controlle ...

  5. Android 8 蓝牙 A2DP流程

    记录一下蓝牙A2DP的流程 packages\apps\Settings\src\com\android\settings\bluetooth\BluetoothPairingDetail.java ...

  6. Android 8 蓝牙 扫描流程

    记录android 8 蓝牙扫描设备的流程 src/com/android/settings/bluetooth/BluetoothSettings.java @Override protected ...

  7. Ajax的工作流程简述

    提到Ajax相信我们都不会陌生,不管你是前端开发还是后台数据处理的程序员,ajax的作用就像现在生活中的手机一样,无论是作用还是流程都差不多,这里我们要进行ajax操作后台数据并显示在页面上的话,首先 ...

  8. [Android] hid设备按键流程简述

    hexdump /dev/hidraw0就能看到usbhid设备传输过来的裸流 如:按下Input键 003ae60 0000 0096 8000 006b 0000 0000 0000 0000 * ...

  9. Kafka 0.10 KafkaConsumer流程简述

    ConsumerConfig.scala 储存Consumer的配置 按照我的理解,0.10的Kafka没有专门的SimpleConsumer,仍然是沿用0.8版本的. 1.从poll开始 消费的规则 ...

随机推荐

  1. 用sparkR, 分析上亿条订单数据的脚本。

    上周我们这个10人的小团队开发的推荐拉新系统, 日拉新人数已接近4万人.过去几个月这个系统从无到有, 拉新从日增几千稳步增长到日增几万, 同事们几个月来,每天工作13个小时以上,洗澡时间都没有, 有时 ...

  2. pytest进阶

    参考文章 使用 pytest pytest 这个 库是一个第三方库,严格来说,它的设计思路不属于 xUnit 系列.但它使用起来比较方便,同时他又兼容 unittest 的用例:用 unittest ...

  3. LintCode题解之Search Range in Binary Search Tree

    1.题目描述 2.问题分析 首先将二叉查找树使用中序遍历的方式将元素放入一个vector,然后在vector 中截取符合条件的数字. 3.代码 /** * Definition of TreeNode ...

  4. EFCore中SQLSERVER 2008 的分页问题

    自SQLSERVER 2012起新增了 Offset Fetch 语法,因此EFCore默认是以此语法生成相应的分页语句的. 如果我们的目标数据库低于 2012,那么EFCore默认生成的语句在执行的 ...

  5. leveldb源码分析--SSTable之block

    在SSTable中主要存储数据的地方是data block,block_builder就是这个专门进行block的组织的地方,我们来详细看看其中的内容,其主要有Add,Finish和CurrentSi ...

  6. 10分钟让你明白MySQL是如何利用索引的

    一.前言 在MySQL中进行SQL优化的时候,经常会在一些情况下,对MySQL能否利用索引有一些迷惑. 譬如: MySQL 在遇到范围查询条件的时候就停止匹配了,那么到底是哪些范围条件? MySQL ...

  7. CISCO ASA 5505 经典配置案例

    nterface Vlan2 nameif outside  ----------------------------------------对端口命名外端口  security-level 0 -- ...

  8. Linux centos6.5 系统语言改成中文简体

    有时候上传的文件在linux上ls显示的时乱码,原因可能是系统语言编码问题,以Linux centos6.5为例,解决方法如下: 1.在root(皇帝)权限下更改: 查看当前所有语言环境:locale ...

  9. 转战JS(1) 初探与变量类型、运算符、常用函数与转换

    转战JS(1)初探与变量类型.运算符.常用函数与转换 做为一名.NET后台开发人员,正考滤向Web前端开发转型,之前也写过一代前端代码,可是当再回头看JS,并有转向它的意愿的时候,突然发现:原来JS不 ...

  10. 2017 SDN第一次作业

    (1)我会选择的,因为网络现在越来越重要,各行各业都离不开网络,这个方向可以适合各种岗位,感觉比较容易就业.但选这个课是为了多学一点东西,没想太多,嘎嘎嘎. (2)SDNLAB,是一个SDN的大的中文 ...