Android -- Bluetooth framework啓動過程簡析

                    Android -- Bluetooth framework啓動過程簡析

 

        藍牙是Android設備中非常常見的一個feature,設備廠家可以用BT來做RC、連接音箱、設備本身做Sink等常見功能。如果一些設備不需要BT功能,Android也可以通過配置來disable此模塊,方便廠家爲自己的設備做客製化。APP操作設備的藍牙功能,一般是通過標準API-BluetoothAdapter實現,這裏我們先不關心具體API的實現flow,先來了解Bluetooth framework的啓動過程,這樣可以爲後面介紹一些BT 常見flow,做鋪墊。

我們都知道Android的主要系統服務都是在system_server中啓動的,BT也不例外:

            // 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();
            }

在SystemServer中,BT framework啓動的起點以服務啓動的形式表現,這在Android中非常常見;我們可以通過配置feature xml文件來表明系統當前是否支持藍牙,在一些沒有藍牙模組的設備上,就可以去掉hardware feature bluetooth的聲明,這樣設備啓動時就不會啓動BT framework相關的模塊了:

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();
        }
    }
    ........
}

BluetoothManagerService構造過程中,跟開機flow中自動enable bt相關的主要是mEnableExternal這個flag:

    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;
    }

它爲true,表明上一次關機前BT就是enable的,這次開機也需要enable;其他的主要是一些廣播、數據庫字段的初始化動作。

回到前面BluetoothService啓動的過程,當系統啓動到合適的階段,就回調SystemService相應的函數,當phase爲PHASE_ACTIVITY_MANAGER_READY時,調用到BMS::handleOnBootPhase(),進行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);
        }
    }

handleOnBootPhase()的內容比較單一,根據一些flag判斷是否需要enable BT;而enable藍牙這裏是通過觸發send msg實現:

    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()去Bind AdapterService拿到它的Binder句柄:

 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;
    }

IBluetooth.class對於的Service聲明在Bluetooth apk的manifest xml中:

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

去Bind AdapterService服務,並拿到它的Binder句柄,用以後面操作它的接口。AdapterService的初始化下篇再講,現在先回到BMS binder成功之後發送MESSAGE_BLUETOOTH_SERVICE_CONNECTED(arg1:SERVICE_IBLUETOOTH)的處理:

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;
                }

主要操作:

  1. 拿到bind服務的onBinder()句柄,並轉成IBluetooth類型
  2. 通過IBluetooth類型的obj,調用enable()接口,將flow轉到AdapterService中,做一些初始化、並向stack下enable bt的cmd

也要注意到,如果BMS中和AdapterService的連接斷掉了,最終會通過MESSAGE_RESTART_BLUETOOTH_SERVICE msg去重新bind它;這在場景可能是由於模組異常導致Bluetooth apk crash(會產生tombstone),與AdapterService的bind連接斷掉;這裏觸發Restart,會導致重走一遍介紹的enable BT流程。

到此,enable BT的flow就從BluetoothManagerService轉到AdapterService中了;實際上,通過BluetoothAdapter下來的大部分API調用最終都是call到AdapterService,再通過它下cmd給stack。

AdapterService是藍牙框架中一個非常重要的服務,它的啓動和初始化部分,我們下篇再單獨介紹。

PS:

可以看到BT啓動過程中有兩個常見到的flag:

  1. mEnable:它主要是用來標記系統運行時,藍牙狀態的變化,它有些時候時跟mEnableExternal值一致的。但如果藍牙的狀態是因爲某些原因,如stack崩潰,導致藍牙需要reset、重新啓動時,需要靠這個flag來標記這種case的enable/disable狀態
  2. mEnableExternal:它主要是記錄通過用戶手動操作導致的BT使能狀態,如通過藍牙功能按鈕來enable/disable BT

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章