ZT 4.3 android bluetooth hfp分析

4.3 android bluetooth hfp分析

592人阅读 评论(3) 收藏 举报

所有程序执行的代码都是有入口的,在这里我们暂时分析一种情景,蓝牙打开着,蓝牙耳机连接。

在设置界面点击蓝牙耳机操作:

packages/apps/Settings/src/com/android/settings/bluetooth/BluetoothDevicePreference.java

  1. void onClicked() {  
  2.     int bondState = mCachedDevice.getBondState();  
  3.   
  4.     if (mCachedDevice.isConnected()) {  
  5.         askDisconnect();  
  6.     } else if (bondState == BluetoothDevice.BOND_BONDED) { //已经配对,但是未连接  
  7.         <span style="color:#ff0000;">mCachedDevice.connect(true);</span>  
  8.     } else if (bondState == BluetoothDevice.BOND_NONE) { //没有配对  
  9.         <span style="color:#ff0000;">pair();</span>  
  10.     }  
  11. }  

mCachedDevice.connect(true);方法会直接调用CachedBluetoothDevice.java的connect的方法。

packages/apps/Settings/src/com/android/settings/bluetooth/CachedBluetoothDevice.java

  1.    void connect(boolean connectAllProfiles) {  
  2.         if (!ensurePaired()) {  //配对处理暂时不关注  
  3.             return;  
  4.         }  
  5.         mConnectAttempted = SystemClock.elapsedRealtime();  
  6.         connectWithoutResettingTimer(connectAllProfiles);  
  7.     }  

代码执行到connectWithoutResettingTimer,注释就不粘贴了。 

  1.     private void connectWithoutResettingTimer(boolean connectAllProfiles) {  
  2.          ......  
  3.         // Reset the only-show-one-error-dialog tracking variable  
  4.         mIsConnectingErrorPossible = true;  
  5.         int preferredProfiles = 0;  
  6.         for (LocalBluetoothProfile profile : mProfiles) {  
  7.             if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) {  
  8.                 if (profile.isPreferred(mDevice)) {  
  9.                     ++preferredProfiles;  
  10.                     connectInt(profile);  
  11.                 }  
  12.             }  
  13.         }  
  14.         if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles);  
  15.   
  16.         if (preferredProfiles == 0) {  
  17.             connectAutoConnectableProfiles();  
  18.         }  
  19.     }  

不同的协议实现类,继承于LocalBluetoothProfile,以HeadsetProfile为例。

  1. synchronized void connectInt(LocalBluetoothProfile profile) {  
  2.     if (!ensurePaired()) {  
  3.         return;  
  4.     }  
  5.     if (<span style="color:#ff0000;">profile.connect(mDevice)</span>) {  
  6.         if (Utils.D) {  
  7.             Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile));  
  8.         }  
  9.         return;  
  10.     }  
  11.     Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName);  
  12. }  

这个方法中,profile.connnect(),直接调用 HeadsetProfile的connnect(),其实headset/handsfree 是共用同一个service。

packages/apps/Settings/src/com/android/settings/bluetooth/HeadsetProfile.java

  1. public boolean connect(BluetoothDevice device) {  
  2.     if (mService == nullreturn false;  
  3.     List<BluetoothDevice> sinks = mService.getConnectedDevices();  
  4.     if (sinks != null) {//断开所有连接  
  5.         for (BluetoothDevice sink : sinks) {  
  6.             mService.disconnect(sink);  
  7.         }  
  8.     }  
  9.     return mService.connect(device);  
  10. }  


mService.connect 直接进入framwork层,调用Bluetooth Headset server的api。

frameworks/base/core/java/android/bluetooth/BluetoothHeadset.java

  1. public boolean connect(BluetoothDevice device) {  
  2.     if (DBG) log("connect(" + device + ")");  
  3.     if (mService != null && isEnabled() &&  
  4.         isValidDevice(device)) {  
  5.         try {  
  6.             return mService.connect(device);  
  7.         } catch (RemoteException e) {  
  8.             Log.e(TAG, Log.getStackTraceString(new Throwable()));  
  9.             return false;  
  10.         }  
  11.     }  
  12.     if (mService == null) Log.w(TAG, "Proxy not attached to service");  
  13.     return false;  
  14. }  

framework 中转了一下,利用Binder机制再次进入Bluetooth模块。

frameworks/base/core/java/android/bluetooth/IBluetoothHeadset.aidl,实现类是

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetService.java
注意顺序:Setting->framewrok->Bluetooth

  1. public boolean connect(BluetoothDevice device) {  
  2.     HeadsetService service = getService();  
  3.     if (service == nullreturn false;  
  4.     return service.connect(device);  
  5. }  


IBluetoothHeadset.Sub仅仅是一个连接,什么都不做直接进入HeadsetService.java的connect 方法。

  1.     public boolean connect(BluetoothDevice device) {         
  2.         enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM,  
  3.                                        "Need BLUETOOTH ADMIN permission");  
  4.   
  5.         if (getPriority(device) == BluetoothProfile.PRIORITY_OFF) {  
  6.             return false;  
  7.         }  
  8.         int connectionState = mStateMachine.getConnectionState(device);  
  9.         if (connectionState == BluetoothProfile.STATE_CONNECTED ||  
  10.             connectionState == BluetoothProfile.STATE_CONNECTING) {  
  11.             return false;  
  12.         }  
  13.         mStateMachine.sendMessage(HeadsetStateMachine.CONNECT, device);//万恶的状态机开始工作  
  14.         return true;  
  15.     }  

 

很讨厌android状态机,感觉把java搞成了非面向对象,进入状态机代码实现:

packages/apps/Bluetooth/src/com/android/bluetooth/hfp/HeadsetStateMachine.java

记住当前为 未连接状态,所以应该进入 Disconnected的状态,Disconnected的processMessage方法中:

  1. switch(message.what) {  
  2.     case CONNECT:  
  3.         BluetoothDevice device = (BluetoothDevice) message.obj;  
  4.         broadcastConnectionState(device, BluetoothProfile.STATE_CONNECTING,  
  5.                        BluetoothProfile.STATE_DISCONNECTED);  
  6.   
  7.         if (!<span style="color:#ff0000;">connectHfpNative(getByteAddress(device)) </span>) {  
  8.             broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED,  
  9.                            BluetoothProfile.STATE_CONNECTING);  
  10.             break;  
  11.         }  
  12.   
  13.         synchronized (HeadsetStateMachine.this) {  
  14.             mTargetDevice = device;  
  15.             transitionTo(mPending);  
  16.         }  


connectHfpNative 连接,jni 方法 简单了。

packages\apps\bluetooth\jni\Com_android_bluetooth_hfp.cpp

  1. {"connectHfpNative""([B)Z", (void *) connectHfpNative},  
  1. static jboolean connectHfpNative(JNIEnv *env, jobject object, jbyteArray address) {  
  2. jbyte *addr;  
  3. bt_status_t status;  
  4.   
  5. ALOGI("%s: sBluetoothHfpInterface: %p", __FUNCTION__, sBluetoothHfpInterface);  
  6. if (!sBluetoothHfpInterface) return JNI_FALSE;  
  7.   
  8. addr = env->GetByteArrayElements(address, NULL);  
  9. if (!addr) {  
  10.     jniThrowIOException(env, EINVAL);  
  11.     return JNI_FALSE;  
  12. }  
  13.   
  14. <span style="color:#ff0000;">if ((status = sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr)) != BT_STATUS_SUCCESS) {</span>  
  15.     ALOGE("Failed HF connection, status: %d", status);  
  16. }  
  17. env->ReleaseByteArrayElements(address, addr, 0);  
  18. return (status == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;  


关键函数是sBluetoothHfpInterface->connect((bt_bdaddr_t *)addr), connect定义在 hardware/libhardware/include/hardware/bt_hf.h,

但是实现却在:external/bluetooth/bluedroid/btif/src/btif_hf.c 中实现

  1. #include <hardware/bt_hf.h>  
  2. static bt_status_t connect( bt_bdaddr_t *bd_addr )  
  3. {  
  4.     CHECK_BTHF_INIT();  
  5.     return btif_queue_connect(UUID_SERVCLASS_AG_HANDSFREE, bd_addr, connect_int);  
  6. }  

看定义,直接连接handsfree

#define UUID_SERVCLASS_AG_HANDSFREE             0X111F  /* Handsfree profile */

btif_queue_connect的定义在下面文件中定义

external/bluetooth/bluedroid/btif/src/btif_profile_queue.c

进入bt_status_t btif_queue_connect看定义:

  1.   
  1. bt_status_t btif_queue_connect(uint16_t uuidconst bt_bdaddr_t *bda,  
  2.                         btif_connect_cb_t *connect_cb)  
  3. {  
  4.     connect_node_t node;  
  5.     memset(&node, 0, sizeof(connect_node_t));  
  6.     memcpy(&(node.bda), bda, sizeof(bt_bdaddr_t));  
  7.     node.uuid = uuid;  
  8.     node.p_cb = connect_cb;  
  9.   
  10.     return btif_transfer_context(queue_int_handle_evt, BTIF_QUEUE_CONNECT_EVT,  
  11.                           (char*)&node, sizeof(connect_node_t), NULL);  
  12. }  

btif_transfer_context定义在如下文件中

external/bluetooth/bluedroid/btif/src/btif_core.c

btif_transfer_context内容就不粘贴了,里面发送消息,调用

external/bluetooth/bluedroid/gki/common/gki_buffer.c

 

  1. void GKI_send_msg (UINT8 task_id, UINT8 mbox, void *msg)  

GKI_send_msg发送一条GKI信息到BTA,GKI_send_msg有三个参数,第一个参数是线程id,也作为task id, 通过bta_sys_init获得,第二个参数是mailbox id,第三个是上一步封装好的p_msg

GKI_send_msg 首先对p_msg进一步封装成event,通过链表存到mailbox id对应的任务队列中,调用external/bluetooth/bluedroid/gki/ulinux/gki_ulinux.c :: GKI_send_event
进行发送。
GKI_send_event设置事件掩码
gki_cb.com.OSWaitEvt[task_id] |= event;, 
通过pthread_cond_signal(&gki_cb.os.thread_evt_cond[task_id]);通知另外线程。
这样,在另外一个等待线程函数中gki_ulinux.c :: GKI_wait可以返回了。

ZT 4.3 android bluetooth hfp分析

上一篇:ZT Android4.2蓝牙基础架构学习


下一篇:SharePoint 2013 APP 安全示例 (三)使用远程的web资源