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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/myvest/article/details/94450893

问题:

项目需要使用蓝牙外接设备,但每次重启开机到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才接收到开机广播,那么是开机广播发的迟了,还是接收慢了?
在这里插入图片描述
可以看到,开机广播在08:00:07已经发出,也确实有其他APK接收到了,那么原因就是开机广播接收慢了。
在这里插入图片描述
那为什么有的APK又能接收到呢?原因有可能是广播接收顺序不同导致:
1、如果是有序广播,那么是按Receiver的优先级来发送的;
2、如果是无序广播(普通广播),那么如果广播是动态注册的,接收时是并行发送,静态注册则也是串行发送,顺序是根据APK启动的顺序来的。
很明显我们这个不可能是第二种情况了,那么也就是说开机广播是一个有序广播,我们的优先级太低了,是这样吗?
查看开机广播发送代码,可以看到其是使用broadcastIntentLocked发送,倒数第五个参数表示是否为有序广播,所以确实开机广播是有序广播,那么问题原因就已经很明确了。

    final void finishBooting() {
       ......省略
                for (int i=0; i<mStartedUsers.size(); i++) {
                    UserStartedState uss = mStartedUsers.valueAt(i);
                    if (uss.mState == UserStartedState.STATE_BOOTING) {
                        uss.mState = UserStartedState.STATE_RUNNING;
                        final int userId = mStartedUsers.keyAt(i);
                        Intent intent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                        intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                        intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT);
                        broadcastIntentLocked(null, null, intent, null,
                                new IIntentReceiver.Stub() {
                                    @Override
                                    public void performReceive(Intent intent, int resultCode,
                                            String data, Bundle extras, boolean ordered,
                                            boolean sticky, int sendingUser) {
                                        synchronized (ActivityManagerService.this) {
                                            requestPssAllProcsLocked(SystemClock.uptimeMillis(),
                                                    true, false);
                                        }
                                    }
                                },
                                0, null, null,
                                android.Manifest.permission.RECEIVE_BOOT_COMPLETED,
                                AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID,
                                userId);
                         Slog.e(TAG, "RECEIVE_BOOT_COMPLETE");
                    }
                }
            }
        }
    }

解决方法:

原因已明确,那么只需要提高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);

猜你喜欢

转载自blog.csdn.net/myvest/article/details/94450893