Android 4.4 Bluetooth學習之一

1、寫在前面的話
近來因爲項目需求須要搞藍牙這一塊,以前在上家公司帶LC(本地鏈接)組時也作過一點藍牙,在Android系統中也解過一些bug,可是不夠系統,如今正比如較系統的學習藍牙。

2、藍牙的協議框架
                     A2dp  Handset  opp Hid Health Pan Map  Dun...
                                       |  |     |...
                                  CORE Stack Specification
                                          |
                                 Host Controller Interface
                                          |
                                        chip

3、Android 4.4(Kitkat)上藍牙的啓動流程

1.服務啓動
系統啓動時在SystemServer中註冊藍牙服務管理BluetoothManagerService服務:

            if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
                Slog.i(TAG, "No Bluetooh Service (emulator)");
            } else if (factoryTest == SystemServer.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 if (disableBluetooth) {
                Slog.i(TAG, "Bluetooth Service disabled by config");
            } else {
                Slog.i(TAG, "Bluetooth Manager Service");
                bluetooth = new BluetoothManagerService(context);
                ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);
            }

其它進程經過binder機制調用該服務,該服務屬於綜合服務管理類,包括AdapterService的啓動、藍牙適配器Adapter的管理等。

2.藍牙啓動模式

在4.4上藍牙的啓動模式分兩種:QuietEnableMode和普通從「設置」裏打開兩種方式,前一中方式主要是爲了NFC的Handover功能——在傳遞媒體大文件時nfc會打開藍牙傳送。

3.藍牙關鍵服務啓動和回調處理

下面就以在「設置」中打開爲例描述下藍牙的啓動流程:

1)藍牙全部的profiles位於上層代碼中/packages/apps/Bluetooth目錄下,經常使用的幾個profiles包括A2dp、HeadSet、Opp、Hid、Pan等,而且Android 4.4上藍牙協議棧採用的是BRCM和Google共同開發的bluedroid;

2)啓動流程涉及代碼結構Settings -> Bluetooth -> framework -> bluedroid -> hci -> chip,啓動過程是先啓動AdapterService並初始化bluedroid,而後啓動全部的profile service(A2dpService、HeadsetService等),
成功加載所支持的profiles後使能bluedroid給藍牙上電,藍牙上電成功後回bluedroid回調類com_android_bluetooth_btservice_AdapterService.cpp的接口static void adapter_state_change_callback(bt_state_t status),經過JNI回調通知AdapterStateMachine更新Adapter狀態,而且通知註冊到AdapterService上回調:
void updateAdapterState(int prevState, int newState){
        if (mCallbacks !=null) {
            int n=mCallbacks.beginBroadcast();
            Log.d(TAG,"Broadcasting updateAdapterState() to " + n + " receivers.");
            for (int i=0; i <n;i++) {
                try {
                    mCallbacks.getBroadcastItem(i).onBluetoothStateChange(prevState,newState);
                }  catch (RemoteException e) {
                    Log.e(TAG, "Unable to call onBluetoothStateChange() on callback #" + i, e);
                }
            }
            mCallbacks.finishBroadcast();
        }
    }

mCallbacks該回調是BluetoothManagerService在成功bind到AdapterService時註冊的回調mBluetoothCallback:
case MESSAGE_BLUETOOTH_SERVICE_CONNECTED:
                {
                    if (DBG) Log.d(TAG,"MESSAGE_BLUETOOTH_SERVICE_CONNECTED: " + msg.arg1);

                    mIsBluetoothServiceConnected = true;

                    IBinder service = (IBinder) msg.obj;
                    synchronized(mConnection) {
                        if (msg.arg1 == SERVICE_IBLUETOOTHGATT) {
                            mBluetoothGatt = IBluetoothGatt.Stub.asInterface(service);
                            break;
                        } // else must be SERVICE_IBLUETOOTH

                        //Remove timeout
                        mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);

                        mBinding = false;
                        mBluetooth = IBluetooth.Stub.asInterface(service);

                        try {
                            boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
                                Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
                            if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
                                Log.e(TAG,"IBluetooth.configHciSnoopLog return false");
                            }
                        } catch (RemoteException e) {
                            Log.e(TAG,"Unable to call configHciSnoopLog", e);
                        }

                        if (mConnection.isGetNameAddressOnly()) {
                            //Request GET NAME AND ADDRESS
                            Message getMsg = mHandler.obtainMessage(MESSAGE_GET_NAME_AND_ADDRESS);
                            mHandler.sendMessage(getMsg);
                            if (!mEnable) return;
                        }

                        mConnection.setGetNameAddressOnly(false);
                        //Register callback object
                        try {
                            mBluetooth.registerCallback(mBluetoothCallback); //註冊Adapter狀態變動的callback
                        } catch (RemoteException re) {
                            Log.e(TAG, "Unable to register BluetoothCallback",re);
                        }
...

而BluetoothManagerService註冊該callback的目的是通知系統全部支持的profiles藍牙的開啓狀態,用於更新每一個profile和對應profile服務的bind,如通知BluetoothHeadset bind到HeadsetService上,經過binder機制獲取HeadsetService的句柄進行相關操做:
BluetoothHeadset.java
final private IBluetoothStateChangeCallback mBluetoothStateChangeCallback =
            new IBluetoothStateChangeCallback.Stub() {
                public void onBluetoothStateChange(boolean up) {
                    if (DBG) Log.d(TAG, "onBluetoothStateChange: up=" + up);
                    if (!up) {
                        if (VDBG) Log.d(TAG,"Unbinding service...");
                        synchronized (mConnection) {
                            try {
                                mService = null;
                                mContext.unbindService(mConnection);
                            } catch (Exception re) {
                                Log.e(TAG,"",re);
                            }
                        }
                    } else {
                        synchronized (mConnection) {
                            try {
                                if (mService == null) {
                                    if (VDBG) Log.d(TAG,"Binding service...");
                                    doBind();//綁定到HeadsetService
                                }
                            } catch (Exception re) {
                                Log.e(TAG,"",re);
                            }
                        }
                    }
                }
        };

那麼既然profile要去bind到對應的service上,這些profile對應的Sercice又是何時註冊的呢?
這個很關鍵,其實在咱們使能藍牙過程當中,AdapaterStateMachine處於OffState狀態,處理 msg.what == USER_TURN_ON
case USER_TURN_ON:
                   if (DBG) Log.d(TAG,"CURRENT_STATE=OFF, MESSAGE = USER_TURN_ON");
                   notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON);
                   mPendingCommandState.setTurningOn(true);
                   transitionTo(mPendingCommandState);
                   sendMessageDelayed(START_TIMEOUT, START_TIMEOUT_DELAY);
                   adapterService.processStart();//啓動系統支持的全部profiles的services

對應調用AdapterService的接口:

    void processStart() {
        if (DBG) debugLog("processStart()");
        Class[] supportedProfileServices = Config.getSupportedProfiles();
        //Initialize data objects
        for (int i=0; i < supportedProfileServices.length;i++) {
            mProfileServicesState.put(supportedProfileServices[i].getName(),BluetoothAdapter.STATE_OFF);
        }
        mRemoteDevices = new RemoteDevices(mPowerManager, this);
        mAdapterProperties.init(mRemoteDevices);

        if (DBG) {debugLog("processStart(): Make Bond State Machine");}
        mBondStateMachine = BondStateMachine.make(this, mAdapterProperties, mRemoteDevices);

        mJniCallbacks.init(mBondStateMachine,mRemoteDevices);

        //FIXME: Set static instance here???
        setAdapterService(this);

        //Start profile services
        if (!mProfilesStarted && supportedProfileServices.length >0) {
            //Startup all profile services
            setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);
        }else {
            if (DBG) {debugLog("processStart(): Profile Services alreay started");}
            mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));
        }
    }

以上就是profiles對應服務的註冊。

3)BluetoothManagerService中處理兩個callback:一個是來自BluetoothAdapter實例化時註冊的回調mManagerCallback並添加到BluetoothManagerService類private final RemoteCallbackList<IBluetoothManagerCallback> mCallbacks中,該callback主要用於當BluetoothManagerService成功bind到AdapterService時BluetoothDevice獲取AdapterService的句柄(BluetoothDevice獲取的過程也是向BluetoothAdapter註冊回調的機制);另外一個來自於各個profile實現類如BluetoothHeadset註冊的callback添加到BluetoothManagerService類private final RemoteCallbackList<IBluetoothStateChangeCallback> mStateChangeCallbacks中,用戶通知每一個profile adapter狀態的變化如TURNING_ON、TURN_ON、TURNING_OFF、TURN_OFF等;


4)Bluetooth中採用的回調機的地方太多,從Settings中顯示部分就多處採用回調來更新UI顯示,如BluetoothSettings父類DeviceListPreferenceFragment在onResume()時向LocalBluetoothEventManager中註冊callback:
@Override
    public void onResume() {
        super.onResume();
        if (mLocalManager == null) return;

        mLocalManager.setForegroundActivity(getActivity());
        mLocalManager.getEventManager().registerCallback(this);//註冊回調

        updateProgressUi(mLocalAdapter.isDiscovering());
    }

不只如此,在JNI和bluedroid的通訊中也採用的時回調機制,如com_android_bluetooth_btservice_AdapterService.cpp類在初始化bluedroid時:
static bool initNative(JNIEnv* env, jobject obj) {
    ALOGV("%s:",__FUNCTION__);

    sJniCallbacksObj = env->NewGlobalRef(env->GetObjectField(obj, sJniCallbacksField));

    if (sBluetoothInterface) {
        int ret = sBluetoothInterface->init(&sBluetoothCallbacks);//初始化回調接口
        if (ret != BT_STATUS_SUCCESS) {
            ALOGE("Error while setting the callbacks \n");
            sBluetoothInterface = NULL;
            return JNI_FALSE;
        }
        if ( (sBluetoothSocketInterface = (btsock_interface_t *)
                  sBluetoothInterface->get_profile_interface(BT_PROFILE_SOCKETS_ID)) == NULL) {
                ALOGE("Error getting socket interface");
        }

        if ( (sBluetoothMceInterface = (btmce_interface_t *)
                  sBluetoothInterface->get_profile_interface(BT_PROFILE_MAP_CLIENT_ID)) == NULL) {
                ALOGE("Error getting mapclient interface");
        } else {
            if ( (sBluetoothMceInterface->init(&sBluetoothMceCallbacks)) != BT_STATUS_SUCCESS) {
                ALOGE("Failed to initialize Bluetooth MCE");
                sBluetoothMceInterface = NULL;
            }
        }

        return JNI_TRUE;
    }
    return JNI_FALSE;
}

初次看code時可能會感受很繞,怎麼會那麼多回調呀?習慣了就好,這貌似時BRCM代碼風格。

4.藍牙關鍵類管理流程

                                                    —— A2dpProfile      < ———— >          BluetoothA2dp       <————>       A2dpService     <—————>    A2dpStateMachine   <————>  
                                                   |        (註冊Listener監聽profile的鏈接狀態)          (bind到A2dpService)             (採用狀態機管理)                 (jni機制)
                                                     com_android_bluetooth_a2dp <————> blueDroid <————> HCI
                                                   |...
                      —— LocalBluetoothProfile <——>|
                     |    (管理全部的profiles)      |
                     |                              —— HidProfile      < ———— >          BluetoothHid       <————>       HidService   <—————> com_android_bluetooth_hid <————> blueDroid <————> HCI
                     |                                    (註冊Listener監聽profile的鏈接狀態)         (bind到HidService)               (jni機制)
                     |                                                                                                                                              —— AdapterStateMachine
LocalBluetoothManager|—— LocalBluetoothApater      <——>     BluetoothAdapter   <————>   BluetoothManagerService <————>          AdapterService           < ————> |                 均經過JniCallback回調
(上層本地藍牙管理類)|      (本地Adpater)     (調用遠端的實現)                (開啓/關閉)   (藍牙遠端服務管理類)          (負責開啓/關閉及其它profile服務的管理)        —— BondStateMachine
                     |
                     |
                      —— BluetoothEventManager               <————>                 CachedBluetoothDeviceManager
                                            (註冊廣播監聽藍牙狀態變動、藍牙設備狀態)


4、小結
原本想採用UML畫出流程圖以備後查,無奈時間緊張、手頭沒有環境,唉作項目的人真心悲催啊!待續...java

相關文章
相關標籤/搜索