博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android4.2蓝牙Enable完全分析
阅读量:6890 次
发布时间:2019-06-27

本文共 9713 字,大约阅读时间需要 32 分钟。

hot3.png

这应该只会是唯一的一篇从头到尾的调用关系都分析一遍的文章,目的是为了帮助初学者从上往下一层一层分析代码,对大量的代码不再害怕。如果是对阅读Android代码很熟悉的人可以略过这一篇。

蓝牙Enable

Android的蓝牙Enable是由BluetoothAdapter提供的。只需要调用BluetoothAdapter.enable()即可启动蓝牙。下面我就分析这一个过程。由于Android的java层的代码过多,我只顺序的看下去。

1、打开BluetoothAdapter.java,找到其中的enable方法,代码如下:

[java]

  1. public boolean enable() {  

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

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

  4.         return true;  

  5.     }  

  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]

  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。但是我们还是得找找到底是怎么来的。

2、在frameworks/base/services/java/com/android/server/SystemServer.java里面可以看到这样一句:

[java]

  1. bluetooth = new BluetoothManagerService(context);  

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

哦,原来是用的一个BluetoothManagerService的东西注册的服务,并不是Bluetooth.apk里面的。去看看是个什么玩意儿。

3、打开BluetoothManagerService.java,可以看到,这个东西就是BluetoothAdapter里面的mManagerService的proxy了。下面看里面的enable方法:

[java]

  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]

  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]

  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]

  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]

  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]

  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]

  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]

  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]

  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(),这个函数大概做了以下的事情:

1、注册java的回调函数(就是当下层已经打开蓝牙了,然后要通知上层,蓝牙已经打开了,java层就可以发送蓝牙打开的Broadcast了。)

2、初始化蓝牙模块的HAL接口。

3、得到sBluetoothInterface

你需要对应着/external/bluetooth/bluedroid/btif/src/bluetooth.c看,就比较容易理解了。

5、接下来终于进入Bluedroid了,找到/external/bluetooth/bluedroid/btif/src /bluetooth.c里面的enable函数,发现调用的btif_enable_bluetooth(),用tag进去看,发现原来整个分析的关键 点

[cpp]

  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]

  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]

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

返回结果:

[cpp]

  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]

  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]

  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]

  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和蓝牙的理解一定会更上一层。

转载于:https://my.oschina.net/u/994235/blog/300420

你可能感兴趣的文章
降低成本 打造高性能定制中端存储
查看>>
改变数据中心架构的SDN
查看>>
5款安卓应用帮你做计划 专治拖延症患者
查看>>
大数据来了 给政府统计带来了机遇与挑战
查看>>
主打无边界计算 从FusionServer V5看华为的服务器创新之道
查看>>
《Java核心技术 卷Ⅱ 高级特性(原书第10版)》一2.7 正则表达式
查看>>
启明星辰亮相首届江苏省网络空间安全攻防对抗赛 安全人才培养成热点
查看>>
电商信用流行造假 央视315曝光刷单黑产
查看>>
第二届MOSEC移动安全技术峰会体验赛“银河争霸”点燃现场
查看>>
Python 开发者如何正确使用 RStudio 编辑器
查看>>
白话阿里巴巴Java开发手册(编程规约)
查看>>
JavaScript 堆内存分析新工具 OneHeap
查看>>
朝九晚五的程序员如何提高开发技能
查看>>
7亿美金!易到用车或委身乐视体育
查看>>
普渡大学创造 DeepHand,用深度学习开发 AR 新技术
查看>>
对于Netty ByteBuf的零拷贝(Zero Copy) 的理解
查看>>
数据加速攻略:选择Server Flash还是全闪存阵列?
查看>>
应用商店成恶意APP滋生新温床 190款感染应用让你措不及防
查看>>
重装系统最关键一步:如何做好备份
查看>>
安全人员发现第一种全平台远程访问木马
查看>>