蓝牙扫描代码流程

基于Android 14

之气整理蓝牙扫描的时候发现了些问题,整理出来交流下,文中会有自己的疑问,如果有知道可以私信或者留言交流,感谢。
总体来说代码部分比较简单,主要是gd模式的疑问。

FW部分

  1. 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;
}
  1. 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部分

  1. 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;
}
  1. 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;
}
  1. 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是回调,执行完上报结果

  1. 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的时候设置的.

  1. 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

  1. 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;
  }
}
  1. 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扫描部分

  1. 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扫描部分

  1. 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);
}
  1. 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了?

  1. 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这点不同了。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值