基于Android 14
之气整理蓝牙扫描的时候发现了些问题,整理出来交流下,文中会有自己的疑问,如果有知道可以私信或者留言交流,感谢。
总体来说代码部分比较简单,主要是gd模式的疑问。
FW部分
- startDiscovery
首先从framework提供的接口开始
packages/modules/Bluetooth/framework/java/android/bluetooth/BluetoothAdapter.java
public boolean startDiscovery() {
if (getState() != STATE_ON) {
return false;
}
mServiceLock.readLock().lock();
try {
if (mService != null) {
final SynchronousResultReceiver<Boolean> recv = SynchronousResultReceiver.get(); //是不是bind都要这样
mService.startDiscovery(mAttributionSource, recv);
return recv.awaitResultNoInterrupt(getSyncTimeout()).getValue(false);
}
} catch (RemoteException | TimeoutException e) {
Log.e(TAG, e.toString() + "\n" + Log.getStackTraceString(new Throwable()));
} finally {
mServiceLock.readLock().unlock();
}
return false;
}
- startDiscovery
AdapterService里的startDiscovery
packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/AdapterService.java
// AdapterService.AdapterServiceBinder extends IBluetooth.Stub
public void startDiscovery(AttributionSource source, SynchronousResultReceiver receiver) {
try {
receiver.send(startDiscovery(source));
} catch (RuntimeException e) {
receiver.propagateException(e);
}
} // 以前没有这个的,这个是为了同步接收结果吗
private boolean startDiscovery(AttributionSource attributionSource) {
AdapterService service = getService();
if (service == null
|| !callerIsSystemOrActiveOrManagedUser(service, TAG, "startDiscovery")) {
return false; // 用户检查
}
if (!Utils.checkScanPermissionForDataDelivery(
service, attributionSource, "Starting discovery.")) {
return false;
}
return service.startDiscovery(attributionSource);
}
// AdapterService.startDiscovery
boolean startDiscovery(AttributionSource attributionSource) {
UserHandle callingUser = Binder.getCallingUserHandle();
debugLog("startDiscovery");
String callingPackage = attributionSource.getPackageName();
mAppOps.checkPackage(Binder.getCallingUid(), callingPackage);
boolean isQApp = Utils.checkCallerTargetSdk(this, callingPackage, Build.VERSION_CODES.Q);
boolean hasDisavowedLocation =
Utils.hasDisavowedLocationForScan(this, attributionSource, mTestModeEnabled);
String permission = null;
if (Utils.checkCallerHasNetworkSettingsPermission(this)) {
permission = android.Manifest.permission.NETWORK_SETTINGS;
} else if (Utils.checkCallerHasNetworkSetupWizardPermission(this)) {
permission = android.Manifest.permission.NETWORK_SETUP_WIZARD;
} else if (!hasDisavowedLocation) {
if (isQApp) {
if (!Utils.checkCallerHasFineLocation(this, attributionSource, callingUser)) {
return false;
}
permission = android.Manifest.permission.ACCESS_FINE_LOCATION;
} else {
if (!Utils.checkCallerHasCoarseLocation(this, attributionSource, callingUser)) {
return false;
}
permission = android.Manifest.permission.ACCESS_COARSE_LOCATION;
}
}
synchronized (mDiscoveringPackages) {
mDiscoveringPackages.add(
new DiscoveringPackage(callingPackage, permission, hasDisavowedLocation));
}
return startDiscoveryNative();
}
内容基本上都是权限检查,安全性检查;
Stack部分
- startDiscoveryNative
packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp
static jboolean startDiscoveryNative(JNIEnv* env, jobject obj) {
ALOGV("%s", __func__);
if (!sBluetoothInterface) return JNI_FALSE; // 初始化赋值不为空
int ret = sBluetoothInterface->start_discovery();
return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}
- start_discovery
packages/modules/Bluetooth/system/btif/src/bluetooth.cc
static int start_discovery(void) {
if (!interface_ready()) return BT_STATUS_NOT_READY;
do_in_main_thread(FROM_HERE, base::BindOnce(btif_dm_start_discovery));
return BT_STATUS_SUCCESS;
}
- btif_dm_start_discovery
packages/modules/Bluetooth/system/btif/src/btif_dm.cc
void btif_dm_start_discovery(void) {
BTIF_TRACE_EVENT("%s", __func__);
BTM_LogHistory(
kBtmLogTag, RawAddress::kEmpty, "Device discovery",
base::StringPrintf("is_request_queued:%c",
bta_dm_is_search_request_queued() ? 'T' : 'F'));
/* no race here because we're guaranteed to be in the main thread */
if (bta_dm_is_search_request_queued()) {
LOG_INFO("%s skipping start discovery because a request is queued",
__func__);
return;
}
/* Will be enabled to true once inquiry busy level has been received */
btif_dm_inquiry_in_progress = false;
/* find nearby devices */
BTA_DmSearch(btif_dm_search_devices_evt);
}
btif_dm_search_devices_evt
是回调,执行完上报结果
- BTA_DmSearch
packages/modules/Bluetooth/system/bta/dm/bta_dm_api.cc
void BTA_DmSearch(tBTA_DM_SEARCH_CBACK* p_cback) {
tBTA_DM_API_SEARCH* p_msg =
(tBTA_DM_API_SEARCH*)osi_calloc(sizeof(tBTA_DM_API_SEARCH));
p_msg->hdr.event = BTA_DM_API_SEARCH_EVT;
p_msg->p_cback = p_cback;
bta_sys_sendmsg(p_msg);
}
要到BTA中处理,bta_dm_search状态机在初始化BTA_dm_init
的时候设置的.
- bta_dm_search_sm_execute
packages/modules/Bluetooth/system/bta/dm/bta_dm_main.cc
bool bta_dm_search_sm_execute(BT_HDR_RIGID* p_msg) {
const tBTA_DM_EVT event = static_cast<tBTA_DM_EVT>(p_msg->event);
...
switch (bta_dm_search_get_state()) {
case BTA_DM_SEARCH_IDLE:
switch (p_msg->event) {
case BTA_DM_API_SEARCH_EVT:
bta_dm_search_set_state(BTA_DM_SEARCH_ACTIVE);
bta_dm_search_start(message);
break;
初始状态BTA_DM_SEARCH_IDLE
,进行下一步前将dm状态设置为BTA_DM_SEARCH_ACTIVE
。
- bta_dm_search_start
packages/modules/Bluetooth/system/bta/dm/bta_dm_act.cc
void bta_dm_search_start(tBTA_DM_MSG* p_data) {
bta_dm_gattc_register();
APPL_TRACE_DEBUG("%s avoid_scatter=%d", __func__,
p_bta_dm_cfg->avoid_scatter);
BTM_ClearInqDb(nullptr);
/* save search params */
bta_dm_search_cb.p_search_cback = p_data->search.p_cback;
bta_dm_search_cb.services = p_data->search.services;
const tBTM_STATUS btm_status =
BTM_StartInquiry(bta_dm_inq_results_cb, bta_dm_inq_cmpl_cb); // 两个回调,一个是扫描结果,一个是扫描动作完成
switch (btm_status) { // 执行结果判断
case BTM_CMD_STARTED:
// Completion callback will be executed when controller inquiry
// timer pops or is cancelled by the user
break;
default:
LOG_WARN("Unable to start device discovery search btm_status:%s",
btm_status_text(btm_status).c_str());
// Not started so completion callback is executed now
bta_dm_inq_cmpl(0);
break;
}
}
- BTM_StartInquiry
packages/modules/Bluetooth/system/stack/btm/btm_inq.cc
tBTM_STATUS BTM_StartInquiry(tBTM_INQ_RESULTS_CB* p_results_cb,
tBTM_CMPL_CB* p_cmpl_cb) {
/* Only one active inquiry is allowed in this implementation.
Also do not allow an inquiry if the inquiry filter is being updated */
if (btm_cb.btm_inq_vars.inq_active) {
LOG_WARN(
"Active device discovery already in progress inq_active:0x%02x"
" state:%hhu counter:%u",
btm_cb.btm_inq_vars.inq_active, btm_cb.btm_inq_vars.state,
btm_cb.btm_inq_vars.inq_counter);
btm_cb.neighbor.inquiry_history_->Push({
.status = tBTM_INQUIRY_CMPL::NOT_STARTED,
});
return BTM_BUSY;
}
/*** Make sure the device is ready ***/
if (!BTM_IsDeviceUp()) {
LOG(ERROR) << __func__ << ": adapter is not up";
btm_cb.neighbor.inquiry_history_->Push({
.status = tBTM_INQUIRY_CMPL::NOT_STARTED,
});
return BTM_WRONG_MODE;
}
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Classic inquiry started",
base::StringPrintf(
"%s", (btm_cb.neighbor.classic_inquiry.start_time_ms == 0)
? ""
: "ERROR Already in progress"));
/* Save the inquiry parameters to be used upon the completion of
* setting/clearing the inquiry filter */
btm_cb.btm_inq_vars.inqparms = {
// tBTM_INQ_PARMS
.mode = BTM_GENERAL_INQUIRY | BTM_BLE_GENERAL_INQUIRY, //模式给到了br和ble扫描两个
.duration = BTIF_DM_DEFAULT_INQ_MAX_DURATION,
};
/* Initialize the inquiry variables */
btm_cb.btm_inq_vars.state = BTM_INQ_ACTIVE_STATE;
btm_cb.btm_inq_vars.p_inq_cmpl_cb = p_cmpl_cb;
btm_cb.btm_inq_vars.p_inq_results_cb = p_results_cb;
btm_cb.btm_inq_vars.inq_cmpl_info = {}; /* Clear the results counter */
btm_cb.btm_inq_vars.inq_active = btm_cb.btm_inq_vars.inqparms.mode;
btm_cb.neighbor.classic_inquiry = {
.start_time_ms = timestamper_in_milliseconds.GetTimestamp(),
.results = 0,
};
LOG_DEBUG("Starting device discovery inq_active:0x%02x",
btm_cb.btm_inq_vars.inq_active);
// Also do BLE scanning here if we aren't limiting discovery to classic only.
// This path does not play nicely with GD BLE scanning and may cause issues
// with other scanners.
if (!bluetooth::shim::is_classic_discovery_only_enabled()) {
if (controller_get_interface()->supports_ble()) {
btm_ble_start_inquiry(btm_cb.btm_inq_vars.inqparms.duration); //开启ble的扫描了,搜的其他文章全部是从这里往下走的
} else {
LOG_WARN("Trying to do LE scan on a non-LE adapter");
btm_cb.btm_inq_vars.inqparms.mode &= ~BTM_BLE_INQUIRY_MASK;
}
}
btm_acl_update_inquiry_status(BTM_INQUIRY_STARTED);
if (btm_cb.btm_inq_vars.inq_active & BTM_SSP_INQUIRY_ACTIVE) {
LOG_INFO("Not starting inquiry as SSP is in progress");
btm_process_inq_complete(HCI_ERR_MAX_NUM_OF_CONNECTIONS,
BTM_GENERAL_INQUIRY);
return BTM_CMD_STARTED;
}
btm_clr_inq_result_flt(); //清空地址数据库,便于后续的蓝牙地址进行匹配
btm_init_inq_result_flt(); //初始化地址数据库,便于后续的蓝牙地址进行匹配
bluetooth::legacy::hci::GetInterface().StartInquiry(
general_inq_lap, btm_cb.btm_inq_vars.inqparms.duration, 0);
// If we are only doing classic discovery, we should also set a timeout for
// the inquiry if a duration is set.
if (bluetooth::shim::is_classic_discovery_only_enabled() &&
btm_cb.btm_inq_vars.inqparms.duration != 0) {
/* start inquiry timer */
uint64_t duration_ms = btm_cb.btm_inq_vars.inqparms.duration * 1280;
alarm_set_on_mloop(btm_cb.btm_inq_vars.classic_inquiry_timer, duration_ms,
btm_classic_inquiry_timeout, NULL);
}
return BTM_CMD_STARTED;
}
上面总体来说都比较简单,一条线调用下来。但是在这里开始有两个问题需要解答:
问题一:bluetooth::shim::is_classic_discovery_only_enabled()
用到的是传说中的rust吗,只在init_flags.rs找到,实现在哪里呢?按照google提供的说明也没到实现呀。
问题二: controller_get_interface()->supports_ble()
实现又在哪里?只在controller.cc中找到MAP_TO_GD(supports_ble, SupportsBle)
.
ble扫描部分
- btm_ble_start_inquiry
packages/modules/Bluetooth/system/stack/btm/btm_ble_gap.cc
tBTM_STATUS btm_ble_start_inquiry(uint8_t duration) {
tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
BTM_TRACE_DEBUG("btm_ble_start_inquiry: inq_active = 0x%02x",
btm_cb.btm_inq_vars.inq_active);
/* if selective connection is active, or inquiry is already active, reject it
*/
if (p_ble_cb->is_ble_inquiry_active()) {
BTM_TRACE_ERROR("LE Inquiry is active, can not start inquiry");
return (BTM_BUSY);
}
/* Cleanup anything remaining on index 0 */
BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_DELETE,
static_cast<tBTM_BLE_PF_FILT_INDEX>(0), nullptr,
base::Bind(btm_ble_scan_filt_param_cfg_evt));
auto adv_filt_param = std::make_unique<btgatt_filt_param_setup_t>();
/* Add an allow-all filter on index 0*/
adv_filt_param->dely_mode = IMMEDIATE_DELY_MODE; //设置过滤参数
adv_filt_param->feat_seln = ALLOW_ALL_FILTER;
adv_filt_param->filt_logic_type = BTA_DM_BLE_PF_FILT_LOGIC_OR;
adv_filt_param->list_logic_type = BTA_DM_BLE_PF_LIST_LOGIC_OR;
adv_filt_param->rssi_low_thres = LOWEST_RSSI_VALUE;
adv_filt_param->rssi_high_thres = LOWEST_RSSI_VALUE;
BTM_BleAdvFilterParamSetup(BTM_BLE_SCAN_COND_ADD, static_cast<tBTM_BLE_PF_FILT_INDEX>(0),
std::move(adv_filt_param), base::Bind(btm_ble_scan_filt_param_cfg_evt));
uint16_t scan_interval = osi_property_get_int32(kPropertyInquiryScanInterval,
BTM_BLE_LOW_LATENCY_SCAN_INT);
uint16_t scan_window = osi_property_get_int32(kPropertyInquiryScanWindow,
BTM_BLE_LOW_LATENCY_SCAN_WIN);
if (!p_ble_cb->is_ble_scan_active()) { //再一次判断是否scan进行中
cache.ClearAll();
btm_send_hci_set_scan_params( // 对应HCI_LE_Set_Scan_Parameters
BTM_BLE_SCAN_MODE_ACTI, scan_interval, scan_window, // 通过设置interval和scan window可以控制扫描强度,来加速扫描
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, SP_ADV_ALL);
p_ble_cb->inq_var.scan_type = BTM_BLE_SCAN_MODE_ACTI;
btm_ble_start_scan(); //没有开启冉后
} else if ((p_ble_cb->inq_var.scan_interval != scan_interval) ||
(p_ble_cb->inq_var.scan_window != scan_window)) {
BTM_TRACE_DEBUG("%s, restart LE scan with low latency scan params",
__func__);
btm_send_hci_scan_enable(BTM_BLE_SCAN_DISABLE, BTM_BLE_DUPLICATE_ENABLE);
btm_send_hci_set_scan_params(
BTM_BLE_SCAN_MODE_ACTI, scan_interval, scan_window,
btm_cb.ble_ctr_cb.addr_mgnt_cb.own_addr_type, SP_ADV_ALL);
btm_send_hci_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
}
p_inq->inq_active |= BTM_BLE_GENERAL_INQUIRY;
p_ble_cb->set_ble_inquiry_active();
BTM_TRACE_DEBUG("btm_ble_start_inquiry inq_active = 0x%02x",
p_inq->inq_active);
if (duration != 0) {
/* start inquiry timer */
uint64_t duration_ms = duration * 1000;
alarm_set_on_mloop(p_ble_cb->inq_var.inquiry_timer, duration_ms,
btm_ble_inquiry_timer_timeout, NULL);
}
btm_cb.neighbor.le_inquiry = {
.start_time_ms = timestamper_in_milliseconds.GetTimestamp(),
.results = 0,
};
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le inquiry started");
return BTM_CMD_STARTED;
}
// 上面的没有scan时设置完扫描参数,然后发送scan enable
static void btm_ble_start_scan() {
btm_cb.neighbor.le_legacy_scan = {
.start_time_ms = timestamper_in_milliseconds.GetTimestamp(),
.results = 0,
};
BTM_LogHistory(kBtmLogTag, RawAddress::kEmpty, "Le legacy scan started",
"Duplicates:disable");
/* start scan, disable duplicate filtering */
btm_send_hci_scan_enable(BTM_BLE_SCAN_ENABLE, BTM_BLE_DUPLICATE_DISABLE);
if (btm_cb.ble_ctr_cb.inq_var.scan_type == BTM_BLE_SCAN_MODE_ACTI)
btm_ble_set_topology_mask(BTM_BLE_STATE_ACTIVE_SCAN_BIT);
else
btm_ble_set_topology_mask(BTM_BLE_STATE_PASSIVE_SCAN_BIT);
}
BLE scan内容还是挺多的,后续另外介绍。
常规的文档进行到这里就结束了,但是这个是ble scan,没有BR的inquiry,也就是hci中对应的HCI_Inquiry.
BR扫描部分
- StartInquiry
第九步中有bluetooth::legacy::hci::GetInterface().StartInquiry
,猜测这里会直接进行到hcicmds.cc
packages/modules/Bluetooth/system/stack/hcic/hcicmds.cc
bluetooth::legacy::hci::Interface interface_ = {
// LINK_CONTROL
.StartInquiry = btsnd_hcic_inquiry, // OCF 0x0401
.InquiryCancel = btsnd_hcic_inq_cancel, // OCF 0x0402
.Disconnect = btsnd_hcic_disconnect, // OCF 0x0406
.ChangeConnectionPacketType = btsnd_hcic_change_conn_type, // OCF 0x040F,
.StartRoleSwitch = btsnd_hcic_switch_role, // OCF 0x080B,
};
static void btsnd_hcic_inquiry(const LAP inq_lap, uint8_t duration,
uint8_t response_cnt) {
BT_HDR* p = (BT_HDR*)osi_malloc(HCI_CMD_BUF_SIZE);
uint8_t* pp = (uint8_t*)(p + 1);
p->len = HCIC_PREAMBLE_SIZE + HCIC_PARAM_SIZE_INQUIRY;
p->offset = 0;
UINT16_TO_STREAM(pp, HCI_INQUIRY);
UINT8_TO_STREAM(pp, HCIC_PARAM_SIZE_INQUIRY);
LAP_TO_STREAM(pp, inq_lap);
UINT8_TO_STREAM(pp, duration);
UINT8_TO_STREAM(pp, response_cnt);
btu_hcif_send_cmd(LOCAL_BR_EDR_CONTROLLER_ID, p);
}
- btu_hcif_send_cmd
忽然想到之前看到BTU是承接BTA和HCI的作用,这里还挺直观的。
packages/modules/Bluetooth/system/stack/hcic/hcicmds.cc
void btu_hcif_send_cmd(UNUSED_ATTR uint8_t controller_id, const BT_HDR* p_buf) {
if (!p_buf) return;
uint16_t opcode;
const uint8_t* stream = p_buf->data + p_buf->offset;
void* vsc_callback = NULL;
STREAM_TO_UINT16(opcode, stream);
// Eww...horrible hackery here
/* If command was a VSC, then extract command_complete callback */
if ((opcode & HCI_GRP_VENDOR_SPECIFIC) == HCI_GRP_VENDOR_SPECIFIC ||
(opcode == HCI_BLE_RAND) || (opcode == HCI_BLE_ENCRYPT)) {
vsc_callback = *((void**)(p_buf + 1));
}
// Skip parameter length before logging
stream++;
btu_hcif_log_command_metrics(opcode, stream,
android::bluetooth::hci::STATUS_UNKNOWN, false);
bluetooth::shim::hci_layer_get_interface()->transmit_command( // 以前还没有bluetooth::shim
p_buf, btu_hcif_command_complete_evt, btu_hcif_command_status_evt,
vsc_callback);
}
问题:印象中shim是属于Gabeldorsche模式的,不是要单独开启或者单独使用的吗,现在是只使用gd模式来发送command了?
- transmit_command
hci部分发送命令相关的了
packages/modules/Bluetooth/system/main/shim/hci_layer.cc
static void transmit_command(const BT_HDR* command,
command_complete_cb complete_callback,
command_status_cb status_callback, void* context) {
CHECK(command != nullptr);
const uint8_t* data = command->data + command->offset;
size_t len = command->len;
CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize));
// little endian command opcode
uint16_t command_op_code = (data[1] << 8 | data[0]);
// Gd stack API requires opcode specification and calculates length, so
// no need to provide opcode or length here.
data += (kCommandOpcodeSize + kCommandLengthSize);
len -= (kCommandOpcodeSize + kCommandLengthSize);
auto op_code = static_cast<const bluetooth::hci::OpCode>(command_op_code);
auto payload = MakeUniquePacket(data, len);
auto packet =
bluetooth::hci::CommandBuilder::Create(op_code, std::move(payload));
LOG_DEBUG("Sending command %s", bluetooth::hci::OpCodeText(op_code).c_str());
if (bluetooth::hci::Checker::IsCommandStatusOpcode(op_code)) {
auto command_unique = std::make_unique<OsiObject>(command);
bluetooth::shim::GetHciLayer()->EnqueueCommand(
std::move(packet), bluetooth::shim::GetGdShimHandler()->BindOnce(
OnTransmitPacketStatus, status_callback, context,
std::move(command_unique)));
} else {
bluetooth::shim::GetHciLayer()->EnqueueCommand(
std::move(packet),
bluetooth::shim::GetGdShimHandler()->BindOnce(
OnTransmitPacketCommandComplete, complete_callback, context));
osi_free(const_cast<void*>(static_cast<const void*>(command)));
}
}
整体看下来需要解释的部分都有英文的解释,也没啥好说的了,主要 bluetooth::legacy::hci::GetInterface().StartInquiry
这点不同了。