Android4.2藍牙Enable徹底分析

這應該只會是惟一的一篇從頭至尾的調用關係都分析一遍的文章,目的是爲了幫助初學者從上往下一層一層分析代碼,對大量的代碼再也不懼怕。若是是對閱讀Android代碼很熟悉的人能夠略過這一篇。java

藍牙Enable

Android的藍牙Enable是由BluetoothAdapter提供的。只須要調用BluetoothAdapter.enable()便可啓動藍牙。下面我就分析這一個過程。因爲Android的java層的代碼過多,我只順序的看下去。android

一、打開BluetoothAdapter.java,找到其中的enable方法,代碼以下:app

[java] view plaincopy函數

  1. public boolean enable() {  學習

  2.     if (isEnabled() == true){  ui

  3.         if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");  spa

  4.         return true;  .net

  5.     }  debug

  6.     try {  代理

  7.         return mManagerService.enable();  

  8.     } catch (RemoteException e) {Log.e(TAG, "", e);}  

  9.     return false;  

  10. }  

發現關鍵的一句就是mManagerService.enable();這個mManagerService是什麼呢?其實就是btAdapter的一個proxy。能夠在getDefaultAdapter()裏面看到以下代碼

[java] view plaincopy

  1. public static synchronized BluetoothAdapter getDefaultAdapter() {  

  2.         if (sAdapter == null) {  

  3.             IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);  

  4.             if (b != null) {  

  5.                 IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);  

  6.                 sAdapter = new BluetoothAdapter(managerService);  

  7.             } else {  

  8.                 Log.e(TAG, "Bluetooth binder is null");  

  9.             }  

  10.         }  

  11.         return sAdapter;  

  12.     }  

  13.   

  14.     BluetoothAdapter(IBluetoothManager managerService) {  

  15.         if (managerService == null) {  

  16.             throw new IllegalArgumentException("bluetooth manager service is null");  

  17.         }  

  18.         try {  

  19.             mService = managerService.registerAdapter(mManagerCallback); //這實際上是一步重要的操做,初始化了咱們的mService  

  20.         } catch (RemoteException e) {Log.e(TAG, "", e);}  

  21.         mManagerService = managerService;  

  22.         mServiceRecordHandler = null;  

  23.     }  


它是經過ServiceManager獲取了一個系統服務,而後轉換爲了IBluetoothManager接口,讓mManagerService做爲 了bluetooth_manager服務的代理。這裏基本就能想到,這個bluetooth_manager服務多是Bluetooth.apk裏面 的btAdapter。可是咱們仍是得找找究竟是怎麼來的。

二、在frameworks/base/services/java/com/android/server/SystemServer.java裏面能夠看到這樣一句:

[java] view plaincopy

  1. bluetooth = new BluetoothManagerService(context);  

  2. ServiceManager.addService(BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE, bluetooth);  

哦,原來是用的一個BluetoothManagerService的東西註冊的服務,並非Bluetooth.apk裏面的。去看看是個什麼玩意兒。

三、打開BluetoothManagerService.java,能夠看到,這個東西就是BluetoothAdapter裏面的mManagerService的proxy了。下面看裏面的enable方法:


[java] view plaincopy

  1. public boolean enable() {  

  2.     //前面省略權限相關的東西  

  3.     synchronized(mReceiver) {  

  4.         mQuietEnableExternal = false;  

  5.         mEnableExternal = true;  

  6.         // waive WRITE_SECURE_SETTINGS permission check  

  7.         long callingIdentity = Binder.clearCallingIdentity();  

  8.         persistBluetoothSetting(BLUETOOTH_ON_BLUETOOTH);  

  9.         Binder.restoreCallingIdentity(callingIdentity);  

  10.         sendEnableMsg(false);  

  11.     }  

  12.     return true;  

  13. }  

看到這裏的關鍵就是sendEnableMsg(),繼續tag進去看看究竟。

[java] view plaincopy

  1. private void sendEnableMsg(boolean quietMode) {  

  2.     mHandler.sendMessage(mHandler.obtainMessage(MESSAGE_ENABLE,  

  3.                          quietMode ? 1 : 0, 0));  

  4. }  

額,又是Handler模式,這個玩意兒在Android系統裏面用得太多了。。遇到這種東西的時候,就進入到mHandler這個對象裏面的handleMessage去看switch---case就對了。

[java] view plaincopy

  1. case MESSAGE_ENABLE:  

  2.     mHandler.removeMessages(MESSAGE_RESTART_BLUETOOTH_SERVICE);  

  3.     mEnable = true;  

  4.     handleEnable(msg.arg1 == 1);  

  5.     break;  

OK,去handleEnable裏面去看吧,這裏傳送的參數是0。這個handleEnable有點太長了,我就截取重要部分了

[java] view plaincopy

  1. if ((mBluetooth == null) && (!mBinding)) {  

  2.      //Start bind timeout and bind  

  3.      Intent i = new Intent(IBluetooth.class.getName());  

  4.      if (!mContext.bindService(i, mConnection,Context.BIND_AUTO_CREATE,  

  5.                                UserHandle.USER_CURRENT)) {  

  6.      }  

  7.  } else if (mBluetooth != null) {  

  8. ="white-space:pre">     </span>//若是已經綁定了服務,就作其餘事……其實咱們通常調用,都是會進入這裏的。  

  9.  }  

  10.   

  11.  //Enable bluetooth  

  12.  try {  

  13.          if (!mQuietEnable) {  

  14.              if(!mBluetooth.enable()) {  

  15.                  Log.e(TAG,"IBluetooth.enable() returned false");  

  16.              }  

  17.          }  

  18.          else {  

  19.              if(!mBluetooth.enableNoAutoConnect()) {  

  20.                  Log.e(TAG,"IBluetooth.enableNoAutoConnect() returned false");  

  21.              }  

  22.          }  

  23.   } catch (RemoteException e) {  

  24.       Log.e(TAG,"Unable to call enable()",e);  

  25.   }  


好吧,轉那麼大的一圈,結果就是調用了mBluetooth.enable();並且蛋疼的是在BluetoothAdapter裏面原本就有 一個mService,而且mService就是registerAdapter()返回的mBluetooth!!不過親愛的朋友得注意了,咱們 BluetoothAdapter的mService的賦值是在這裏的bindService以前的,並且其餘的API的實現,都實際上是直接用的 mService,因此其實bindService是在BluetoothManagerService.java的另一個 MESSAGE_GET_NAME_AND_ADDRESS中調用的。真心蛋疼,這裏我我的以爲寫得很很差。

這個mBluetooth就是Bluetooth.apk裏面的AdapterService了。去看看代碼吧。

4.打開/packages/app/Bluetooth/src/com/android/bluetooth/btservice/AdapterService.java,找到關鍵代碼

[java] view plaincopy

  1. public synchronized boolean enable(boolean quietMode) {  

  2.     enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,  

  3.             "Need BLUETOOTH ADMIN permission");  

  4.     if (DBG)debugLog("Enable called with quiet mode status =  " + mQuietmode);  

  5.     mQuietmode  = quietMode;  

  6.     Message m =  

  7.             mAdapterStateMachine.obtainMessage(AdapterState.USER_TURN_ON);  

  8.     mAdapterStateMachine.sendMessage(m);  

  9.     return true;  

  10. }  

額,用了StateMachine,直接搜索UER_TURN_ON找到processMessage吧(StateMachine就是狀態機,在不一樣的狀態下,收到相同的Event,作不一樣的事情)

[cpp] view plaincopy

  1. notifyAdapterStateChange(BluetoothAdapter.STATE_TURNING_ON);        //更新AdapterService裏的狀態爲TURNING_ON  

  2.    mPendingCommandState.setTurningOn(true);             //設置在等待狀態下的TurningOn爲打開狀態  

  3.    transitionTo(mPendingCommandState);                  //轉移到Pending(等待)狀態  

  4.    sendMessageDelayed(START_TIMEOUT, START_TIMEOUT_DELAY);      //這個傢伙是設置超時的  

  5.    mAdapterService.processStart();                  //真正Enable藍牙的地方  



繼續看processStart

[cpp] view plaincopy

  1. void processStart() {   

  2.        ..................         

  3.     if (!mProfilesStarted && supportedProfileServices.length >0) {  

  4.         //Startup all profile services  

  5.         setProfileServiceState(supportedProfileServices,BluetoothAdapter.STATE_ON);<span style="white-space:pre">   </span>//這種狀況下也會Call到else裏面的同樣的代碼  

  6.     }else {  

  7.         if (DBG) {debugLog("processStart(): Profile Services alreay started");}  

  8.         mAdapterStateMachine.sendMessage(mAdapterStateMachine.obtainMessage(AdapterState.STARTED));  

  9.     }  

  10. }  



Android就是這麼煩,又進入了STARTED的狀態,此次是在Pending狀態下去看

[cpp] view plaincopy

  1. //Remove start timeout  

  2. removeMessages(START_TIMEOUT);                  //去除超時的定時器  

  3. //Enable  

  4. boolean ret = mAdapterService.enableNative();           //。。。原來這裏纔是真正的enableNative  

  5. if (!ret) {                             //若是失敗了  

  6.     notifyAdapterStateChange(BluetoothAdapter.STATE_OFF);       //讓AdapterService進入失敗狀態  

  7.     transitionTo(mOffState);                      

  8. } else {  

  9.     sendMessageDelayed(ENABLE_TIMEOUT, ENABLE_TIMEOUT_DELAY);  

  10. }  



好了,這樣就從java層進入到Native層了。對於之後分析藍牙,我就直接分析Bluetooth.apk裏面的東西了,就不會涉及到任何其餘的java代碼了。


5.在Bluetooth APP裏面打開jni/com_android_bluetooth_btservice_AdapterService.cpp,找到裏面的enableNative();

[cpp] view plaincopy

  1. jboolean result = JNI_FALSE;  

  2. if (!sBluetoothInterface) return result;  

  3.   

  4. int ret = sBluetoothInterface->enable();  

  5. result = (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;  

  6. return result;  

嗯,直接調用了sBluetoothInterface裏面的enable();sBluetoothInterface的初始化在classInitNative(),這個函數大概作了如下的事情:


一、註冊java的回調函數(就是當下層已經打開藍牙了,而後要通知上層,藍牙已經打開了,java層就能夠發送藍牙打開的Broadcast了。)

二、初始化藍牙模塊的HAL接口。

三、獲得sBluetoothInterface


你須要對應着/external/bluetooth/bluedroid/btif/src/bluetooth.c看,就比較容易理解了。

五、接下來終於進入Bluedroid了,找到/external/bluetooth/bluedroid/btif/src /bluetooth.c裏面的enable函數,發現調用的btif_enable_bluetooth(),用tag進去看,發現原來整個分析的關鍵 點

[cpp] view plaincopy

  1. bte_main_enable(btif_local_bd_addr.address);  

這個函數有點長啊,在bluedroid/main/bte_main.c裏面,咱們就關心bt_hc_if->set_power就是了。前面有作一些初始化Bluedroid的動做


bt_hc_if是由bt_hc_get_interface()返回的。繼續tag進去看。

發如今bluedroid/hci/src/bt_hci_bdroid.c裏面的,有個set_power()

這個過程以下:

[cpp] view plaincopy

  1. int pwr_state;  

  2.   

  3. BTHCDBG("set_power %d", state);  

  4.   

  5. /* Calling vendor-specific part */  

  6. pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;  

  7.   

  8. if (bt_vnd_if)  

  9.     bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state);  

  10. else  

  11.     ALOGE("vendor lib is missing!");  

好吧,最終就是調用的bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state);bt_vnd_if在init_vnd_if()函數裏面賦值,發現實際上是一個libbt-vendor.so的 interface。好吧,能夠絕望了,這個是Vendor的library。

我解釋一下什麼是VND(Vendor)

Vendor就是芯片供應商的意思,在他們作好一塊藍牙芯片後,須要提供一些硬件相關的動做,好比上下電,設置波特率之類的。可是這些操做通常 不會對沒有許可的開放。Bluedroid提供了一個統一的接口bt_vendor_interface_t,供應商只須要實現這個接口定義的藍牙相關的 操做就能夠交給bluedroid去作剩下的事情了。


咱們繼續分析,既然原生的Android代碼可以編譯出來可用的Android系統,那麼裏面確定也有廠家提供的開放的libbt-vendor.so,咱們進入/hardware/裏面去執行如下命令

[cpp] view plaincopy

  1. $ find . -name Android.mk | xargs grep "libbt"  

返回結果:

[cpp] view plaincopy

  1. $ find . -name Android.mk | xargs grep libbt  

  2. ./qcom/bt/Android.mk:include $(call all-named-subdir-makefiles,libbt-vendor)  

  3. ./qcom/bt/libbt-vendor/Android.mk:LOCAL_MODULE := libbt-vendor  

哈哈,原來Nexus4用的高通提供的藍牙芯片,那咱們能夠繼續進去看咯。

打開./qcom/bt/libbt-vendor/bt_vendor_qcom.c,找到op函數,找到關鍵點

[cpp] view plaincopy

  1. case BT_VND_OP_POWER_CTRL:  

  2.     {  

  3.         nState = *(int *) param;  

  4.         retval = hw_config(nState);  

  5.         if(nState == BT_VND_PWR_ON  

  6.            && retval == 0  

  7.            && is_hw_ready() == TRUE){  

  8.             retval = 0;  

  9.         }  

  10.         else {  

  11.             retval = -1;  

  12.         }  

  13.     }  

  14.     break;  

額,調用的hw_config(nState),進入看

[cpp] view plaincopy

  1. int hw_config(int nState)  

  2. {  

  3.     ALOGI("Starting hciattach daemon");  

  4.     char *szState[] = {"true", "false"};  

  5.     char *szReqSt = NULL;  

  6.   

  7.     if(nState == BT_VND_PWR_OFF)  

  8.         szReqSt = szState[1];  

  9.     else  

  10.         szReqSt = szState[0];  

  11.   

  12.     ALOGI("try to set %s", szReqSt);  

  13.   

  14.     if (property_set("bluetooth.hciattach", szReqSt) < 0){  

  15.         ALOGE("Property Setting fail");  

  16.         return -1;  

  17.     }  

  18.   

  19.     return 0;  

  20. }  

看到這裏,我又蛋疼了。怎麼跟Android的前幾個版本實現同樣了。我到如今都不知道這個hciattach屬性是在哪裏定義的,估計可能根本沒有使用 這個東西,由於bluez的hciattach.c我沒有找到。因此爲了避免妨礙咱們學習,我又找到了Broadcom的Vendor實現

在/device/common/libbt/src/bt_vendor_brcm.c裏面的。一樣的方式找到了upio.c裏面的upio_set_bluetooth_power()


[cpp] view plaincopy

  1. int upio_set_bluetooth_power(int on)  

  2. {  

  3.     int sz;  

  4.     int fd = -1;  

  5.     int ret = -1;  

  6.     char buffer = '0';  

  7.   

  8.     switch(on)  

  9.     {  

  10.         case UPIO_BT_POWER_OFF:  

  11.             buffer = '0';  

  12.             break;  

  13.   

  14.         case UPIO_BT_POWER_ON:  

  15.             buffer = '1';  

  16.             break;  

  17.     }  

  18.   

  19.     if (is_emulator_context())  

  20.     {  

  21.         /* if new value is same as current, return -1 */  

  22.         if (bt_emul_enable == on)  

  23.             return ret;  

  24.   

  25.         UPIODBG("set_bluetooth_power [emul] %d", on);  

  26.   

  27.         bt_emul_enable = on;  

  28.         return 0;  

  29.     }  

  30.   

  31.     /* check if we have rfkill interface */  

  32.     if (is_rfkill_disabled())  

  33.         return 0;  

  34.   

  35.     if (rfkill_id == -1)  

  36.     {  

  37.         if (init_rfkill())  

  38.             return ret;  

  39.     }  

  40.   

  41.     fd = open(rfkill_state_path, O_WRONLY);  

  42.   

  43.     if (fd < 0)  

  44.     {  

  45.         ALOGE("set_bluetooth_power : open(%s) for write failed: %s (%d)",  

  46.             rfkill_state_path, strerror(errno), errno);  

  47.         return ret;  

  48.     }  

  49.   

  50.     sz = write(fd, &buffer, 1);  

  51.   

  52.     if (sz < 0) {  

  53.         ALOGE("set_bluetooth_power : write(%s) failed: %s (%d)",  

  54.             rfkill_state_path, strerror(errno),errno);  

  55.     }  

  56.     else  

  57.         ret = 0;  

  58.   

  59.     if (fd >= 0)  

  60.         close(fd);  

  61.   

  62.     return ret;  

  63. }  


好吧,原來就是在rfkill_state_path(/sys/class/rfkill/rfkill[x]/state)虛擬設備裏寫入了1。對於驅動的代碼,我就不繼續看了。畢竟目前我也沒深刻到那一塊去。

rfkill是Linux下的一個標準的無線控制的虛擬設備,Linux也提供了rfkill的命令去查看以及控制全部的註冊的無線設備。它們會在/dev/(PC的Linux)或者/sys/class(通常是Android)下生成相應的虛擬設備。

到這裏,整個藍牙的Enable過程就分析完了。。

總結

整個過程十分累,從應用到下層。可是其實關鍵步驟就那麼幾步,從JNI那一塊開始入手的看,仍是比較好分析的。只要咱們願意深刻下去看,對於Bluedroid和藍牙的理解必定會更上一層。

相關文章
相關標籤/搜索