近期发现android 11 版本上的某些PDA机器上存在某个BLE的连接在断开且removeBond后, 后台虽然看不到已绑定设备, 但 getBondState()依然处于bonding状态, 造成 startScan 扫描不到, 而且这种状态都重启PDA或其他方式都无法恢复, 这样在用户创建 createBond就会弹出PIN框. 解决方法只能是由用户手动进行配对连接 或者 {BANNED}中国{BANNED}中国第一次连接后不做removeBond操作.
{BANNED}最佳终解决方法
点击(此处)折叠或打开
- 
				<application>
 
- 
				...
 
- 
				...
 
- 
				        <receiver android:name="aidc.uhf.pda.args_comm.nls_ble_impl.NlsBlePairReceiver"
 
- 
				            android:exported="true">
 
- 
				            <intent-filter android:priority="1000">
 
- 
				                <action android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
 
- 
				            </intent-filter>
 
- 
				        </receiver>
 
- 
				
 
- 
				    </application>
 
- 
				
 
- 
				
 
- 
				-------------------------------------------------------
 
- 
				@SuppressLint("MissingPermission")
 
- 
				    @Override
 
- 
				    public void onReceive(Context context, Intent intent) {
 
- 
				        if (BluetoothDevice.ACTION_PAIRING_REQUEST.equals(intent.getAction())) {
 
- 
				            int type = intent.getIntExtra(BluetoothDevice.EXTRA_PAIRING_VARIANT, BluetoothDevice.ERROR);
 
- 
				            //if (type != BluetoothDevice.PAIRING_VARIANT_PIN) return;
 
- 
				
 
- 
				            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
 
- 
				            if (device == null) return;
 
- 
				            String mac = device.getAddress();
 
- 
				            if ((mac == null) || (macPairing == null)) return;
 
- 
				            if (!mac.equals(macPairing)) {
 
- 
				                LogSdk.e(TAG, "setPin failed: mac not fit macPairing");
 
- 
				                return;
 
- 
				            }
 
- 
				            String devName = device.getName();
 
- 
				            if ((devName == null) || (devName.length() < 6)) {
 
- 
				                LogSdk.e(TAG, "Device Name too short. [" + devName + "]");
 
- 
				                return;
 
- 
				            }
 
- 
				
 
- 
				            String szPin = devName.substring(devName.length() - 6);
 
- 
				            boolean bResult = device.setPin(szPin.getBytes()); // 根据规则设定 PIN码
 
- 
				            mBondOK.set((bResult) ? PAIRED_OK : PAIRED_FAILED);
 
- 
				            Log.e(TAG, bResult ? "pairing OK" : "pairing failed");
 
- 
				
 
- 
				            abortBroadcast(); // 阻止广播继续传播
 
- 
				        }
 
- 
				    }
 
- 
				
 
- 
				实际上不用 pin 连接, 直接跳过
 
- 
				mBleService = gatt.getService(BT_SERVICE_UUID);// 获取我们的服务的通道.
 
- 
				               if (mBleService != null) {
 
- 
				                   connStatus = BLEDEV_STATE_CONNECTED_AND_PAIRED;
 
- 
				// if (nlsBleSyncPairOnce(mBleDev, TimeoutBlePaired)) { // 根据 PIN码 规则进行 配对
 
- 
				//                        connStatus = BLEDEV_STATE_CONNECTED_AND_PAIRED;
 
- 
				//                        LogSdk.w(TAG, "gatt: " + gatt + "  mBleGatt: " + mBleGatt);
 
- 
				//                    } else { //配对失败.
 
- 
				//                        connStatus = BLEDEV_STATE_INVALID;
 
- 
				//                    }
 
- 
				                } else { //未找到专属 service UUID.
 
- 
				                    connStatus = BLEDEV_STATE_INVALID;
 
- 
				                }
 
- 
				
 
- 这样, 后台是 bonding状态, 在进行 connectGatt 时会激发 PIN 提示框, 在 AndroidManifest.xml 中注册了拦截器, 就不会提示了. 然后在连接过程中根本不在进行Bond动作, 这样就可完美避坑
看下android的新版本源码到底哪里有bug造成这个问题. 主要看bluedroid的部分.
下载代码
- 
				
 
- 
				mkdir /ws/android_11/bin
 
- 
				curl https://storage.googleapis.com/git-repo-downloads/repo > /ws/android_11/bin/repo
 
- 
				chmod a+x /ws/android_11/bin/repo
 
- 
				
 
- 
				mkdir /ws/android_11/android-11.0.0_r3
 
- 
				cd /ws/android_11/android-11.0.0_r3
 
- 
				
 
- 
				git config --global user.email "iibull@yeah.net"
 
- 
				git config --global user.name "iibull"
 
- 
				
 
- 
				/ws/android_11/bin/repo init -u https://aosp.tuna.tsinghua.edu.cn/platform/manifest -b android-11.0.0_r3 --repo-url=https://gerrit-googlesource.lug.ustc.edu.cn/git-repo
 
- repo sync -c --no-tags ## 需要 至少50GB 空间(代码+编译)
点击(此处)折叠或打开
- 
				# 初始化编译环境( .可以用source代替,如 source build/envsetup.sh )
 
- 
				. build/envsetup.sh
 
- 
				# 执行
 
- 
				lunch  或者 lunch sdk_phone_x86_64
 
- 
				# 我这里使用模拟器所以选择 31 (即aosp_x86_64-eng)
 
- 
				Which would you like? [aosp_arm-eng] 31
 
- 
				# 开始编译(这里怕我电脑扛不住用的-j1,电脑好的可加大力度)
 
- 
				make -j8  ## 3个小时.
 
- 
				
 
- 
				
 
- emulator 内存{BANNED}{BANNED}最佳佳好 >= 12GB
点击(此处)折叠或打开
- 
				网上摘录
 
- 
				安卓中蓝牙协议栈主要分为三个时期,上古时期使用的是BlueZ,后来在4.2之后自己独立出来称为BlueDroid,现在好像又改名叫Fluoride了
 
- BlueZ蓝牙协议栈部分在内核中实现,socket系统调用提供了AF_BLUETOOTH的 family,可以支持获取HCI、L2CAP、RFCOMM类型的socket;
- 
				
 
- 
				对于BlueDroid而言,协议栈是在用户层实现的,内核只暴露出HCI(USB/UART)的接口
 
- 
				
 
- 
				Android 8.0 以后对蓝牙协议栈进行了重构,主要优化是使用HIDL来取代之前的硬件抽象层,方便厂商的接口集成
 
- 
				/packages/apps/bluetooth/{bluetooth service + profiles} 
 
- 
				/packages/apps/bluetooth/jni (bluetooth stack 在 system/bt)通过 HIDL 和 (hardware/interfaces/bluetooth + Vendor impl的Bluetooth Controller)
 
- 
				
 
- Android蓝牙协议栈的实现在system/bt目录中.
点击(此处)折叠或打开
- 
				从用户接口出发,参考Android的开发者文档是如何发现设备以及创建蓝牙连接的:
 
- 
				
 
- 
				https://developer.android.com/guide/topics/connectivity/bluetooth
 
- 
				https://developer.android.com/guide/topics/connectivity/bluetooth-le
 
- 
				
 
- 
				paired和connected的区别:
 
- 
				
 
- 
				paired 表示两个设备知道彼此的存在,并且已经协商好了链路秘钥(Link Key),可用该秘钥来进行认证和创建加密链接
 
- 
				connected 表示两个已经配对的设备创建了一个RFCOMM链接,共享一个RFCOMM channel
 
- 
				
 
- 其他分析参考 https://evilpan.com/2021/07/11/android-bt/

