Android -- Bluetooth framework startup process brief analysis

                    Android -- Bluetooth framework startup process brief analysis

 

        Bluetooth is a very common feature in Android devices. Device manufacturers can use BT to do common functions such as RC, connecting speakers, and the device itself as a sink. If some devices do not need the BT function, Android can also disable this module through configuration, which is convenient for manufacturers to customize their own devices. The Bluetooth function of the APP operating device is generally realized through the standard API-BluetoothAdapter. Here we don’t care about the implementation flow of the specific API. Let’s first understand the startup process of the Bluetooth framework, which can pave the way for the introduction of some common BT flows later.

We all know that the main system services of Android are started in system_server, and BT is no exception:

            // Skip Bluetooth if we have an emulator kernel
            // TODO: Use a more reliable check to see if this product should
            // support Bluetooth - see bug 988521
            if (isEmulator) {
                Slog.i(TAG, "No Bluetooth Service (emulator)");
            } else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
                Slog.i(TAG, "No Bluetooth Service (factory test)");
            } else if (!context.getPackageManager().hasSystemFeature
                       (PackageManager.FEATURE_BLUETOOTH)) {
                Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
            } else {
                traceBeginAndSlog("StartBluetoothService");
                mSystemServiceManager.startService(BluetoothService.class);
                traceEnd();
            }

In SystemServer, the starting point of BT framework starts in the form of service startup, which is very common in Android; we can configure the feature xml file to indicate whether the system currently supports Bluetooth. On some devices without Bluetooth modules, you can Remove the declaration of hardware feature bluetooth, so that the BT framework-related modules will not be started when the device starts:

class BluetoothService extends SystemService {
    private BluetoothManagerService mBluetoothManagerService;

    public BluetoothService(Context context) {
        super(context);
        //创建BluetoothManagerService的实例
        mBluetoothManagerService = new BluetoothManagerService(context);
    }
    ........
    @Override
    public void onBootPhase(int phase) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            //将BluetoothManagerService实例发布到系统中,这样就可以Context根据BT的service名去获取它的Binder代理操作API了
            publishBinderService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
                    mBluetoothManagerService);
        } else if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
            //此时系统应该启动到一个比较晚的阶段了,可以使用AMS去Bind需要的Service了
            mBluetoothManagerService.handleOnBootPhase();
        }
    }
    ........
}

During the construction of BluetoothManagerService, the mEnableExternal flag is mainly related to the automatic enable bt in the boot flow:

    BluetoothManagerService(Context context) {
        mHandler = new BluetoothHandler(IoThread.get().getLooper());//创建内部处理msg的handler

        mContext = context;

        mPermissionReviewRequired = context.getResources()
                .getBoolean(com.android.internal.R.bool.config_permissionReviewRequired);

        mCrashes = 0;
        mBluetooth = null;
        mBluetoothBinder = null;
        mBluetoothGatt = null;
        mBinding = false;
        mUnbinding = false;
        mEnable = false;
        mState = BluetoothAdapter.STATE_OFF;
        mQuietEnableExternal = false;//false表示此次enable需要触发auto connect device和保存状态,BluetoothAdapter::enableNoAutoConnect()可以改变此状态
        mEnableExternal = false;
        mAddress = null;
        mName = null;
        mErrorRecoveryRetryCounter = 0;
        mContentResolver = context.getContentResolver();
        // Observe BLE scan only mode settings change.
        registerForBleScanModeChange();
        mCallbacks = new RemoteCallbackList<IBluetoothManagerCallback>();
        mStateChangeCallbacks = new RemoteCallbackList<IBluetoothStateChangeCallback>();

        IntentFilter filter = new IntentFilter();
        filter.addAction(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);//监听App通过接口修改BT local name的广播(对端设备搜索你显示的字符串)
        filter.addAction(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);//监听bt地址改变的广播
        filter.addAction(Intent.ACTION_SETTING_RESTORED);//监听当前设置需要restore回上一次设置的广播,此时需要重新保存name和addr为上一次的信息
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        mContext.registerReceiver(mReceiver, filter);

        loadStoredNameAndAddress();//从数据库中加载本机Bt的local name和address
        if (isBluetoothPersistedStateOn()) {//查看上一次关机时,BT是否为enable状态;如果是,这次开机也需要enable BT
            if (DBG) {
                Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
            }
            mEnableExternal = true;//表明开机过程中需要enable BT
        }

        String airplaneModeRadios =
                Settings.Global.getString(mContentResolver, Settings.Global.AIRPLANE_MODE_RADIOS);
        if (airplaneModeRadios == null || airplaneModeRadios.contains(
                Settings.Global.RADIO_BLUETOOTH)) {
            mContentResolver.registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON), true,
                    mAirplaneModeObserver);//监听Airplane mode改变,相应改变BT状态;这在TV plateform上基本没用
        }

        int systemUiUid = -1;
        try {
            // Check if device is configured with no home screen, which implies no SystemUI.
            boolean noHome = mContext.getResources().getBoolean(R.bool.config_noHomeScreen);
            if (!noHome) {
                systemUiUid = mContext.getPackageManager()
                        .getPackageUidAsUser("com.android.systemui", PackageManager.MATCH_SYSTEM_ONLY,
                                UserHandle.USER_SYSTEM);
            }
            Slog.d(TAG, "Detected SystemUiUid: " + Integer.toString(systemUiUid));
        } catch (PackageManager.NameNotFoundException e) {
            // Some platforms, such as wearables do not have a system ui.
            Slog.w(TAG, "Unable to resolve SystemUI's UID.", e);
        }
        mSystemUiUid = systemUiUid;
    }

It is true, indicating that BT was enabled before the last shutdown, and this startup also needs to be enabled; others are mainly initialization actions of some broadcasting and database fields.

Go back to the previous BluetoothService startup process. When the system starts to a suitable stage, call back the corresponding function of SystemService. When the phase is PHASE_ACTIVITY_MANAGER_READY, call BMS::handleOnBootPhase() to start the BT framework:

    /**
     * Send enable message and set adapter name and address. Called when the boot phase becomes
     * PHASE_SYSTEM_SERVICES_READY.
     */
    public void handleOnBootPhase() {
        if (DBG) {
            Slog.d(TAG, "Bluetooth boot completed");
        }
        UserManagerInternal userManagerInternal =
                LocalServices.getService(UserManagerInternal.class);
        userManagerInternal.addUserRestrictionsListener(mUserRestrictionsListener);
        final boolean isBluetoothDisallowed = isBluetoothDisallowed();
        if (isBluetoothDisallowed) {
            return;
        }
        if (mEnableExternal && isBluetoothPersistedStateOnBluetooth()) {
            if (DBG) {
                Slog.d(TAG, "Auto-enabling Bluetooth.");
            }
            sendEnableMsg(mQuietEnableExternal/*默认false,表示此次enable需要自动连接device/保存enable状态*/,
                    BluetoothProtoEnums.ENABLE_DISABLE_REASON_SYSTEM_BOOT,
                    mContext.getPackageName());
        } else if (!isNameAndAddressSet()) {
            if (DBG) {
                Slog.d(TAG, "Getting adapter name and address");
            }
            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
            mHandler.sendMessage(getMsg);
        }
    }

The content of handleOnBootPhase() is relatively simple. According to some flags, it is judged whether to enable BT; and enable Bluetooth is realized by triggering send msg here:

    private void sendEnableMsg(boolean quietMode, int reason, String packageName) {
	    //发送MESSAGE_ENABLE msg
        mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE, quietMode ? 1 : 0, 0));
        addActiveLog(reason, packageName, true);
        mLastEnabledTime = SystemClock.elapsedRealtime();
    }


     case MESSAGE_ENABLE:
                    if (DBG) {
                        Slog.d(TAG, "MESSAGE_ENABLE(" + msg.arg1 + "): mBluetooth = " + mBluetooth);
                    }
                    mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                    mEnable = true;

                    // Use service interface to get the exact state
                    try {
                        mBluetoothLock.readLock().lock();
                        if (mBluetooth != null) { //开机第一次enable,值为null
                            int state = mBluetooth.getState();
                            if (state == BluetoothAdapter.STATE_BLE_ON) {//大部分设备一般都不是ble only mode
                                Slog.w(TAG, "BT Enable in BLE_ON State, going to ON");
                                mBluetooth.onLeServiceUp();
                                persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);
                                break;
                            }
                        }
                    } catch (RemoteException e) {
                        Slog.e(TAG, "", e);
                    } finally {
                        mBluetoothLock.readLock().unlock();
                    }

                    mQuietEnable = (msg.arg1 == 1);//此时为false
                    if (mBluetooth == null) {//mBluetooth是后面绑定Bt apk中AdapterService时拿到的Binder代理对象;用以把操作bypass到BT核心框架中
                        handleEnable(mQuietEnable);
                    } else {//如果mBluetooth不是null,说明之前已经启动过了;此时是Restart flow,以MESSAGE_RESTART_BLUETOOTH_SERVICE触发
                        //
                        // We need to wait until transitioned to STATE_OFF and
                        // the previous Bluetooth process has exited. The
                        // waiting period has three components:
                        // (a) Wait until the local state is STATE_OFF. This
                        //     is accomplished by "waitForOnOff(false, true)".
                        // (b) Wait until the STATE_OFF state is updated to
                        //     all components.
                        // (c) Wait until the Bluetooth process exits, and
                        //     ActivityManager detects it.
                        // The waiting for (b) and (c) is accomplished by
                        // delaying the MESSAGE_RESTART_BLUETOOTH_SERVICE
                        // message. On slower devices, that delay needs to be
                        // on the order of (2 * SERVICE_RESTART_TIME_MS).
                        //
                        waitForOnOff(false, true);
                        Message restartMsg =
                                mHandler.obtainMessage(MESSAGE_RESTART_BLUETOOTH_SERVICE);
                        mHandler.sendMessageDelayed(restartMsg, 2 * SERVICE_RESTART_TIME_MS);
                    }
                    break;

handleEnable() goes to Bind AdapterService to get its Binder handle:

 private BluetoothServiceConnection mConnection = new BluetoothServiceConnection();
......

    private class BluetoothServiceConnection implements ServiceConnection {
        public void onServiceConnected(ComponentName componentName, IBinder service) {
            String name = componentName.getClassName();
            if (DBG) {
                Slog.d(TAG, "BluetoothServiceConnection: " + name);
            }
            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
            if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
                msg.arg1 = SERVICE_IBLUETOOTH;
            } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
                msg.arg1 = SERVICE_IBLUETOOTHGATT;
            } else {
                Slog.e(TAG, "Unknown service connected: " + name);
                return;
            }
            msg.obj = service;
            mHandler.sendMessage(msg);
        }

        public void onServiceDisconnected(ComponentName componentName) {
            // Called if we unexpectedly disconnect.
            String name = componentName.getClassName();
            if (DBG) {
                Slog.d(TAG, "BluetoothServiceConnection, disconnected: " + name);
            }
            Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
            if (name.equals("com.android.bluetooth.btservice.AdapterService")) {
                msg.arg1 = SERVICE_IBLUETOOTH;
            } else if (name.equals("com.android.bluetooth.gatt.GattService")) {
                msg.arg1 = SERVICE_IBLUETOOTHGATT;
            } else {
                Slog.e(TAG, "Unknown service disconnected: " + name);
                return;
            }
            mHandler.sendMessage(msg);
        }
    }
......
    boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
        intent.setComponent(comp);
        if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
            Slog.e(TAG, "Fail to bind to: " + intent);
            return false;
        }
        return true;
    }

The Service declaration of IBluetooth.class is in the manifest xml of Bluetooth apk:

        <service
            android:process="@string/process"
            android:name = ".btservice.AdapterService">
            <intent-filter>
                <action android:name="android.bluetooth.IBluetooth" />
            </intent-filter>
        </service>

Go to the Bind AdapterService service and get its Binder handle to operate its interface later. The initialization of AdapterService will be discussed in the next chapter. Now let’s go back to the processing of sending MESSAGE_BLUETOOTH_SERVICE_CONNECTED(arg1:SERVICE_IBLUETOOTH) after the BMS binder succeeds:

case MESSAGE_BLUETOOTH_SERVICE_CONNECTED: {
                    if (DBG) {
                        Slog.d(TAG, "MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);
                    }

                    IBinder service = (IBinder) msg.obj; //保存Service的onBinder()句柄
                    try {
                        mBluetoothLock.writeLock().lock();
                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                            mBluetoothGatt =
                                    IBluetoothGatt.Stub.asInterface(Binder.allowBlocking(service));
                            continueFromBleOnState();
                            break;
                        } // else must be SERVICE_IBLUETOOTH

                        //Remove timeout
                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);

                        mBinding = false;
                        mBluetoothBinder = service;
                        mBluetooth = IBluetooth.Stub.asInterface(Binder.allowBlocking(service));//再转成IBluetooth对象

                        if (!isNameAndAddressSet()) {
                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
                            mHandler.sendMessage(getMsg);
                            if (mGetNameAddressOnly) {
                                return;
                            }
                        }

                        //Register callback object
                        try {
                            mBluetooth.registerCallback(mBluetoothCallback);//mBluetoothCallback用来监听BT的enable状态,如state_on/state_off的状态变化
                        } catch (RemoteException re) {
                            Slog.e(TAG, "Unable to register BluetoothCallback", re);
                        }
                        //Inform BluetoothAdapter instances that service is up
                        sendBluetoothServiceUpCallback();

                        //Do enable request
                        try {
                            if (!mQuietEnable) {
                                if (!mBluetooth.enable()) {//Service bind成功之后,call AdpaterService的enable()接口;做一些初始化动作,并向stack发送enable命令启动蓝牙
                                    Slog.e(TAG, "IBluetooth.enable() returned false");
                                }
                            } else {
                                if (!mBluetooth.enableNoAutoConnect()) {
                                    Slog.e(TAG, "IBluetooth.enableNoAutoConnect() returned false");
                                }
                            }
                        } catch (RemoteException e) {
                            Slog.e(TAG, "Unable to call enable()", e);
                        }
                    } finally {
                        mBluetoothLock.writeLock().unlock();
                    }

                    if (!mEnable) {
                        waitForOnOff(true, false);
                        handleDisable();
                        waitForOnOff(false, false);
                    }
                    break;
                }

Main operations:

  1. Get the onBinder() handle of the bind service and convert it to IBluetooth type
  2. Through the obj of IBluetooth type, call the enable() interface, transfer the flow to AdapterService, do some initialization, and enable bt cmd under the stack

Also note that if the connection between the BMS and the AdapterService is broken, it will eventually be re-bind through the MESSAGE_RESTART_BLUETOOTH_SERVICE msg; this may be due to the Bluetooth apk crash (which will generate a tombstone) due to an abnormal module, and the bind connection with the AdapterService Disconnected; Restart is triggered here, which will cause the enable BT process introduced again.

At this point, the flow of enable BT is transferred from BluetoothManagerService to AdapterService; in fact, most of the API calls through BluetoothAdapter are finally called to AdapterService, and then the cmd is sent to the stack through it.

AdapterService is a very important service in the Bluetooth framework. Its startup and initialization parts will be introduced separately in the next article.

PS:

You can see that there are two common flags during the BT startup process:

  1. mEnable: It is mainly used to mark the change of the Bluetooth state when the system is running, and it is sometimes consistent with the value of mEnableExternal. But if the status of Bluetooth is due to some reasons, such as stack crash, which causes Bluetooth to reset or restart, you need to use this flag to mark the enable/disable status of this case
  2. mEnableExternal: It mainly records the BT enabling state caused by manual operation by the user, such as enabling/disabling BT through the Bluetooth function button

 

 

 

Guess you like

Origin blog.csdn.net/csdn_of_coder/article/details/103965577
Recommended