Android framework 蓝牙开机连接慢与开机广播

问题:

项目需要使用蓝牙外接设备,但每次重启开机到launcher显示后,蓝牙设备均需要等待20秒以上才能操作,体验非常差。

分析:

蓝牙的回连是由framework层实现。BluetoothManagerService相关代码如下,可以看到,自动打开蓝牙的流程是接收开机广播实现的。

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
......省略
            } else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
                synchronized(mReceiver) {
                    if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
                        //Enable
                        if (DBG) Log.d(TAG, "Auto-enabling Bluetooth.");
                        sendEnableMsg(mQuietEnableExternal);
                    }
                }
......省略
            }
        }
    };

    BluetoothManagerService(Context context) {
......省略
        IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        registerForAirplaneMode(filter);
        mContext.registerReceiver(mReceiver, filter);
        loadStoredNameAndAddress();
        if (isBluetoothPersistedStateOn()) {
            mEnableExternal = true;
        }
......省略        
    }

继续分析开机流程,可以发现,BluetoothManagerService在08:00:23才接收到开机广播,那么是开机广播发的迟了,还是接收慢了?
Android framework 蓝牙开机连接慢与开机广播_第1张图片
可以看到,开机广播在08:00:07已经发出,也确实有其他APK接收到了,那么原因就是开机广播接收慢了。
在这里插入图片描述
那为什么有的APK又能接收到呢?原因有可能是广播接收顺序不同导致:
1、如果是有序广播,那么是按Receiver的优先级来发送的;
2、如果是无序广播(普通广播),那么如果广播是动态注册的,接收时是并行发送,静态注册则也是串行发送,顺序是根据APK启动的顺序来的。
很明显我们这个不可能是第二种情况了,那么也就是说开机广播是一个有序广播,我们的优先级太低了,是这样吗?
查看开机广播发送代码,可以看到其是使用broadcastIntentLocked发送,倒数第五个参数表示是否为有序广播,所以确实开机广播是有序广播,那么问题原因就已经很明确了。

    final void finishBooting() {
       ......省略
                for (int i=0; i

解决方法:

原因已明确,那么只需要提高BluetoothManagerService对开机广播的优先级即可,如下:
setPriority 可设置优先级为-1000~1000,越高则优先级越高,但实际上是可以设置到Integer.MAX_VALUE,目前暂不需要这么改,设置为1000,即IntentFilter.SYSTEM_HIGH_PRIORITY即可。

IntentFilter filter = new IntentFilter(Intent.ACTION_BOOT_COMPLETED);
	filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY/*Integer.MAX_VALUE*/);//提高优先级
        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
        filter.addAction(Intent.ACTION_USER_SWITCHED);
        registerForAirplaneMode(filter);
        mContext.registerReceiver(mReceiver, filter);

你可能感兴趣的:(Android)