4.2的藍牙打開流程這一部分還是有些變化的,從界面上看藍牙開關就是設置settings里那個switch開關,widget開關當然也可以,起點不同而已,后續的流程是一樣的。先來看systemServer.java的代碼,藍牙服務開啟的地方,最后一個else分支是我們關心的,前兩個是模擬器的一個測試模式的。
?
[java]?view plaincopy ? 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?{??????????????????????????????????????????????????????????????????????????????????????????????Slog.i(TAG,?"Bluetooth?Manager?Service");?????????????????????????????????????????????????????????bluetooth?=?new?BluetoothManagerService(context);?????????????????????????????????????????????????ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,?bluetooth);?????????????}????? ? ? ? ? ?暫且看下bluetoothManagerService的構造方法,代碼有點多,我們只看兩個地方,?loadStoredNameAndAddress()是讀取藍牙打開默認名稱的地方,isBluetoothPersistedStateOn()是判斷是否已打開藍牙的,如果已打開,后續操作要執行開啟藍牙的動作,前面那幾行注冊廣播其中就有這個作用。
?
[java]?view plaincopy ? 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;??????????}??????}?? ?
? ? ? ? 回到界面開關那個看得著的地方,界面上開關就是BluetoothEnabler.java這個類了,而setBluetoothEnabled()則是具體開關動作。看下代碼
?
[java]?view plaincopy ? public?void?onCheckedChanged(CompoundButton?buttonView,?boolean?isChecked)?{????????????????if?(isChecked?&&?????????????????!WirelessSettings.isRadioAllowed(mContext,?Settings.Global.RADIO_BLUETOOTH))?{?????????????Toast.makeText(mContext,?R.string.wifi_in_airplane_mode,?Toast.LENGTH_SHORT).show();????????????????????????buttonView.setChecked(false);???????????????????}???????????if?(mLocalAdapter?!=?null)?{?????????????mLocalAdapter.setBluetoothEnabled(isChecked);?????????}?????????mSwitch.setEnabled(false);?????}?? 這里在判斷是飛行模式不知道為什么沒有return,如果是飛行模式會有提示toast彈出,既然這樣源碼為什么還要執行下面打開流程呢,也許是個bug?不細究這個了,繼續看setBluetoothEnabled()方法做什么了,很明顯mLocalAdapter(LocalBluetoothAdapter )只是個過渡,里面的?mAdapter(BluetoothAdapter)才是真正的主角,代碼如下:
?
[java]?view plaincopy ? public?void?setBluetoothEnabled(boolean?enabled)?{??????boolean?success?=?enabled?????mAdapter.enable()?:?mAdapter.disable();????????if?(success)?{??????????setBluetoothStateInt(enabled????????????????BluetoothAdapter.STATE_TURNING_ON??????????????:?BluetoothAdapter.STATE_TURNING_OFF);??????}?else?{?????????.........??????}??}?? ? ? ? ? 在BluetoothAdapter.java里可以看到一個單例模式的應用,主要提供給其它程序調用藍牙的一些方法用的,外部程序想調用藍牙的方法就要先用這個
拿到BluetoothAdapter對象,代碼也簡單看下吧,里面是典型的binder應用。
?
[java]?view plaincopy ? public?static?synchronized?BluetoothAdapter?getDefaultAdapter()?{?????if?(sAdapter?==?null)?{?????????IBinder?b?=?ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);?????????if?(b?!=?null)?{?????????????IBluetoothManager?managerService?=?IBluetoothManager.Stub.asInterface(b);?????????????sAdapter?=?new?BluetoothAdapter(managerService);?????????}?else?{?????????????Log.e(TAG,?"Bluetooth?binder?is?null");?????????}?????}?????return?sAdapter;?? ? ? ? ? 此時我們更關心mAdapter.enable()的后續操作,外部其它應用到getDefaultAdapter()也是調用enable(),注意,到了BluetoothAdapter我們已經在framework層了,順著BluetoothAdapter.java的enable()調用先回到BluetoothManagerService.java的enable(),再進一步來到BluetoothManagerService.java中的handleEnable()
方法,后面要跳轉到新類了,貼出來一起看下,這部分好像不同版本還有些出入,不過核心的啟動service是一樣的,不影響理解。
?
[java]?view plaincopy ? ?private?void?handleEnable(boolean?persist,?boolean?quietMode)?{???synchronized(mConnection)?{??????if?((mBluetooth?==?null)?&&?(!mBinding))?{??????????????????Message?timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);??????????mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);??????????mConnection.setGetNameAddressOnly(false);??????????Intent?i?=?new?Intent(IBluetooth.class.getName());??????????if?(!mContext.bindService(i,?mConnection,Context.BIND_AUTO_CREATE,????????????????????????????????????UserHandle.USER_CURRENT))?{??????????????mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);??????????????Log.e(TAG,?"Fail?to?bind?to:?"?+?IBluetooth.class.getName());??????????}?else?{??????????????mBinding?=?true;??????????}??????}??? ? ? ? ?下面跑到哪個service里去了呢,在log信息里可以看到"ActivityManager: Start proc com.android.bluetooth for service com.android.bluetooth/.btservice.AdapterService:"
?
這樣的信息,那就是去AdapterService里看看,里面一共有三個enable(),跳轉關系不復雜,我們直接看最后一個關鍵的。
?
[java]?view plaincopy ? public?synchronized?boolean?enable(boolean?quietMode)?{???????enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,???????????????"Need?BLUETOOTH?ADMIN?permission");???????if?(DBG)debugLog("Enable?called?with?quiet?mode?status?=??"?+?mQuietmode);???????mQuietmode??=?quietMode;???????Message?m?=???????????????mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);???????mAdapterStateMachine.sendMessage(m);???????return?true;???}?? ?狀態機來了,狀態轉換圖,從一個狀態接受命令跳到另一個狀態,因為我們是在開啟藍牙,所以先去的AdapterState.java內部類offstate.java里面找,在這個分支USER_TURN_ON看到mAdapterService.processStart();在這里面可以看到藍牙遍歷下所支持的profile,最后又發出個帶AdapterState.STARTED標識的消息
處理在同文件下面的代碼里
?
[java]?view plaincopy ? case?STARTED:???{????if?(DBG)?Log.d(TAG,"CURRENT_STATE=PENDING,?MESSAGE?=?STARTED,?isTurningOn="?+?isTurningOn?+?",?isTurningOff="?+?isTurningOff);??????removeMessages(START_TIMEOUT);????????boolean?ret?=?mAdapterService.enableNative();????if?(!ret)?{????????Log.e(TAG,?"Error?while?turning?Bluetooth?On");????????notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);????????transitionTo(mOffState);????}?else?{????????sendMessageDelayed(ENABLE_TIMEOUT,?ENABLE_TIMEOUT_DELAY);????}???
看到那個enableNative()函數調用了吧,又要用到JNI了,稍微回頭看下前面的代碼,我們先從應用界面開關BluetoothEnabler走到framework的BluetoothAdapter,又回到package的adapterService,現在又要去JNI的C++代碼了,往常一般是packages -->framework-->下面一層,這次順序有些顛倒了,不過這不能影響我們跟蹤代碼,最后
?
還是要到下面去的。一起往下看吧。
? ? ? ? 根據android JNI的函數命名慣例很容易找到enableNative對應的C++函數在packages/apps/Bluetooth/jni/com_android_bluetooth_btservice_AdapterService.cpp里面
?
[java]?view plaincopy ? static?jboolean?enableNative(JNIEnv*?env,?jobject?obj)?{?????ALOGV("%s:",__FUNCTION__);?????jboolean?result?=?JNI_FALSE;??????if?(!sBluetoothInterface)?return?result;??????int?ret?=?sBluetoothInterface->enable();??????result?=?(ret?==?BT_STATUS_SUCCESS)???JNI_TRUE?:?JNI_FALSE;??????return?result;??}?? ?
代碼瞬間簡潔了不少,看來更多的故事還在下面,sBluetoothInterface這是什么,直接關系到下一步去哪的問題,看下變量聲明,原來是
Const bt_interface_t *sBluetoothInterface = NULL; 再去找在哪初始化,搜索external目錄可以找到/external/bluetooth/bluedroid/btif/src/bluetooth.c
?
[cpp]?view plaincopy ? ????static?const?bt_interface_t?bluetoothInterface?=?{??????sizeof(bt_interface_t),??????init,??????enable,??????disable,??????.............??????start_discovery,??????cancel_discovery,??????create_bond,??????remove_bond,??????cancel_bond,?????...............??};?? 原來在這里,說下怎么找到,直接跳轉是不成了,看這個文件夾下的mk文件,那里面有libhardware目錄是編譯的時候要用到,這個多半在hardware目錄里,在這里面很快可以看到bluetooth.h,那里面有最我們要找的結構體定義,頭文件找到了,再找同名C文件就快了,好了繼續吧看下enable()里是怎么實現的
?
?
[cpp]?view plaincopy ? static?int?enable(?void?)??{??????ALOGI("enable");????????????if?(interface_ready()?==?FALSE)??????????return?BT_STATUS_NOT_READY;????????return?btif_enable_bluetooth();??}?? 又是一個新函數,直接跳轉,比起剛才的尋覓這太幸福了
[cpp]?view plaincopy ? bt_status_t?btif_enable_bluetooth(void)??{??????BTIF_TRACE_DEBUG0("BTIF?ENABLE?BLUETOOTH");????????if?(btif_core_state?!=?BTIF_CORE_STATE_DISABLED)??????{??????????ALOGD("not?disabled\n");??????????return?BT_STATUS_DONE;??????}????????btif_core_state?=?BTIF_CORE_STATE_ENABLING;????????????bte_main_enable(btif_local_bd_addr.address);????????return?BT_STATUS_SUCCESS;??}?? 忘了寫路徑了 好在可以直接跳轉,下面是/external/bluetooth/bluedroid/main/bte_main.c,有點長,暫時只關心set_power那部分就好了,
[cpp]?view plaincopy ? void?bte_main_enable(uint8_t?*local_addr)??{??????APPL_TRACE_DEBUG1("%s",?__FUNCTION__);??????........................????#if?(defined?(BT_CLEAN_TURN_ON_DISABLED)?&&?BT_CLEAN_TURN_ON_DISABLED?==?TRUE)??????????APPL_TRACE_DEBUG1("%s??Not?Turninig?Off?the?BT?before?Turninig?ON",?__FUNCTION__);????#else??????????????????bt_hc_if->set_power(BT_HC_CHIP_PWR_OFF);??#endif??????????bt_hc_if->set_power(BT_HC_CHIP_PWR_ON);????????????bt_hc_if->preload(NULL);??????}?????????.............................??}?? ?
路徑在這里/external/bluetooth/bluedroid/hci/src/bt_hci_bdroid.c,看看set_power里面有什么,快到頭了
?
[cpp]?view plaincopy ? static?void?set_power(bt_hc_chip_power_state_t?state)??{??????int?pwr_state;????????BTHCDBG("set_power?%d",?state);????????????pwr_state?=?(state?==?BT_HC_CHIP_PWR_ON)???BT_VND_PWR_ON?:?BT_VND_PWR_OFF;????????if?(bt_vnd_if)??????????bt_vnd_if->op(BT_VND_OP_POWER_CTRL,?&pwr_state);??????else??????????ALOGE("vendor?lib?is?missing!");??}?? ? ? ? ? 這下又有新東西了bt_vnd_if,這個是什么,bt_vendor_interface_t *bt_vnd_if=NULL;和剛才的bt_interface_t 一樣,我們希望可以找到它的初始化,那樣就可以繼續跟蹤了,不過看到下面的代碼和注釋,在源碼中我們要絕望了。路徑:/external/bluetooth/bluedroid/hci/include/bt_vendor_lib.h
?
?
[cpp]?view plaincopy ? extern?const?bt_vendor_interface_t?BLUETOOTH_VENDOR_LIB_INTERFACE;????bt_vendor_interface_t?*bt_vnd_if=NULL;??
?google定義好了接口,具體實現要看vendor廠商來做了,這后面怎么實現就看各家芯片商怎么寫了,肯定各有不同,而且這一部分代碼一般是不會公開,當然授權購買后除外了。所以在4.2的源碼中我們只跟到這里了,那后面會做什么呢,加載驅動和上電這兩項肯定要有了,打開藍牙沒這兩步怎么行,類似下面的字符串
?
?
[cpp]?view plaincopy ? static?const?char*?BT_DRIVER_MODULE_PATH?=????"/system/lib/modules/mbt8xxx.ko";??static?const?char*?BT_DRIVER_MODULE_NAME?=?????"bt8xxx";??static?const?char*?BT_DRIVER_MODULE_INIT_ARG?=?"?init_cfg=";??static?const?char*?BT_DRIVER_MODULE_INIT_CFG_PATH?=?"bt_init_cfg.conf";?? 在有類似下面的動作,insmod加載驅動,rfkill控制上下電,具體廠商具體做法也不同。
?
[cpp]?view plaincopy ? ret?=?insmod(BT_DRIVER_MODULE_PATH,?arg_buf);??ret?=?system("/system/bin/rfkill?block?all");?? ? ? ? ?寫到這,關于4.2源碼的藍牙打開流程就算結束了,比起4.1之前的代碼感覺沒有以前的直觀,對于vendor那部分的代碼大家只能看各自廠商的代碼了,一般藍牙開啟后才會上電,這樣也比較符合邏輯和節省電量,是否上電可以連上手機用adb shell看sys/class/rfkill目錄下的state狀態值,有些廠商會把藍牙和wifi的上電算在一起,這個也是要注意的,小心誤判。最后呢,這次文章寫得有點倉促,寫錯的或遺漏地方希望朋友指出來,非常感謝。
轉載于:https://www.cnblogs.com/Free-Thinker/p/4539973.html
總結
以上是生活随笔為你收集整理的android -- 蓝牙 bluetooth (二) 打开蓝牙的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。