当前位置: 首页 > news >正文

长春网站快速排名提升友妙招链接怎么弄

长春网站快速排名提升,友妙招链接怎么弄,免费网站制作开发公司,网站域名所有人前面我们提到了 蓝牙协议栈中的 Properties #xff0c; 这篇文章是 他的补充。 【android bluetooth 框架分析 04】【bt-framework 层详解 6】【Properties介绍】 在 AOSP#xff08;Android Open Source Project#xff09;中#xff0c;AdapterProperties 是一个 Java…前面我们提到了 蓝牙协议栈中的 Properties 这篇文章是 他的补充。 【android bluetooth 框架分析 04】【bt-framework 层详解 6】【Properties介绍】 在 AOSPAndroid Open Source Project中AdapterProperties 是一个 Java 层类存在于 Bluetooth 栈的上层/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/AdapterProperties.java它的作用是 封装并管理本地蓝牙适配器Bluetooth Adapter的属性如名称、地址、开关状态、能见性等。 可以将 AdapterProperties 类比为一个“蓝牙身份证” 它记录了本地蓝牙设备的“姓名”Name、“身份证号”Address、“工作能力”支持的 Profile UUID等同时它也像一个“前台秘书”代表本地蓝牙向系统汇报身份变更地址、名称改了并在用户询问时给出准确答复所有的数据都是它通过“原始记录处”native 层查询来的并自己维护一份缓存副本提高效率。 1. AdapterProperties 的主要职责 职责说明属性缓存缓存从 native 层获取的适配器属性避免重复调用底层属性更新接收 native 层的事件通知如 Adapter 属性变化及时更新属性值状态同步与 AdapterService 协同工作确保 UI 层获取一致的适配器状态权限保护对外暴露属性前执行权限检查比如是否允许访问设备地址等通知分发当属性发生变化时通知系统的其他组件如广播 Intent对 native 层调用的封装如 setAdapterPropertyNative()setBufferLengthMillisNative()通过 JNI 与 native 通信 职能分类具体内容适配器信息管理地址、名称、CoD、UUID 等native 接口封装封装对 HAL 层的属性访问接口属性变更监听接收 native 层属性变更事件并更新缓存状态广播属性变化时向系统广播通知 UI 层或应用权限与安全控制某些敏感属性的访问例如地址 2. 设计目的为什么这样设计 目的说明解耦将 Adapter 属性管理从 AdapterService 中剥离逻辑更清晰状态缓存native 属性变更频繁通过缓存减少系统负载多线程安全封装属性处理逻辑有助于线程同步对外接口控制通过 AdapterProperties 控制暴露出去的属性利于权限和隐私控制JNI 管理集中化所有蓝牙本地属性相关的 native 方法都集中管理避免 JNI 调用散乱 3. 接口说明 adapter property 保管的重要信息如何在 java 层 和 native 层传递的 1. java - native api 关于 AdapterPropertyNative 有如下几个 jni 接口 android/app/src/com/android/bluetooth/btservice/AdapterService.java /*package*/native boolean setAdapterPropertyNative(int type, byte[] val);/*package*/native boolean getAdapterPropertiesNative();/*package*/native boolean getAdapterPropertyNative(int type);/*package*/native boolean setAdapterPropertyNative(int type); 上面几个接口 是 java - native 主动调用的接口 2. native - java api /packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp static void classInitNative(JNIEnv* env, jclass clazz) { ...method_adapterPropertyChangedCallback env-GetMethodID(jniCallbackClass, adapterPropertyChangedCallback, ([I[[B)V); ... }/packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/JniCallbacks.java void adapterPropertyChangedCallback(int[] types, byte[][] val) {mAdapterProperties.adapterPropertyChangedCallback(types, val);}native 侧 如果要主动将 adapter property 发送给 java 侧通过 adapterPropertyChangedCallback 回调函数来实现。 adapter_properties_callback 功能介绍 是 Android 蓝牙 JNI 层Bluetooth JNI Layer用于处理适配器Adapter属性变化回调的函数。它的功能是把底层 C/C Bluetooth stack 传来的属性变化信息封装为 Java 对象然后通过 JNI 调用 Java 层的回调函数。 定义了一个静态函数 adapter_properties_callback当蓝牙适配器本地蓝牙模块属性发生变化时被调用。 packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp /* 入参介绍status: 操作状态例如 BT_STATUS_SUCCESS 表示成功num_properties: 属性的数量properties: 指向 bt_property_t 类型数组包含多个属性数据*/static void adapter_properties_callback(bt_status_t status, int num_properties,bt_property_t* properties) {// 创建一个 CallbackEnv 对象用于获取当前线程的 JNI 环境。CallbackEnv sCallbackEnv(__func__);if (!sCallbackEnv.valid()) return; // 如果当前线程没有有效的 JNI 环境比如当前线程没有附加到 JVM直接返回。ALOGV(%s: Status is: %d, Properties: %d, __func__, status, num_properties);// 如果状态不是成功输出错误日志并返回。if (status ! BT_STATUS_SUCCESS) {ALOGE(%s: Status %d is incorrect, __func__, status);return;}/*创建一个 jbyteArray 类型的 Java 字节数组用来测试 JNI 是否可以正确分配内存但这个变量并未后续使用可能只是用于验证 JVM 能否正常分配数组。ScopedLocalRef 是一个 RAII 类型的包装器会自动释放局部引用避免 JNI 局部引用表溢出。*/ScopedLocalRefjbyteArray val(sCallbackEnv.get(),(jbyteArray)sCallbackEnv-NewByteArray(num_properties));if (!val.get()) { // 如果数组分配失败记录错误并返回。ALOGE(%s: Error allocating byteArray, __func__);return;}// 获取 val 对象的 Java 类用于后续创建对象数组虽然是 jbyteArray 类型但这里取得的是其 Class 对象。ScopedLocalRefjclass mclass(sCallbackEnv.get(),sCallbackEnv-GetObjectClass(val.get()));/* (BT) Initialize the jobjectArray and jintArray here itself and send theinitialized array pointers alone to get_properties */// 创建一个 jobjectArray 数组用来存储 Java 层属性对象。数组长度为 num_properties数组元素类型是 mclass即 byte[]。ScopedLocalRefjobjectArray props(sCallbackEnv.get(),sCallbackEnv-NewObjectArray(num_properties, mclass.get(), NULL));if (!props.get()) { // 如果对象数组分配失败记录错误并返回。ALOGE(%s: Error allocating object Array for properties, __func__);return;}// 创建一个 jintArray 数组用于存储属性类型每个 bt_property_t 对象的 type 字段。ScopedLocalRefjintArray types(sCallbackEnv.get(), (jintArray)sCallbackEnv-NewIntArray(num_properties));if (!types.get()) { // 如果类型数组分配失败记录错误并返回。ALOGE(%s: Error allocating int Array for values, __func__);return;}// 将 ScopedLocalRef 中的原生 JNI 对象提取出来准备传给 C 函数。jintArray typesPtr types.get();jobjectArray propsPtr props.get();// 调用辅助函数 get_properties将 C 层属性 bt_property_t* 转换为 Java 中的 jintArray类型数组和 jobjectArray属性值数组。如果转换失败直接返回。if (get_properties(num_properties, properties, typesPtr, propsPtr) 0) {return;}/*最后调用 Java 层的回调方法 adapterPropertyChangedCallback把构建好的属性类型数组和属性值数组传给 Java。sJniCallbacksObj 是之前保存的全局 Java 回调对象method_adapterPropertyChangedCallback 是方法 IDjmethodID对应 Java 中定义的回调函数*/sCallbackEnv-CallVoidMethod(sJniCallbacksObj,method_adapterPropertyChangedCallback,types.get(), props.get()); }该函数的流程如下 检查 JNI 环境判断 status 是否成功为属性数据创建 Java 类型的数组将底层属性转换为 Java 格式回调 Java 层传递这些属性。 4. 管理那些属性 1. AdapterProperties 和 DeviceProperties 共同使用 枚举常量说明使用范围数据类型访问权限 适用于 Adapter 和 Remote DeviceBT_PROPERTY_BDNAME设备名称Adapter: 读/写Remote Device: 只读bt_bdname_tGET / SETAdapterGETRemoteBT_PROPERTY_BDADDR设备地址Adapter Remote DeviceRawAddressGETBT_PROPERTY_UUIDS支持的服务 UUID 列表Remote Devicebluetooth::Uuid[]GETBT_PROPERTY_CLASS_OF_DEVICE类别码Remote Deviceuint32_tGETBT_PROPERTY_TYPE_OF_DEVICE设备类型BR/EDR/LERemote Devicebt_device_type_tGETBT_PROPERTY_SERVICE_RECORD服务记录Remote Devicebt_service_record_tGET 2. 仅 AdapterProperties 使用 枚举常量说明使用范围数据类型访问权限 仅适用于 Adapter本地适配器BT_PROPERTY_ADAPTER_SCAN_MODE扫描模式可发现性Adapterbt_scan_mode_tGET / SETBT_PROPERTY_ADAPTER_BONDED_DEVICES已绑定设备地址列表AdapterRawAddress[]GETBT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT可发现超时时间Adapteruint32_tGET / SETBT_PROPERTY_LOCAL_LE_FEATURES本地 LE 特性Adapterbt_local_le_features_tGETBT_PROPERTY_LOCAL_IO_CAPS本地 IO 能力经典蓝牙Adapterbt_io_cap_tGET / SETBT_PROPERTY_LOCAL_IO_CAPS_BLE本地 IO 能力BLEAdapterbt_io_cap_tGET / SETBT_PROPERTY_DYNAMIC_AUDIO_BUFFER音频缓冲设置动态Adapter自定义类型未明确 BT_PROPERTY_DYNAMIC_AUDIO_BUFFER : 应该是 a2dp source 有关 遇到具体问题在分析 不是本篇重点暂时不表。 5. 真实车机日志鉴赏 这里我分享一个 真实的车机 蓝牙启动过程中 AdapterProperties 相关的日志。我们一起来欣赏一下在启动过程中 AdapterProperties 交互。 // 蓝牙进程已经拉起 01-02 04:40:07.206918 2259 2658 I AdapterState0: OFF : entered 01-02 04:40:07.206954 2259 2658 D AdapterProperties: Setting state to OFF// 蓝牙开始启动 ble 相关的服务例如 GattService 01-02 04:40:07.348232 2259 2658 I AdapterState0: BLE_TURNING_ON : entered 01-02 04:40:07.348271 2259 2658 D AdapterProperties: Setting state to BLE_TURNING_ON 01-02 04:40:07.356894 2259 2658 I AdapterProperties: init(), maxConnectedAudioDevices, default5, propertyOverlayed1, finalValue1// native-java: 更新 ble 支持那些 feature. 01-02 04:40:08.961744 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:13 len:28 01-02 04:40:08.962018 2259 2691 D AdapterProperties: BT_PROPERTY_LOCAL_LE_FEATURES: update from BT controller mNumOfAdvertisementInstancesSupported 16 mRpaOffloadSupported true mNumOfOffloadedIrkSupported 32 mNumOfOffloadedScanFilterSupported 32 mOffloadedScanResultStorageBytes 10240 mIsActivityAndEnergyReporting true mVersSupported 96 mTotNumOfTrackableAdv 32 mIsExtendedScanSupported true mIsDebugLogSupported false mIsLe2MPhySupported true mIsLeCodedPhySupported true mIsLeExtendedAdvertisingSupported true mIsLePeriodicAdvertisingSupported true mLeMaximumAdvertisingDataLength 1650 mDynamicAudioBufferSizeSupportedCodecsGroup1 0 mDynamicAudioBufferSizeSupportedCodecsGroup2 0 mIsLePeriodicAdvertisingSyncTransferSenderSupported true mIsLeConnectedIsochronousStreamCentralSupported false mIsLeIsochronousBroadcasterSupported false mIsLePeriodicAdvertisingSyncTransferRecipientSupported true// native-java: 更新 配对设备列表 此时 len:0 没有配对设备 01-02 04:40:08.988612 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:8 len:0// native-java: 更新 mac 地址 01-02 04:40:08.988664 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:2 len:6// native-java: 更新 蓝牙名字 01-02 04:40:08.992951 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:1 len:10 01-02 04:40:09.007034 2259 2691 D AdapterProperties: Name is: xxxxx// native-java: 更新 扫描模式 01-02 04:40:09.007075 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:7 len:4 01-02 04:40:09.008607 2259 2691 D AdapterProperties: Scan Mode:20// native-java: 更新 Discoverable Timeout 01-02 04:40:09.008637 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:9 len:4 01-02 04:40:09.008671 2259 2691 D AdapterProperties: Discoverable Timeout:120// native-java: 更新 配对设备列表 01-02 04:40:09.008688 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:8 len:6 01-02 04:40:09.009478 2259 2691 D AdapterProperties: Adding bonded device:70:8F:47:91:B0:62// native-java: 更新 UUID 此时 len: 0, 没有可更新的 uuid 01-02 04:40:09.010275 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:3 len:0// 此时 ble 相关的服务完全启动 01-02 04:40:09.013738 2259 2658 I AdapterState0: BLE_ON : entered 01-02 04:40:09.013761 2259 2658 D AdapterProperties: Setting state to BLE_ON// 开始启动 经典蓝牙, 此时会启动 a2dpsink pbap client, hfp 等 profile. 01-02 04:40:09.042387 2259 2658 I AdapterState0: TURNING_ON : entered 01-02 04:40:09.042476 2259 2658 D AdapterProperties: Setting state to TURNING_ON// native-java: 更新 各个 子 profile 的 uuid. 标识当前 profile 的 service 已经启动成功 // 此时app 侧 可以对单个 profile 发起 操作了。 如果对应 profile uuid 没有更新, app 侧操作也会返回失败。 01-02 04:40:09.064374 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:3 len:16 01-02 04:40:09.111270 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:3 len:32 01-02 04:40:09.198514 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:3 len:32 01-02 04:40:09.210353 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:3 len:32 01-02 04:40:09.214185 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:3 len:48// 这里 标识 所有的 profile 已经启动完毕 经典蓝牙可以使用了 01-02 04:40:09.231319 2259 2259 D AdapterProperties: onBluetoothReady, stateTURNING_ON, ScanMode20 01-02 04:40:09.235691 2259 2259 I AdapterProperties: getBondedDevices: length1// native-java: 更新 扫描模式 01-02 04:40:09.236183 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:7 len:4 01-02 04:40:09.236748 2259 2691 D AdapterProperties: Scan Mode:21// native-java: 更新 Discoverable Timeout 01-02 04:40:09.236802 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:9 len:4 01-02 04:40:09.236819 2259 2691 D AdapterProperties: Discoverable Timeout:120// 此时经典蓝牙的所有 profile 已经都启动完毕 01-02 04:40:09.238341 2259 2658 I AdapterState0: ON : entered 01-02 04:40:09.238494 2259 2658 D AdapterProperties: Setting state to ON// native-java: 更新 Local IO Capability 01-02 04:40:09.240490 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:14 len:4 01-02 04:40:09.240542 2259 2691 D AdapterProperties: mLocalIOCapability set to 1// native-java: 更新 Ble Local IO Capability 01-02 04:40:09.240579 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:15 len:4 01-02 04:40:09.240616 2259 2691 D AdapterProperties: mLocalIOCapabilityBLE set to 4// native-java: 更新 DYNAMIC AUDIO BUFFER 01-02 04:40:09.240640 2259 2691 I AdapterProperties: adapterPropertyChangedCallback with type:16 len:192 6. GET 方向代码分析 我们如何获取到 当前蓝牙的 mac 地址 1. app 在应用侧 可以之间通过调用 BluetoothAdapter.getAddress() // framework/java/android/bluetooth/BluetoothAdapter.javapublic String getAddress() {try {return mManagerService.getAddress(mAttributionSource); } catch (RemoteException e) {Log.e(TAG, , e);}return null;}mManagerService.getAddress(mAttributionSource); : 会先调用到 system_server 中 这个过程本文不表。会触发调用到 bt.server 侧从这里开始分析。 2. bt.server-java 1. AdapterService // android/app/src/com/android/bluetooth/btservice/AdapterService.javaOverridepublic String getAddress() {if (mService null) {return null;}return getAddressWithAttribution(Utils.getCallingAttributionSource(mService));}Overridepublic void getAddressWithAttribution(AttributionSource source,SynchronousResultReceiver receiver) {try {receiver.send(getAddressWithAttribution(source));} catch (RuntimeException e) {receiver.propagateException(e);}}private String getAddressWithAttribution(AttributionSource attributionSource) {AdapterService service getService();if (service null || !callerIsSystemOrActiveOrManagedUser(service, TAG, getAddress)|| !Utils.checkConnectPermissionForDataDelivery(service, attributionSource, AdapterService getAddress)) {return null;}enforceLocalMacAddressPermission(service);// 最终通过 mAdapterProperties.getAddress() 获得return Utils.getAddressStringFromByte(service.mAdapterProperties.getAddress());}最终通过 mAdapterProperties.getAddress() 获得 2. AdapterProperties // android/app/src/com/android/bluetooth/btservice/AdapterProperties.javabyte[] getAddress() {return mAddress;}是不是很简单就获取到了 3. AdapterProperties-callback 按照我们的理解 此时不应该时 要调用到 native 从 native 开始获取吗 怎么到这里就直接 获得了。 其实不然 在第 3. 接口说明 native-java api 是有一个回调的。 void adapterPropertyChangedCallback(int[] types, byte[][] values) {Intent intent;int type;byte[] val;for (int i 0; i types.length; i) {val values[i];type types[i];infoLog(adapterPropertyChangedCallback with type: type len: val.length);synchronized (mObject) {switch (type) {case AbstractionLayer.BT_PROPERTY_BDADDR:mAddress val; // 赋值给 mAddress// 向外发送广播String address Utils.getAddressStringFromByte(mAddress);intent newIntent(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED,BluetoothAdapterExt.ACTION_BLUETOOTH_ADDRESS_CHANGED);intent.putExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS, address);intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);mService.sendBroadcastAsUser(intent, UserHandle.ALL,BLUETOOTH_CONNECT, Utils.getTempAllowlistBroadcastOptions());break;在蓝牙启动过程中就会将 BT_PROPERTY_BDADDR 从 native 更新到 java 侧。 4. AdapterService 启动时 当 AdapterService 启动时在其生命周期 onCreate 中会触发 native 获取 mac 地址 /packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/AdapterService.java public void onCreate() {...mAdapterProperties new AdapterProperties(this);mAdapterStateMachine AdapterState.make(this);...getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDADDR); // 主动获取 mac 地址 蓝牙名字 蓝牙类型getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME);getAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE);...}native 层 获取到 对应的mac 地址后 会回调到 adapterPropertyChangedCallback 7. SET 方向代码分析 这里 拿用户设置 蓝牙命名举例说明这个过程。 1. app app 侧调用 BluetoothAdapter.setName(xxx) 来设置蓝牙命名 // framework/java/android/bluetooth/BluetoothAdapter.javapublic boolean setName(String name) {Log.d(TAG, setName() name:name);if (getState() ! STATE_ON) {return false;}try {mServiceLock.readLock().lock();if (mService ! null) {final SynchronousResultReceiverBoolean recv SynchronousResultReceiver.get();mService.setName(name, 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;}2.AdapterService // android/app/src/com/android/bluetooth/btservice/AdapterService.javaOverridepublic void setName(String name, AttributionSource source,SynchronousResultReceiver receiver) {final String packageName source.getPackageName();Log.d(TAG, BluetoothAdapter Binder setName namename pkg:packageName);try {receiver.send(setName(name, source)); // 1.} catch (RuntimeException e) {receiver.propagateException(e);}}private boolean setName(String name, AttributionSource attributionSource) {AdapterService service getService();if (service null || !callerIsSystemOrActiveOrManagedUser(service, TAG, setName)|| !Utils.checkConnectPermissionForDataDelivery(service, attributionSource, AdapterService setName)) {return false;}return service.mAdapterProperties.setName(name); // 2. }3. AdapterProperties 在如下场景中我们都会使用到 setAdapterPropertyNative 接口 // android/app/src/com/android/bluetooth/btservice/AdapterProperties.java/*** Set the local adapter property - name* param name the name to set*/boolean setName(String name) {synchronized (mObject) {return mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_BDNAME,name.getBytes());}}boolean setBluetoothClass(BluetoothClass bluetoothClass) {synchronized (mObject) {boolean result mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_CLASS_OF_DEVICE,bluetoothClass.getClassOfDeviceBytes());if (result) {mBluetoothClass bluetoothClass;}return result;}}boolean setIoCapability(int capability) {synchronized (mObject) {boolean result mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS, Utils.intToByteArray(capability));if (result) {mLocalIOCapability capability;}return result;}}boolean setLeIoCapability(int capability) {synchronized (mObject) {boolean result mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_LOCAL_IO_CAPS_BLE,Utils.intToByteArray(capability));if (result) {mLocalIOCapabilityBLE capability;}return result;}}boolean setScanMode(int scanMode) {addScanChangeLog(scanMode);synchronized (mObject) {return mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_ADAPTER_SCAN_MODE,Utils.intToByteArray(AdapterService.convertScanModeToHal(scanMode)));}}boolean setDiscoverableTimeout(int timeout) {synchronized (mObject) {return mService.setAdapterPropertyNative(AbstractionLayer.BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT,Utils.intToByteArray(timeout));}}// android/app/src/com/android/bluetooth/btservice/AdapterService.javanative boolean setAdapterPropertyNative(int type, byte[] val); 8. GET 相关重要函数讲解 1. getAdapterPropertyNative 根据传入的 type : 获取 指定的 property 值 该函数 不是同步立马拿到结果。 会将结果异步 回调到 java 侧。 // packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/AdapterService.java/*package*/ native boolean getAdapterPropertyNative(int type);/packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp static jboolean getAdapterPropertyNative(JNIEnv* env, jobject obj, jint type) {ALOGV(%s, __func__);if (!sBluetoothInterface) return JNI_FALSE;int ret sBluetoothInterface-get_adapter_property((bt_property_type_t)type);return (ret BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; }system/btif/src/bluetooth.cc static int get_adapter_property(bt_property_type_t type) {/* Allow get_adapter_property only for BDADDR and BDNAME if BT is disabled */if (!btif_is_enabled() (type ! BT_PROPERTY_BDADDR) (type ! BT_PROPERTY_BDNAME) (type ! BT_PROPERTY_CLASS_OF_DEVICE))return BT_STATUS_NOT_READY;do_in_main_thread(FROM_HERE, base::BindOnce(btif_get_adapter_property, type));return BT_STATUS_SUCCESS; }void btif_get_adapter_property(bt_property_type_t type) {BTIF_TRACE_EVENT(%s %d, __func__, type);bt_status_t status BT_STATUS_SUCCESS;char buf[512];bt_property_t prop;prop.type type;prop.val (void*)buf;prop.len sizeof(buf);if (prop.type BT_PROPERTY_LOCAL_LE_FEATURES) {...} else if (prop.type BT_PROPERTY_DYNAMIC_AUDIO_BUFFER) {...} else {status btif_storage_get_adapter_property(prop);}invoke_adapter_properties_cb(status, 1, prop); }2. getAdapterPropertiesNative java 侧可以通过该 函数触发 所有 propert 的获取 同样也不是 同步调用。 // packages/modules/Bluetooth/android/app/src/com/android/bluetooth/btservice/AdapterService.java/*package*/native boolean getAdapterPropertiesNative();// packages/modules/Bluetooth/android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp static jboolean getAdapterPropertiesNative(JNIEnv* env, jobject obj) {ALOGV(%s, __func__);if (!sBluetoothInterface) return JNI_FALSE;int ret sBluetoothInterface-get_adapter_properties();return (ret BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; }// packages/modules/Bluetooth/system/btif/src/bluetooth.ccEXPORT_SYMBOL bt_interface_t bluetoothInterface {sizeof(bluetoothInterface),init,enable,disable,cleanup,get_adapter_properties, // get_adapter_properties...};static int get_adapter_properties(void) {if (!btif_is_enabled()) return BT_STATUS_NOT_READY;do_in_main_thread(FROM_HERE, base::BindOnce(btif_get_adapter_properties));return BT_STATUS_SUCCESS; }// packages/modules/Bluetooth/system/btif/src/btif_core.ccvoid btif_get_adapter_properties(void) {BTIF_TRACE_EVENT(%s, __func__);btif_in_get_adapter_properties(); }static bt_status_t btif_in_get_adapter_properties(void) {const static uint32_t NUM_ADAPTER_PROPERTIES 8;bt_property_t properties[NUM_ADAPTER_PROPERTIES];uint32_t num_props 0;RawAddress addr;bt_bdname_t name;bt_scan_mode_t mode;uint32_t disc_timeout;RawAddress bonded_devices[BTM_SEC_MAX_DEVICE_RECORDS];Uuid local_uuids[BT_MAX_NUM_UUIDS];bt_status_t status;bt_io_cap_t local_bt_io_cap;bt_io_cap_t local_bt_io_cap_ble;/* RawAddress */BTIF_STORAGE_FILL_PROPERTY(properties[num_props], BT_PROPERTY_BDADDR,sizeof(addr), addr);status btif_storage_get_adapter_property(properties[num_props]);// Add BT_PROPERTY_BDADDR property into list only when successful.// Otherwise, skip this property entry.if (status BT_STATUS_SUCCESS) {num_props;}/* BD_NAME */BTIF_STORAGE_FILL_PROPERTY(properties[num_props], BT_PROPERTY_BDNAME,sizeof(name), name);btif_storage_get_adapter_property(properties[num_props]);num_props;/* SCAN_MODE */BTIF_STORAGE_FILL_PROPERTY(properties[num_props],BT_PROPERTY_ADAPTER_SCAN_MODE, sizeof(mode),mode);btif_storage_get_adapter_property(properties[num_props]);num_props;/* DISC_TIMEOUT */BTIF_STORAGE_FILL_PROPERTY(properties[num_props],BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT,sizeof(disc_timeout), disc_timeout);btif_storage_get_adapter_property(properties[num_props]);num_props;/* BONDED_DEVICES */BTIF_STORAGE_FILL_PROPERTY(properties[num_props],BT_PROPERTY_ADAPTER_BONDED_DEVICES,sizeof(bonded_devices), bonded_devices);btif_storage_get_adapter_property(properties[num_props]);num_props;/* LOCAL UUIDs */BTIF_STORAGE_FILL_PROPERTY(properties[num_props], BT_PROPERTY_UUIDS,sizeof(local_uuids), local_uuids);btif_storage_get_adapter_property(properties[num_props]);num_props;/* LOCAL IO Capabilities */BTIF_STORAGE_FILL_PROPERTY(properties[num_props], BT_PROPERTY_LOCAL_IO_CAPS,sizeof(bt_io_cap_t), local_bt_io_cap);btif_storage_get_adapter_property(properties[num_props]);num_props;BTIF_STORAGE_FILL_PROPERTY(properties[num_props],BT_PROPERTY_LOCAL_IO_CAPS_BLE, sizeof(bt_io_cap_t),local_bt_io_cap_ble);btif_storage_get_adapter_property(properties[num_props]);num_props;invoke_adapter_properties_cb(BT_STATUS_SUCCESS, num_props, properties);return BT_STATUS_SUCCESS; }3. btif_storage_get_adapter_property getAdapterPropertyNative 和 getAdapterPropertiesNative 最终都会调用 btif_storage_get_adapter_property 作用根据 property-type 类型获取本地 Bluetooth 适配器的某项属性如地址、已绑定设备、UUID 支持列表等并将其填入传入的 property 结构中。 system/btif/src/btif_storage.cc /********************************************************************************* Function btif_storage_get_adapter_property** Description BTIF storage API - Fetches the adapter property-type* from NVRAM and fills property-val.* Caller should provide memory for property-val and* set the property-val** Returns BT_STATUS_SUCCESS if the fetch was successful,* BT_STATUS_FAIL otherwise*******************************************************************************//*参数property: 指向 bt_property_t 的指针结构内包含类型、长度和值的指针。 */ bt_status_t btif_storage_get_adapter_property(bt_property_t* property) {/* Special handling for adapter address and BONDED_DEVICES *//*判断当前请求的属性是否是获取本地蓝牙地址。强制转换为 RawAddress* 类型以便赋值。*/if (property-type BT_PROPERTY_BDADDR) {RawAddress* bd_addr (RawAddress*)property-val;/* Fetch the local BD ADDR *//*获取底层 Bluetooth Controller 的接口比如 HCI 层接口指针*/const controller_t* controller controller_get_interface();if (!controller-get_is_ready()) { // 检查 Controller 是否已经初始化完成。LOG_ERROR(%s: Controller not ready! Unable to return Bluetooth Address,__func__);*bd_addr RawAddress::kEmpty; // 如果未就绪返回一个空地址并失败退出return BT_STATUS_FAIL;} else {LOG_ERROR(%s: Controller ready!, __func__);*bd_addr *controller-get_address(); // 否则将 Controller 返回的地址写入 property-val}property-len RawAddress::kLength; // 设置属性长度并返回成功return BT_STATUS_SUCCESS;} else if (property-type BT_PROPERTY_ADAPTER_BONDED_DEVICES) { // 获取已绑定设备地址列表BONDED_DEVICESbtif_bonded_devices_t bonded_devices;btif_in_fetch_bonded_devices(bonded_devices, 0); // 获取绑定设备地址列表填充到 bonded_devices 结构中BTIF_TRACE_DEBUG(%s: Number of bonded devices: %d Property:BT_PROPERTY_ADAPTER_BONDED_DEVICES,__func__, bonded_devices.num_devices);// 设置返回值长度并拷贝设备地址数组到 property-valproperty-len bonded_devices.num_devices * RawAddress::kLength;memcpy(property-val, bonded_devices.devices, property-len);/* if there are no bonded_devices, then length shall be 0 */return BT_STATUS_SUCCESS;} else if (property-type BT_PROPERTY_UUIDS) { // 获取支持的 UUID 服务列表/* publish list of local supported services */Uuid* p_uuid reinterpret_castUuid*(property-val);uint32_t num_uuids 0;uint32_t i;// 获取已启用的 Profile 服务掩码bitmasktBTA_SERVICE_MASK service_mask btif_get_enabled_services_mask();LOG_INFO(%s service_mask:0x%x, __func__, service_mask);// 遍历所有服务 ID如果对应服务启用则进入处理。for (i 0; i BTA_MAX_SERVICE_ID; i) {/* This should eventually become a function when more services are enabled*/if (service_mask (tBTA_SERVICE_MASK)(1 i)) {switch (i) {case BTA_HFP_SERVICE_ID: { // 如果启用了 HFP将其 UUID 填入数组。*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_AG_HANDSFREE);num_uuids;}FALLTHROUGH_INTENDED; /* FALLTHROUGH *//* intentional fall through: Send both BFP HSP UUIDs if HFP is* enabled */// HFP 时顺带把 HSP 也加上经典 Bluetooth 的设计case BTA_HSP_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_HEADSET_AUDIO_GATEWAY);num_uuids;} break;case BTA_A2DP_SOURCE_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SOURCE);num_uuids;} break;case BTA_A2DP_SINK_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_AUDIO_SINK);num_uuids;} break;case BTA_PBAP_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_PBAP_PSE);num_uuids;} break;case BTA_HFP_HS_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_HF_HANDSFREE);num_uuids;} break;case BTA_MAP_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_ACCESS);num_uuids;} break;case BTA_MN_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_MESSAGE_NOTIFICATION);num_uuids;} break;case BTA_PCE_SERVICE_ID: {*(p_uuid num_uuids) Uuid::From16Bit(UUID_SERVCLASS_PBAP_PCE);num_uuids;} break;}}}property-len (num_uuids) * sizeof(Uuid); // 设置最终的 UUID 数组长度返回成功。return BT_STATUS_SUCCESS;}/* fall through for other properties */if (!cfg2prop(NULL, property)) { // 其他属性统一处理// 如果不属于以上特殊处理的属性类型尝试从配置文件中读取如 cfg2prop 从存储获取属性值。return btif_dm_get_adapter_property(property); // 若仍未命中则调用 btif_dm_get_adapter_property 去处理默认属性}return BT_STATUS_SUCCESS; }属性类型宏说明处理方式BT_PROPERTY_BDADDR获取本地蓝牙地址读取 controller 地址BT_PROPERTY_ADAPTER_BONDED_DEVICES获取绑定设备地址列表从绑定设备结构中复制BT_PROPERTY_UUIDS获取支持的服务 UUID 列表遍历启用服务掩码生成 UUID其它如名字、状态等通过配置或默认接口读取 1.cfg2prop 功能 该函数用于从配置文件中读取蓝牙属性值写入到 prop 指向的结构体中。属性来源可能是本地适配器如 Adapter 名称、扫描模式等或远程设备如远程设备名称、UUID 列表、版本信息等。 system/btif/src/btif_storage.cc /* remote_bd_addr远程设备的蓝牙地址如果为 NULL则表示读取本地适配器属性。prop目标属性结构体指针类型为 bt_property_t包括 type、val指向数据缓存和 len数据长度。 */static int cfg2prop(const RawAddress* remote_bd_addr, bt_property_t* prop) {std::string bdstr;if (remote_bd_addr) {/*如果传入了 remote_bd_addr就将其转为字符串形如 11:22:33:44:55:66用于后续配置文件查询 key。否则是读取本地适配器相关的属性。*/bdstr remote_bd_addr-ToString();}if (prop-len 0) {// 属性长度必须是正数否则认为是非法请求LOG_WARN(Invalid property read from configuration file type:%d, len:%d,prop-type, prop-len);return false;}int ret false;switch (prop-type) {case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:if (prop-len (int)sizeof(int))// 从配置中读取设备的时间戳ret btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,(int*)prop-val);break;case BT_PROPERTY_BDNAME: { // 本地或远程名称int len prop-len;if (remote_bd_addr)ret btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME,(char*)prop-val, len); // 如果是远程设备则从其对应的配置条目中读取名字elseret btif_config_get_str(Adapter, BTIF_STORAGE_KEY_ADAPTER_NAME,(char*)prop-val, len); // 如果是本地设备key 是 Adapter配置项名为 Name。if (ret len len prop-len) // 成功读取后更新 prop-len 为实际有效长度去掉 null terminator。prop-len len - 1;else {prop-len 0; // 如果读取失败则置为 0 并标记失败。ret false;}break;}case BT_PROPERTY_REMOTE_FRIENDLY_NAME: { // 与 BDNAME 类似从配置中获取远程设备别名 RemoteAlias。int len prop-len;ret btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE,(char*)prop-val, len);if (ret len len prop-len)prop-len len - 1;else {prop-len 0;ret false;}break;}case BT_PROPERTY_ADAPTER_SCAN_MODE: // 读取适配器的可见性扫描模式整型。if (prop-len (int)sizeof(int))ret btif_config_get_int(Adapter, BTIF_STORAGE_KEY_ADAPTER_SCANMODE,(int*)prop-val);break;// 读取本地 IO 能力常用于配对流程分为 BR/EDR 和 BLE。case BT_PROPERTY_LOCAL_IO_CAPS:if (prop-len (int)sizeof(int))ret btif_config_get_int(Adapter, BTIF_STORAGE_KEY_LOCAL_IO_CAPS,(int*)prop-val);break;case BT_PROPERTY_LOCAL_IO_CAPS_BLE:if (prop-len (int)sizeof(int))ret btif_config_get_int(Adapter, BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE,(int*)prop-val);break;// 获取适配器的可发现超时时间。case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:if (prop-len (int)sizeof(int))ret btif_config_get_int(Adapter, BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT, (int*)prop-val);break;// 获取远程设备的设备类别整型编码。case BT_PROPERTY_CLASS_OF_DEVICE:if (prop-len (int)sizeof(int))ret btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS,(int*)prop-val);break;// 获取设备类型如 phone、audio 等。case BT_PROPERTY_TYPE_OF_DEVICE:if (prop-len (int)sizeof(int))ret btif_config_get_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE,(int*)prop-val);break;// 从配置读取远程设备支持的 UUID 列表逗号分隔的字符串case BT_PROPERTY_UUIDS: {char value[1280];int size sizeof(value);if (btif_config_get_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, value,size)) {Uuid* p_uuid reinterpret_castUuid*(prop-val);// 调用 btif_split_uuids_string 函数分割字符串并转换为 UUID 对象数组size_t num_uuids btif_split_uuids_string(value, p_uuid, BT_MAX_NUM_UUIDS);prop-len num_uuids * sizeof(Uuid);ret true;} else {prop-val NULL;prop-len 0;}} break;// 读取远程设备的版本信息厂商、版本号、子版本号case BT_PROPERTY_REMOTE_VERSION_INFO: {bt_remote_version_t* info (bt_remote_version_t*)prop-val;if (prop-len (int)sizeof(bt_remote_version_t)) {ret btif_config_get_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_MFCT,info-manufacturer);if (ret)ret btif_config_get_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_VER,info-version);if (ret)ret btif_config_get_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_SUBVER,info-sub_ver);}} break;default: // 未支持的 type 直接报错返回BTIF_TRACE_ERROR(Unknow prop type:%d, prop-type);return false;}return ret; }#define BTIF_STORAGE_PATH_BLUEDROID /data/misc/bluedroid//#define BTIF_STORAGE_PATH_ADAPTER_INFO adapter_info //#define BTIF_STORAGE_PATH_REMOTE_DEVICES remote_devices #define BTIF_STORAGE_PATH_REMOTE_DEVTIME Timestamp #define BTIF_STORAGE_PATH_REMOTE_DEVCLASS DevClass #define BTIF_STORAGE_PATH_REMOTE_DEVTYPE DevType #define BTIF_STORAGE_PATH_REMOTE_NAME Name//#define BTIF_STORAGE_PATH_REMOTE_LINKKEYS remote_linkkeys #define BTIF_STORAGE_PATH_REMOTE_ALIASE Aliase #define BTIF_STORAGE_PATH_REMOTE_SERVICE Service #define BTIF_STORAGE_PATH_REMOTE_HIDINFO HidInfo #define BTIF_STORAGE_KEY_ADAPTER_NAME Name #define BTIF_STORAGE_KEY_ADAPTER_SCANMODE ScanMode #define BTIF_STORAGE_KEY_LOCAL_IO_CAPS LocalIOCaps #define BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE LocalIOCapsBLE #define BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT DiscoveryTimeout #define BTIF_STORAGE_KEY_GATT_CLIENT_SUPPORTED GattClientSupportedFeatures #define BTIF_STORAGE_KEY_GATT_CLIENT_DB_HASH GattClientDatabaseHash #define BTIF_STORAGE_KEY_GATT_SERVER_SUPPORTED GattServerSupportedFeatures #define BTIF_STORAGE_DEVICE_GROUP_BIN DeviceGroupBin #define BTIF_STORAGE_CSIS_AUTOCONNECT CsisAutoconnect #define BTIF_STORAGE_CSIS_SET_INFO_BIN CsisSetInfoBin #define BTIF_STORAGE_LEAUDIO_AUTOCONNECT LeAudioAutoconnect #define BTIF_STORAGE_LEAUDIO_HANDLES_BIN LeAudioHandlesBin #define BTIF_STORAGE_LEAUDIO_SINK_PACS_BIN SinkPacsBin #define BTIF_STORAGE_LEAUDIO_SOURCE_PACS_BIN SourcePacsBin #define BTIF_STORAGE_LEAUDIO_ASES_BIN AsesBin #define BTIF_STORAGE_LEAUDIO_SINK_AUDIOLOCATION SinkAudioLocation #define BTIF_STORAGE_LEAUDIO_SOURCE_AUDIOLOCATION SourceAudioLocation #define BTIF_STORAGE_LEAUDIO_SINK_SUPPORTED_CONTEXT_TYPE \SinkSupportedContextType #define BTIF_STORAGE_LEAUDIO_SOURCE_SUPPORTED_CONTEXT_TYPE \SourceSupportedContextType我们接下来看一下 他俩是如何实现的。 btif_config_get_str 和 btif_config_get_int 1. btif_config_get_str 和 btif_config_get_int system/btif/src/btif_config.cc bool btif_config_get_int(const std::string section, const std::string key,int* value) {CHECK(bluetooth::shim::is_gd_stack_started_up()); // 这里已经启用了 gd 协议栈return bluetooth::shim::BtifConfigInterface::GetInt(section, key, value); }bool btif_config_get_str(const std::string section, const std::string key,char* value, int* size_bytes) {CHECK(bluetooth::shim::is_gd_stack_started_up());return bluetooth::shim::BtifConfigInterface::GetStr(section, key, value,size_bytes); }system/main/shim/config.cc bool BtifConfigInterface::GetStr(const std::string section,const std::string property, char* value,int* size_bytes) {...// 这里会最终从 /data/misc/bluedroid/bt_config.conf 获取auto str GetStorage()-GetConfigCache()-GetProperty(section, property);...*size_bytes str-copy(value, (*size_bytes - 1));value[*size_bytes] \0;*size_bytes 1;return true; } // system/main/shim/entry.cc storage::StorageModule* GetStorage() {return Stack::GetInstance()-GetStackManager()-GetInstancestorage::StorageModule(); }// system/gd/storage/storage_module.cc ConfigCache* StorageModule::GetConfigCache() {std::lock_guardstd::recursive_mutex lock(mutex_);return pimpl_-cache_; // 这里的 cache_ 就是从 /data/misc/bluedroid/bt_config.conf 读到 内存的缓存 }---void StorageModule::Start() {...auto config LegacyConfigFile::FromPath(config_file_path_).Read(temp_devices_capacity_);...pimpl_ std::make_uniqueimpl(GetHandler(), std::move(config.value()), temp_devices_capacity_);}struct StorageModule::impl {explicit impl(Handler* handler, ConfigCache cache, size_t in_memory_cache_size_limit): config_save_alarm_(handler), cache_(std::move(cache)), memory_only_cache_(in_memory_cache_size_limit, {}) {} };想具体了解 StorageModule 请 参看 【android bluetooth 框架分析 02】【Module详解 6】【StorageModule 模块介绍】 2. ConfigCache::GetProperty 函数作用是根据指定的 section 和 property 键名查询配置缓存中是否存在对应的值并返回其值可能是明文或解密后的密文。 system/gd/storage/config_cache.cc /* 返回值是 std::optionalstd::string说明返回结果可能存在也可能不存在。参数 section配置项所在的“区块”类似 INI 文件里的 [section]。参数 property具体的键名。*/std::optionalstd::string ConfigCache::GetProperty(const std::string section, const std::string property) const {/*加锁保护多线程访问 information_sections_、persistent_devices_、temporary_devices_ 等成员变量。recursive_mutex 表示允许同一线程多次加锁避免死锁。*/std::lock_guardstd::recursive_mutex lock(mutex_);/*优先查找 information_sections_这是“运行时内存中保存的系统信息类配置”。如果 section 存在再查找其中是否有目标属性property。如果找到了直接返回该值明文。*/auto section_iter information_sections_.find(section);if (section_iter ! information_sections_.end()) {auto property_iter section_iter-second.find(property);if (property_iter ! section_iter-second.end()) {return property_iter-second;}}/*如果上一步没找到接着在 persistent_devices_ 中查找这是“持久化保存的设备相关信息”可能来源于配置文件。若找到对应 section 和 property执行下一步检查*/section_iter persistent_devices_.find(section);if (section_iter ! persistent_devices_.end()) {auto property_iter section_iter-second.find(property);if (property_iter ! section_iter-second.end()) {std::string value property_iter-second;/*如果值是一个特殊标记如 Encrypted说明真正的数据加密存储在 keystore 中使用 section - property 拼成 key 向 BtKeystoreInterface 查询解密后的值。否则直接返回明文值。*/if (os::ParameterProvider::GetBtKeystoreInterface() ! nullptr value kEncryptedStr) {return os::ParameterProvider::GetBtKeystoreInterface()-get_key(section - property);}return value;}}/*如果还没找到就在 temporary_devices_ 中查找这可能是“临时设备信息”生命周期较短。查找逻辑同上。*/section_iter temporary_devices_.find(section);if (section_iter ! temporary_devices_.end()) {auto property_iter section_iter-second.find(property);if (property_iter ! section_iter-second.end()) {return property_iter-second;}}return std::nullopt; // 如果三处都没找到返回空值. }查找顺序说明是否解密information_sections_内存中的系统信息否persistent_devices_持久化设备信息可能被加密是temporary_devices_临时设备信息仅内存存在否 该函数逻辑清晰地体现了一个设备配置信息获取的通用策略优先本地缓存其次查文件可能加密最后查临时存储。 2. btif_dm_get_adapter_property 该函数是 Bluetooth Adapter 属性查询的入口之一由上层调用例如 Settings 或 Bluetooth 服务层获取蓝牙本地信息时使用 此函数属于 BTIFBluetooth Interface层是 Java/Binder 与 BTA/Bluetooth stack 之间的桥梁。 功能根据传入的 prop-type填充 prop-val 值。 返回值为 bt_status_t表示操作是否成功例如 BT_STATUS_SUCCESS 或 BT_STATUS_FAIL。 system/btif/src/btif_dm.cc /********************************************************************************* Function btif_dm_get_adapter_property** Description Queries the BTA for the adapter property** Returns bt_status_t*******************************************************************************/ bt_status_t btif_dm_get_adapter_property(bt_property_t* prop) {BTIF_TRACE_EVENT(%s: type0x%x, __func__, prop-type);switch (prop-type) {// 获取蓝牙本地名称case BT_PROPERTY_BDNAME: {bt_bdname_t* bd_name (bt_bdname_t*)prop-val;strncpy((char*)bd_name-name, (char*)btif_get_default_local_name(),sizeof(bd_name-name) - 1); // 获取本地设备名系统默认名可能来源于 ro.product.*bd_name-name[sizeof(bd_name-name) - 1] 0; // 拷贝到 bd_name-name确保结尾有 \0prop-len strlen((char*)bd_name-name);} break;case BT_PROPERTY_ADAPTER_SCAN_MODE: { // 获取扫描模式/* if the storage does not have it. Most likely app never set it. Default* is NONE */bt_scan_mode_t* mode (bt_scan_mode_t*)prop-val;*mode BT_SCAN_MODE_NONE; // 默认设置为不可被扫描BT_SCAN_MODE_NONE除非应用层设置了别的值。prop-len sizeof(bt_scan_mode_t); // 这里不从系统读出设置值只是返回默认值。} break;// 如果设备开启“被发现模式”这个字段指定超时时间。case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: { // 获取可被发现超时时间uint32_t* tmt (uint32_t*)prop-val;*tmt 120; /* default to 120s, if not found in NV */ // 默认 120 秒prop-len sizeof(uint32_t);} break;// 获取设备的类信息case BT_PROPERTY_CLASS_OF_DEVICE: {DEV_CLASS dev_class; // DEV_CLASS 是一个 3 字节的数组如 [0x5A, 0x02, 0x0C]表示设备类型如手机/耳机/音箱等。btif_dm_get_local_class_of_device(dev_class);memcpy(prop-val, dev_class, sizeof(DEV_CLASS)); // 获取当前本地设备类prop-len sizeof(DEV_CLASS);} break;// While fetching IO_CAP* values for the local device, we maintain backward// compatibility by using the value from #define macros BTM_LOCAL_IO_CAPS,// BTM_LOCAL_IO_CAPS_BLE if the values have never been explicitly set.case BT_PROPERTY_LOCAL_IO_CAPS: { // 获取本地 IO 能力Classic 模式*(bt_io_cap_t*)prop-val (bt_io_cap_t)BTM_LOCAL_IO_CAPS; // 返回本地设备的经典蓝牙 IO 能力如显示/键盘/无输入输出。prop-len sizeof(bt_io_cap_t);} break;case BT_PROPERTY_LOCAL_IO_CAPS_BLE: { // 获取 BLE IO 能力低功耗蓝牙*(bt_io_cap_t*)prop-val (bt_io_cap_t)BTM_LOCAL_IO_CAPS_BLE; // 和上面类似只不过是 BLE 模式的 IO 能力prop-len sizeof(bt_io_cap_t);} break;default:prop-len 0;return BT_STATUS_FAIL; // 如果传入的类型不是已知的几种设置长度为 0并返回失败。}return BT_STATUS_SUCCESS; }enum : uint8_t {BTM_IO_CAP_OUT 0, /* DisplayOnly */BTM_IO_CAP_IO 1, /* DisplayYesNo */BTM_IO_CAP_IN 2, /* KeyboardOnly */BTM_IO_CAP_NONE 3, /* NoInputNoOutput */BTM_IO_CAP_KBDISP 4, /* Keyboard display */BTM_IO_CAP_MAX 5,BTM_IO_CAP_UNKNOWN 0xFF /* Unknown value */ };#ifndef BTM_LOCAL_IO_CAPS #define BTM_LOCAL_IO_CAPS BTM_IO_CAP_IO #endif#ifndef BTM_LOCAL_IO_CAPS_BLE #define BTM_LOCAL_IO_CAPS_BLE BTM_IO_CAP_KBDISP #endifprop-type 宏名内容默认值/说明BT_PROPERTY_BDNAME本地设备名称btif_get_default_local_name()BT_PROPERTY_ADAPTER_SCAN_MODE当前扫描模式BT_SCAN_MODE_NONEBT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT可发现超时时间120 秒BT_PROPERTY_CLASS_OF_DEVICE蓝牙设备类别COD设备类宏定义BT_PROPERTY_LOCAL_IO_CAPS本地 I/O 能力经典BTM_LOCAL_IO_CAPSBT_PROPERTY_LOCAL_IO_CAPS_BLE本地 I/O 能力BLEBTM_LOCAL_IO_CAPS_BLE 4. invoke_adapter_properties_cb system/btif/src/bluetooth.cc getAdapterPropertyNative 和 getAdapterPropertiesNative 最终都会调用 invoke_adapter_properties_cb void invoke_adapter_properties_cb(bt_status_t status, int num_properties,bt_property_t* properties) {do_in_jni_thread(FROM_HERE,base::BindOnce([](bt_status_t status, int num_properties,bt_property_t* properties) {HAL_CBACK(bt_hal_cbacks, adapter_properties_cb, status,num_properties, properties);if (properties) {osi_free(properties);}},status, num_properties,property_deep_copy_array(num_properties, properties))); }// android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp static bt_callbacks_t sBluetoothCallbacks {sizeof(sBluetoothCallbacks),adapter_state_change_callback,adapter_properties_callback,...};// 在 【3.接口说明】【2.native - java api】 中有详细讲解 static void adapter_properties_callback(bt_status_t status, int num_properties,bt_property_t* properties) {}9. SET 相关重要函数讲解 1. setAdapterPropertyNative android/app/jni/com_android_bluetooth_btservice_AdapterService.cpp static jboolean setAdapterPropertyNative(JNIEnv* env, jobject obj, jint type,jbyteArray value) {ALOGV(%s, __func__);if (!sBluetoothInterface) return JNI_FALSE;jbyte* val env-GetByteArrayElements(value, NULL);bt_property_t prop;prop.type (bt_property_type_t)type;prop.len env-GetArrayLength(value);prop.val val;int ret sBluetoothInterface-set_adapter_property(prop); // 1. env-ReleaseByteArrayElements(value, val, 0);return (ret BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE; }// system/btif/src/bluetooth.cc static int set_adapter_property(const bt_property_t* property) {if (!btif_is_enabled()) return BT_STATUS_NOT_READY;switch (property-type) {// 只有下面的 属性支持 Set , 其他属性 之间返回失败。不支持写case BT_PROPERTY_BDNAME:case BT_PROPERTY_ADAPTER_SCAN_MODE:case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:case BT_PROPERTY_CLASS_OF_DEVICE:case BT_PROPERTY_LOCAL_IO_CAPS:case BT_PROPERTY_LOCAL_IO_CAPS_BLE:break;default:return BT_STATUS_FAIL;}do_in_main_thread(FROM_HERE, base::BindOnce([](bt_property_t* property) {btif_set_adapter_property(property); // 1.osi_free(property);},property_deep_copy(property)));return BT_STATUS_SUCCESS; }2. btif_set_adapter_property 该函数用于设置蓝牙适配器的属性例如名称、扫描模式、类信息等并更新到底层 Bluetooth Stack同时缓存到本地存储如配置文件、nvram 等中。 功能将上层传入的新属性值更新到 Core Bluetooth Stack同时缓存到设备存储中。 应用于设置名称、设备类型、扫描模式等配置。 注意函数为 void 类型不返回 bt_status_t但可以通过其他回调机制通知上层成功/失败。 system/btif/src/btif_core.cc /********************************************************************************* Function btif_set_adapter_property** Description Updates core stack with property value and stores it in* local cache** Returns bt_status_t*******************************************************************************/void btif_set_adapter_property(bt_property_t* property) {BTIF_TRACE_EVENT(btif_set_adapter_property type: %d, len %d, 0x%x,property-type, property-len, property-val);switch (property-type) {case BT_PROPERTY_BDNAME: { // 设置蓝牙本地名称char bd_name[BTM_MAX_LOC_BD_NAME_LEN 1];uint16_t name_len property-len BTM_MAX_LOC_BD_NAME_LEN? BTM_MAX_LOC_BD_NAME_LEN: property-len;memcpy(bd_name, property-val, name_len);bd_name[name_len] \0; // 将新名称从 property-val 拷贝出来并保证最后一位为 \0BTIF_TRACE_EVENT(set property name : %s, (char*)bd_name);BTA_DmSetDeviceName((const char*)bd_name); // 调用 BTA_DmSetDeviceName() 向 BTA 层设置设备名通知 controller 层及远端设备。btif_core_storage_adapter_write(property); // 保存该配置例如写入 bt_config.conf 文件} break;case BT_PROPERTY_ADAPTER_SCAN_MODE: { // 设置扫描模式bt_scan_mode_t mode *(bt_scan_mode_t*)property-val;BTIF_TRACE_EVENT(set property scan mode : %x, mode);if (BTA_DmSetVisibility(mode)) { // 调用 BTA_DmSetVisibility(mode) 通知 BTA 更新设备可见性。btif_core_storage_adapter_write(property); // 如果设置成功就把它存到配置文件中}} break;case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT: { // 设置可被发现的超时时间 /* Nothing to do beside store the value in NV. Javawill change the SCAN_MODE property after setting timeout,if required */btif_core_storage_adapter_write(property); // 只做持久化存储不会立刻改变 controller 的状态。 java 层会在设置完 timeout 后自动设置 scan mode} break;case BT_PROPERTY_CLASS_OF_DEVICE: { // 设置设备类型 CODDEV_CLASS dev_class;memcpy(dev_class, property-val, DEV_CLASS_LEN);BTIF_TRACE_EVENT(set property dev_class : 0x%02x%02x%02x, dev_class[0],dev_class[1], dev_class[2]);BTM_SetDeviceClass(dev_class); // 使用 BTM_SetDeviceClass() 设置底层 controller 的设备类别。btif_core_storage_adapter_notify_empty_success(); // 通知设置成功用于反馈} break;case BT_PROPERTY_LOCAL_IO_CAPS: // 设置 IO 能力用于配对认证case BT_PROPERTY_LOCAL_IO_CAPS_BLE: {// Changing IO Capability of stack at run-time is not currently supported.// This call changes the stored value which will affect the stack next// time it starts up.btif_core_storage_adapter_write(property); // 虽然运行时不能动态更改 IO 能力比如从无输入输出变为键盘显示但会保存为下次启动生效。} break;default:break;} }类型宏名设置行为BT_PROPERTY_BDNAME设置设备名通知 Stack写入本地配置BT_PROPERTY_ADAPTER_SCAN_MODE设置可见性写入本地配置成功时BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT仅存储实际生效由 scan mode 决定BT_PROPERTY_CLASS_OF_DEVICE设置设备类型COD立即生效通知上层成功BT_PROPERTY_LOCAL_IO_CAPS/BLE设置 IO 能力仅写配置下次启动后生效 BTA_DmSetDeviceName 、 BTA_DmSetVisibility、BTM_SetDeviceClass 不再本文讨论范围内。暂时不表。有机会会单独出篇章讲解。 这里我们重点看一下 btif_core_storage_adapter_write 3. btif_core_storage_adapter_write system/btif/src/btif_core.cc static void btif_core_storage_adapter_write(bt_property_t* prop) {BTIF_TRACE_EVENT(type: %d, len %d, 0x%x, prop-type, prop-len, prop-val);bt_status_t status btif_storage_set_adapter_property(prop); // 1.invoke_adapter_properties_cb(status, 1, prop); // 这里同样会把 属性的结构回调到 java 侧 }4. btif_storage_set_adapter_property system/btif/src/btif_storage.cc bt_status_t btif_storage_set_adapter_property(bt_property_t* property) {return prop2cfg(NULL, property) ? BT_STATUS_SUCCESS : BT_STATUS_FAIL; }static int prop2cfg(const RawAddress* remote_bd_addr, bt_property_t* prop) {std::string bdstr;if (remote_bd_addr) {bdstr remote_bd_addr-ToString();}char value[1024];if (prop-len 0 || prop-len (int)sizeof(value) - 1) {LOG_WARN(Unable to save property to configuration file type:%d, len:%d is invalid,prop-type, prop-len);return false;}switch (prop-type) {case BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP:btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTIME,(int)time(NULL));break;case BT_PROPERTY_BDNAME: {int name_length prop-len BTM_MAX_LOC_BD_NAME_LEN? BTM_MAX_LOC_BD_NAME_LEN: prop-len;strncpy(value, (char*)prop-val, name_length);value[name_length] \0;if (remote_bd_addr) {btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_NAME, value);} else {btif_config_set_str(Adapter, BTIF_STORAGE_KEY_ADAPTER_NAME, value);btif_config_flush();}break;}case BT_PROPERTY_REMOTE_FRIENDLY_NAME:strncpy(value, (char*)prop-val, prop-len);value[prop-len] \0;btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_ALIASE, value);break;case BT_PROPERTY_ADAPTER_SCAN_MODE:btif_config_set_int(Adapter, BTIF_STORAGE_KEY_ADAPTER_SCANMODE,*(int*)prop-val);break;case BT_PROPERTY_LOCAL_IO_CAPS:btif_config_set_int(Adapter, BTIF_STORAGE_KEY_LOCAL_IO_CAPS,*(int*)prop-val);break;case BT_PROPERTY_LOCAL_IO_CAPS_BLE:btif_config_set_int(Adapter, BTIF_STORAGE_KEY_LOCAL_IO_CAPS_BLE,*(int*)prop-val);break;case BT_PROPERTY_ADAPTER_DISCOVERABLE_TIMEOUT:btif_config_set_int(Adapter, BTIF_STORAGE_KEY_ADAPTER_DISC_TIMEOUT,*(int*)prop-val);break;case BT_PROPERTY_CLASS_OF_DEVICE:btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVCLASS,*(int*)prop-val);break;case BT_PROPERTY_TYPE_OF_DEVICE:btif_config_set_int(bdstr, BTIF_STORAGE_PATH_REMOTE_DEVTYPE,*(int*)prop-val);break;case BT_PROPERTY_UUIDS: {std::string val;size_t cnt (prop-len) / sizeof(Uuid);for (size_t i 0; i cnt; i) {val (reinterpret_castUuid*(prop-val) i)-ToString() ;}btif_config_set_str(bdstr, BTIF_STORAGE_PATH_REMOTE_SERVICE, val);break;}case BT_PROPERTY_REMOTE_VERSION_INFO: {bt_remote_version_t* info (bt_remote_version_t*)prop-val;if (!info) return false;btif_config_set_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_MFCT,info-manufacturer);btif_config_set_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_VER, info-version);btif_config_set_int(bdstr, BT_CONFIG_KEY_REMOTE_VER_SUBVER,info-sub_ver);} break;default:BTIF_TRACE_ERROR(Unknown prop type:%d, prop-type);return false;}/* No need to look for bonded device with address of NULL */if (remote_bd_addr btif_in_fetch_bonded_device(bdstr) BT_STATUS_SUCCESS) {/* save changes if the device was bonded */btif_config_flush();}return true; }1. btif_config_set_str 和 btif_config_set_int // system/btif/src/btif_config.cc bool btif_config_set_int(const std::string section, const std::string key,int value) {CHECK(bluetooth::shim::is_gd_stack_started_up());return bluetooth::shim::BtifConfigInterface::SetInt(section, key, value); }// system/main/shim/config.cc bool BtifConfigInterface::SetInt(const std::string section,const std::string property, int value) {ConfigCacheHelper::FromConfigCache(*GetStorage()-GetConfigCache()).SetInt(section, property, value);return true; }// system/gd/storage/config_cache_helper.cc void ConfigCacheHelper::SetInt(const std::string section, const std::string property, int value) {config_cache_.SetProperty(section, property, std::to_string(value)); }2. ConfigCache::SetProperty 功能 设置一个配置项如蓝牙设备属性或通用配置并根据是否为设备属性决定是否进入持久化配置或临时配置缓存中。 // system/gd/storage/config_cache.ccvoid ConfigCache::SetProperty(std::string section, std::string property, std::string value) {/*使用递归互斥锁保护对 information_sections_、persistent_devices_、temporary_devices_ 等共享数据结构的并发访问。防止多线程同时读写 config。*/std::lock_guardstd::recursive_mutex lock(mutex_);// 移除传入字符串中可能存在的 \n 或 \r防止注入或破坏配置格式。TrimAfterNewLine(section);TrimAfterNewLine(property);TrimAfterNewLine(value);// section 和 property 名不能为空否则断言失败开发期调试用ASSERT_LOG(!section.empty(), Empty section name not allowed);ASSERT_LOG(!property.empty(), Empty property name not allowed);/* 判断是否为“设备节一般如 [Adapter], [Metrics], [Global] 属于非设备配置节而类似 [Device_XX:XX:XX:XX:XX:XX] 才是设备配置节。*/if (!IsDeviceSection(section)) {/*存入 information_sections_非设备类配置如果该节尚不存在则创建将 property - value 插入通知配置已更改。适用于如 [Adapter] 节下的 Name、ScanMode 等普通配置项。*/auto section_iter information_sections_.find(section);if (section_iter information_sections_.end()) {section_iter information_sections_.try_emplace_back(section, common::ListMapstd::string, std::string{}).first;}section_iter-second.insert_or_assign(property, std::move(value));PersistentConfigChangedCallback();return;}/*如果是设备配置节Device_...检查是否可持久化保存如果该设备还不在 persistent_devices_ 中且当前 property 是可持久化的如 LinkKey尝试从临时设备中迁移。*/auto section_iter persistent_devices_.find(section);if (section_iter persistent_devices_.end() IsPersistentProperty(property)) {// move paired devices or create new paired device when a link key is set/*从 temporary_devices_ 迁移或新建一项若该设备的属性存在于临时设备列表中则将其“转正”迁入 persistent否则新建。场景举例连接配对时第一次保存 link key从临时状态迁移为持久配对状态。*/auto section_properties temporary_devices_.extract(section);if (section_properties) {section_iter persistent_devices_.try_emplace_back(section, std::move(section_properties-second)).first;} else {section_iter persistent_devices_.try_emplace_back(section, common::ListMapstd::string, std::string{}).first;}}/*安全模式下加密敏感属性值如果开启了安全模式如 CC Mode并且属性为敏感字段如 LinkKey、LE_KEY_PENC 等通过 KeyStore 接口尝试加密存储若成功则设置为标记字符串 value $encrypted 表示已加密。 */if (section_iter ! persistent_devices_.end()) {bool is_encrypted value kEncryptedStr;if ((!value.empty()) os::ParameterProvider::GetBtKeystoreInterface() ! nullptr os::ParameterProvider::IsCommonCriteriaMode() InEncryptKeyNameList(property) !is_encrypted) {if (os::ParameterProvider::GetBtKeystoreInterface()-set_encrypt_key_or_remove_key(section - property, value)) {value kEncryptedStr;}}/*插入持久化设备属性 通知更改将处理后的值插入设备节中通知持久化更改通常触发异步写入 config 文件。 */section_iter-second.insert_or_assign(property, std::move(value));PersistentConfigChangedCallback();return;}/*如果该设备节仍不存在写入 temporary_devices_表示当前属性不需要持久化保存到 temporary_devices_ 中通常用于会话属性、未配对设备等*/section_iter temporary_devices_.find(section);if (section_iter temporary_devices_.end()) {auto triple temporary_devices_.try_emplace(section, common::ListMapstd::string, std::string{});section_iter std::get0(triple);}section_iter-second.insert_or_assign(property, std::move(value)); }SetProperty(section, key, value) │ ├─ Trim strings check valid │ ├─ if (section is not device) ─── write to information_sections_ │ ├─ if (section is device) │ ├─ if property is persistent section not in persistent_devices_ │ │ ├─ try extract from temporary_devices_ │ │ └─ or create new persistent section │ │ │ └─ if (CC mode key needs encryption) ── encrypt value │ │ └─ write to persistent_devices_ │ └─ else write to temporary_devices_ 首次连接设备存入 temporary_devices_ 成功配对后写入 LinkKey触发迁移到 persistent_devices_ 设置 Adapter 名称写入 information_sections_[Adapter][Name] CC 模式存储加密后的密钥值至 keystoreconfig 文件只存 $encrypted。
http://www.hkea.cn/news/14462854/

相关文章:

  • 洛阳免费提供建站方案广州高端品牌网站建设哪家公司好
  • 专门做酒的网站有哪些亿网联播
  • 夹江网站建设微信广告推广平台
  • 豪华网站建设免费ai写作网站3000字
  • 网站2345查询网
  • 网站租房做公寓国内视频培训网站建设
  • 网站建设技术知乎瓷器网站源码
  • 网站怎么做推广成都网站建设有名的公司
  • 展示型网站解决方案成都易站网站建设
  • 做防护用品的网站wordpress菜单优化插件
  • 济南网站建设开发公司开通网站运营商备案
  • dede 网站目录无忧代理 在线
  • html5 网站logo学推广网络营销去哪里
  • 如何做ico空投网站写网页用什么软件
  • 建设银行 商户网站打不开创业平台是干什么的
  • 网站后台基本功能wordpress 壁纸模板
  • 以用户为中心 建设学校网站至少保存十个以上域名网站
  • 网站建设的栏目内容邢台做网站的
  • 镇江网站建设方案短链接生成官网
  • 做网站要坚持青州网站建设青州
  • 电商网站话费充值怎么做网站维护一次多少钱
  • 做艺术品展览的网站微信下载网址是多少
  • 佛山合展商务网站建设正版电子商务网
  • 网站怎么设计抖音seo工具
  • 手机精品网站建设ae模板网
  • 什么网站备案容易审核沈阳网站建设q479185700棒
  • 网站怎么免费做推广好品质高端网站设计新感觉建站
  • 做网站的工资高host wordpress
  • 暖色调网页设计网站自己画装修设计图的软件
  • 电气网站开发网站建设公司广