日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

android -- 蓝牙 bluetooth (二) 打开蓝牙

發布時間:2023/12/18 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android -- 蓝牙 bluetooth (二) 打开蓝牙 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

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)?{??
  • ???????//?Show?toast?message?if?Bluetooth?is?not?allowed?in?airplane?mode??
  • ???????if?(isChecked?&&??
  • ???????????????!WirelessSettings.isRadioAllowed(mContext,?Settings.Global.RADIO_BLUETOOTH))?{??
  • ???????????Toast.makeText(mContext,?R.string.wifi_in_airplane_mode,?Toast.LENGTH_SHORT).show();??
  • ???????????//?Reset?switch?to?off??
  • ???????????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))?{??
  • ????????//Start?bind?timeout?and?bind??
  • ????????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);??
  • ??//Remove?start?timeout??
  • ??removeMessages(START_TIMEOUT);??
  • ??
  • ??//Enable??
  • ??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");??
  • ??
  • ????/*?sanity?check?*/??
  • ????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;??
  • ??
  • ????/*?Create?the?GKI?tasks?and?run?them?*/??
  • ????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??
  • ????????/*?toggle?chip?power?to?ensure?we?will?reset?chip?in?case?
  • ???????????a?previous?stack?shutdown?wasn't?completed?gracefully?*/??
  • ????????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);??
  • ??
  • ????/*?Calling?vendor-specific?part?*/??
  • ????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 ?
  • /*?Entry?point?of?DLib?--?
  • ?*??????Vendor?library?needs?to?implement?the?body?of?bt_vendor_interface_t?
  • ?*??????structure?and?uses?the?below?name?as?the?variable?name.?HCI?library?
  • ?*??????will?use?this?symbol?name?to?get?address?of?the?object?through?the?
  • ?*??????dlsym?call.?
  • ?*/??
  • 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 (二) 打开蓝牙的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。