Android4.4(MT8685)源码蓝牙解析--连接
2014-12-13 15:31
447 查看
在BluetoothSetting的onResume生命周期方法中会执行updateContent方法,当蓝牙状态为开时,会执行其中这么一段代码:
这里我们只要关注LocalBluetoothManager这个类,进入这个类看看:
这里采用了单例模式,进入构造方法:
分别实例化了CachedBluetoothDeviceManager、BluetoothEventManager、LocalBluetoothProfileManager对象,其中CachedBluetoothDeviceManager和BluetoothEventManager的对象时作为LocalBluetoothProfileManager构造方法的参数,我们进入LocalBluetoothProfileManager中看看:
进入到updateLocalProfiles方法中:
这个方法的作用是初始化或更新本地的profile 对象,注意,这里还有另一个非常重要的方法,setBluetoothStateOn
这个方法会在LocalBluetoothAdapter类中,当蓝牙状态为开时调用,这个方法是初始化所有还未初始化的profile。分析到这里,似乎和蓝牙的连接没啥关系,不是的,上面的分析是铺垫,因为蓝牙涉及到多种不同的协议,当连接不同类型的蓝牙设备时,就要用不同的profile去连接,比如游戏手柄,就是用HidProfile。
下面我们来看看连接部分的代码,回到BluetoothSettings中的onDevicePreferenceClick方法,这个方法最终会调用父类的onDevicePreferenceClick方法:
进入到BluetoothDevicePreference的onClicked方法中:
这里首先获取当前被点击设备的状态,当状态为已配对时,就对你进行连接操作,进入CachedBluetoothDevice的connect方法
进入connectWithoutResettingTimer方法
这里会遍历之前初始化的所有profile,并将它们依次作为参数传入connectInt方法中,进入这个方法
这里就会调用profile的connect方法了,下面以HidProfile为例进行讲解,进入HidProfile的connect方法
这个mService是BluetoothInputDevice对象,进入它的connect方法
这里又是一个mSerivce,这个mSerivce其实是一个IBluetoothInputDevice接口对象,那我们只要找到相应的实现,HidSerivce,进入connect方法
这里会发送一个消息,我们看哪个地方接收这个消息
又见到了本地方法connectHidNative,进入到相应的jni方法中,在Com_android_bluetooth_hid.cpp文件中connectHidNative
又是sBluetoothHidInterface,它的实现是在MTK封装的蓝牙库中,连接完毕后会返回连接的信息,在connection_state_callback方法中
这个方法会回调HIDService中的onConnectStateChanged方法
这里又是发送一个消息,接收的地方
这里会通过broadcastConnectionState广播蓝牙的连接结果,
LocalBluetoothManager.getInstance(getActivity()).setDiscoverableEnabler( mDiscoverableEnabler);
这里我们只要关注LocalBluetoothManager这个类,进入这个类看看:
public static synchronized LocalBluetoothManager getInstance(Context context) { if (sInstance == null) { LocalBluetoothAdapter adapter = LocalBluetoothAdapter.getInstance(); if (adapter == null) { return null; } // This will be around as long as this process is Context appContext = context.getApplicationContext(); sInstance = new LocalBluetoothManager(adapter, appContext); } return sInstance; }
这里采用了单例模式,进入构造方法:
private LocalBluetoothManager(LocalBluetoothAdapter adapter, Context context) { mContext = context; mLocalAdapter = adapter; mCachedDeviceManager = new CachedBluetoothDeviceManager(context); mEventManager = new BluetoothEventManager(mLocalAdapter, mCachedDeviceManager, context); mProfileManager = new LocalBluetoothProfileManager(context, mLocalAdapter, mCachedDeviceManager, mEventManager); }
分别实例化了CachedBluetoothDeviceManager、BluetoothEventManager、LocalBluetoothProfileManager对象,其中CachedBluetoothDeviceManager和BluetoothEventManager的对象时作为LocalBluetoothProfileManager构造方法的参数,我们进入LocalBluetoothProfileManager中看看:
LocalBluetoothProfileManager(Context context, LocalBluetoothAdapter adapter, CachedBluetoothDeviceManager deviceManager, BluetoothEventManager eventManager) { mContext = context; mLocalAdapter = adapter; mDeviceManager = deviceManager; mEventManager = eventManager; // pass this reference to adapter and event manager (circular dependency) mLocalAdapter.setProfileManager(this); mEventManager.setProfileManager(this); ParcelUuid[] uuids = adapter.getUuids(); // uuids may be null if Bluetooth is turned off if (uuids != null) { Xlog.d(TAG, "bluetooth adapter uuid: "); for (ParcelUuid uuid : uuids) { Xlog.v(TAG, " " + uuid); } updateLocalProfiles(uuids); } }
进入到updateLocalProfiles方法中:
void updateLocalProfiles(ParcelUuid[] uuids) { // A2DP if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.AudioSource)) { if (mA2dpProfile == null) { Log.d(TAG, "Adding local A2DP profile"); mA2dpProfile = new A2dpProfile(mContext, mLocalAdapter, mDeviceManager, this); addProfile(mA2dpProfile, A2dpProfile.NAME, BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED); } } else if (mA2dpProfile != null) { Log.w(TAG, "Warning: A2DP profile was previously added but the UUID is now missing."); } // Headset / Handsfree if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.Handsfree_AG) || BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.HSP_AG)) { if (mHeadsetProfile == null) { Log.d(TAG, "Adding local HEADSET profile"); mHeadsetProfile = new HeadsetProfile(mContext, mLocalAdapter, mDeviceManager, this); addProfile(mHeadsetProfile, HeadsetProfile.NAME, BluetoothHeadset.ACTION_CONNECTION_STATE_CHANGED); } } else if (mHeadsetProfile != null) { Log.w(TAG, "Warning: HEADSET profile was previously added but the UUID is now missing."); } // OPP if (BluetoothUuid.isUuidPresent(uuids, BluetoothUuid.ObexObjectPush)) { if (mOppProfile == null) { Log.d(TAG, "Adding local OPP profile"); mOppProfile = new OppProfile(); // Note: no event handler for OPP, only name map. mProfileNameMap.put(OppProfile.NAME, mOppProfile); } } else if (mOppProfile != null) { Log.w(TAG, "Warning: OPP profile was previously added but the UUID is now missing."); } mEventManager.registerProfileIntentReceiver(); // There is no local SDP record for HID and Settings app doesn't control PBAP }
这个方法的作用是初始化或更新本地的profile 对象,注意,这里还有另一个非常重要的方法,setBluetoothStateOn
// Called from LocalBluetoothAdapter when state changes to ON void setBluetoothStateOn() { //M: when BT is turned on and these profiles have never been initialized, initialize it @{ if(mHidProfile == null) { mHidProfile = new HidProfile(mContext, mLocalAdapter, mDeviceManager, this); addProfile(mHidProfile, HidProfile.NAME, BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); } if(mPanProfile == null) { mPanProfile = new PanProfile(mContext); addPanProfile(mPanProfile, PanProfile.NAME, BluetoothPan.ACTION_CONNECTION_STATE_CHANGED); } if(mMapProfile == null) { if(DEBUG) Log.d(TAG, "Adding local MAP profile"); mMapProfile = new MapProfile(mContext, mLocalAdapter, mDeviceManager, this); addProfile(mMapProfile, MapProfile.NAME, BluetoothMap.ACTION_CONNECTION_STATE_CHANGED); } if(mPbapProfile == null) { mPbapProfile = new PbapServerProfile(mContext); } if(mFtpProfile == null) { mFtpProfile = new FtpProfile(mContext); addProfile(mFtpProfile, FtpProfile.NAME, BluetoothFtp.ACTION_STATE_CHANGED); } //@} ParcelUuid[] uuids = mLocalAdapter.getUuids(); if (uuids != null) { updateLocalProfiles(uuids); } mEventManager.readPairedDevices(); }
这个方法会在LocalBluetoothAdapter类中,当蓝牙状态为开时调用,这个方法是初始化所有还未初始化的profile。分析到这里,似乎和蓝牙的连接没啥关系,不是的,上面的分析是铺垫,因为蓝牙涉及到多种不同的协议,当连接不同类型的蓝牙设备时,就要用不同的profile去连接,比如游戏手柄,就是用HidProfile。
下面我们来看看连接部分的代码,回到BluetoothSettings中的onDevicePreferenceClick方法,这个方法最终会调用父类的onDevicePreferenceClick方法:
void onDevicePreferenceClick(BluetoothDevicePreference btPreference) { btPreference.onClicked(); }
进入到BluetoothDevicePreference的onClicked方法中:
void onClicked() { int bondState = mCachedDevice.getBondState(); if (mCachedDevice.isConnected()) { askDisconnect(); } else if (bondState == BluetoothDevice.BOND_BONDED) { Xlog.d(TAG, mCachedDevice.getName() + " connect"); mCachedDevice.connect(true); } else if (bondState == BluetoothDevice.BOND_NONE) { pair(); } }
这里首先获取当前被点击设备的状态,当状态为已配对时,就对你进行连接操作,进入CachedBluetoothDevice的connect方法
void connect(boolean connectAllProfiles) { if (!ensurePaired()) { return; } mConnectAttempted = SystemClock.elapsedRealtime(); connectWithoutResettingTimer(connectAllProfiles); }
进入connectWithoutResettingTimer方法
private void connectWithoutResettingTimer(boolean connectAllProfiles) { // Try to initialize the profiles if they were not. if (mProfiles.isEmpty()) { // if mProfiles is empty, then do not invoke updateProfiles. This causes a race // condition with carkits during pairing, wherein RemoteDevice.UUIDs have been updated // from bluetooth stack but ACTION.uuid is not sent yet. // Eventually ACTION.uuid will be received which shall trigger the connection of the // various profiles // If UUIDs are not available yet, connect will be happen // upon arrival of the ACTION_UUID intent. Log.d(TAG, "No profiles. Maybe we will connect later"); return; } // Reset the only-show-one-error-dialog tracking variable mIsConnectingErrorPossible = true; int preferredProfiles = 0; for (LocalBluetoothProfile profile : mProfiles) { if (connectAllProfiles ? profile.isConnectable() : profile.isAutoConnectable()) { if (profile.isPreferred(mDevice)) { ++preferredProfiles; connectInt(profile); } } } if (DEBUG) Log.d(TAG, "Preferred profiles = " + preferredProfiles); if (preferredProfiles == 0) { connectAutoConnectableProfiles(); } }
这里会遍历之前初始化的所有profile,并将它们依次作为参数传入connectInt方法中,进入这个方法
synchronized void connectInt(LocalBluetoothProfile profile) { if (!ensurePaired()) { return; } if (profile.connect(mDevice)) { if (Utils.D) { Log.d(TAG, "Command sent successfully:CONNECT " + describe(profile)); } return; } Log.i(TAG, "Failed to connect " + profile.toString() + " to " + mName); }
这里就会调用profile的connect方法了,下面以HidProfile为例进行讲解,进入HidProfile的connect方法
public boolean connect(BluetoothDevice device) { if (mService == null) return false; return mService.connect(device); }
这个mService是BluetoothInputDevice对象,进入它的connect方法
public boolean connect(BluetoothDevice device) { if (DBG) log("connect(" + device + ")"); if (mService != null && isEnabled() && isValidDevice(device)) { try { return mService.connect(device); } catch (RemoteException e) { Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable())); return false; } } if (mService == null) Log.w(TAG, "Proxy not attached to service"); return false; }
这里又是一个mSerivce,这个mSerivce其实是一个IBluetoothInputDevice接口对象,那我们只要找到相应的实现,HidSerivce,进入connect方法
boolean connect(BluetoothDevice device) { enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); log("begin to connect,device=" + device); if (getConnectionState(device) != BluetoothInputDevice.STATE_DISCONNECTED) { Log.e(TAG, "Hid Device not disconnected: " + device); return false; } if (getPriority(device) == BluetoothInputDevice.PRIORITY_OFF) { Log.e(TAG, "Hid Device PRIORITY_OFF: " + device); return false; } Message msg = mHandler.obtainMessage(MESSAGE_CONNECT, device); mHandler.sendMessage(msg); return true; }
这里会发送一个消息,我们看哪个地方接收这个消息
private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_CONNECT: { BluetoothDevice device = (BluetoothDevice) msg.obj; if (!connectHidNative(Utils.getByteAddress(device)) ) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); break; } mTargetDevice = device; } break; case MESSAGE_DISCONNECT: { BluetoothDevice device = (BluetoothDevice) msg.obj; if (!disconnectHidNative(Utils.getByteAddress(device)) ) { broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTING); broadcastConnectionState(device, BluetoothProfile.STATE_DISCONNECTED); break; } } break; case MESSAGE_CONNECT_STATE_CHANGED: { BluetoothDevice device = getDevice((byte[]) msg.obj); int halState = msg.arg1; Integer prevStateInteger = mInputDevices.get(device); int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED :prevStateInteger; if(DBG) Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:"+ convertHalState(halState)+", prevState:"+prevState); if (okToBroadcastConnectState(device, halState, prevState)) { broadcastConnectionState(device, convertHalState(halState)); } if (halState != CONN_STATE_CONNECTING) { mTargetDevice = null; } else { // CONN_STATE_CONNECTING is received only during // local initiated connection. mTargetDevice = device; } } break; case MESSAGE_GET_PROTOCOL_MODE: { BluetoothDevice device = (BluetoothDevice) msg.obj; if(!getProtocolModeNative(Utils.getByteAddress(device)) ) { Log.e(TAG, "Error: get protocol mode native returns false"); } } break; case MESSAGE_ON_GET_PROTOCOL_MODE: { BluetoothDevice device = getDevice((byte[]) msg.obj); int protocolMode = msg.arg1; broadcastProtocolMode(device, protocolMode); } break; case MESSAGE_VIRTUAL_UNPLUG: { BluetoothDevice device = (BluetoothDevice) msg.obj; if(!virtualUnPlugNative(Utils.getByteAddress(device))) { Log.e(TAG, "Error: virtual unplug native returns false"); } } break; case MESSAGE_SET_PROTOCOL_MODE: { BluetoothDevice device = (BluetoothDevice) msg.obj; byte protocolMode = (byte) msg.arg1; log("sending set protocol mode(" + protocolMode + ")"); if(!setProtocolModeNative(Utils.getByteAddress(device), protocolMode)) { Log.e(TAG, "Error: set protocol mode native returns false"); } } break; case MESSAGE_GET_REPORT: { BluetoothDevice device = (BluetoothDevice) msg.obj; Bundle data = msg.getData(); byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE); byte reportId = data.getByte(BluetoothInputDevice.EXTRA_REPORT_ID); int bufferSize = data.getInt(BluetoothInputDevice.EXTRA_REPORT_BUFFER_SIZE); if(!getReportNative(Utils.getByteAddress(device), reportType, reportId, bufferSize)) { Log.e(TAG, "Error: get report native returns false"); } } break; case MESSAGE_SET_REPORT: { BluetoothDevice device = (BluetoothDevice) msg.obj; Bundle data = msg.getData(); byte reportType = data.getByte(BluetoothInputDevice.EXTRA_REPORT_TYPE); String report = data.getString(BluetoothInputDevice.EXTRA_REPORT); if(!setReportNative(Utils.getByteAddress(device), reportType, report)) { Log.e(TAG, "Error: set report native returns false"); } } break; case MESSAGE_SEND_DATA: { BluetoothDevice device = (BluetoothDevice) msg.obj; Bundle data = msg.getData(); String report = data.getString(BluetoothInputDevice.EXTRA_REPORT); if(!sendDataNative(Utils.getByteAddress(device), report)) { Log.e(TAG, "Error: send data native returns false"); } } break; case MESSAGE_ON_VIRTUAL_UNPLUG: { BluetoothDevice device = getDevice((byte[]) msg.obj); int status = msg.arg1; broadcastVirtualUnplugStatus(device, status); } break; } } };
又见到了本地方法connectHidNative,进入到相应的jni方法中,在Com_android_bluetooth_hid.cpp文件中connectHidNative
static jboolean connectHidNative(JNIEnv *env, jobject object, jbyteArray address) { bt_status_t status; jbyte *addr; jboolean ret = JNI_TRUE; if (!sBluetoothHidInterface) return JNI_FALSE; addr = env->GetByteArrayElements(address, NULL); if (!addr) { ALOGE("Bluetooth device address null"); return JNI_FALSE; } if ((status = sBluetoothHidInterface->connect((bt_bdaddr_t *) addr)) != BT_STATUS_SUCCESS) { ALOGE("Failed HID channel connection, status: %d", status); ret = JNI_FALSE; } env->ReleaseByteArrayElements(address, addr, 0); return ret; }
又是sBluetoothHidInterface,它的实现是在MTK封装的蓝牙库中,连接完毕后会返回连接的信息,在connection_state_callback方法中
static void connection_state_callback(bt_bdaddr_t *bd_addr, bthh_connection_state_t state) { jbyteArray addr; CHECK_CALLBACK_ENV addr = sCallbackEnv->NewByteArray(sizeof(bt_bdaddr_t)); if (!addr) { ALOGE("Fail to new jbyteArray bd addr for HID channel state"); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); return; } sCallbackEnv->SetByteArrayRegion(addr, 0, sizeof(bt_bdaddr_t), (jbyte *) bd_addr); sCallbackEnv->CallVoidMethod(mCallbacksObj, method_onConnectStateChanged, addr, (jint) state); checkAndClearExceptionFromCallback(sCallbackEnv, __FUNCTION__); sCallbackEnv->DeleteLocalRef(addr); }
这个方法会回调HIDService中的onConnectStateChanged方法
private void onConnectStateChanged(byte[] address, int state) { log("onConnectStateChanged:address=" + address + " state=" + state); Message msg = mHandler.obtainMessage(MESSAGE_CONNECT_STATE_CHANGED); msg.obj = address; msg.arg1 = state; mHandler.sendMessage(msg); }
这里又是发送一个消息,接收的地方
private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case MESSAGE_CONNECT_STATE_CHANGED: { BluetoothDevice device = getDevice((byte[]) msg.obj); int halState = msg.arg1; Integer prevStateInteger = mInputDevices.get(device); int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED :prevStateInteger; if(DBG) Log.d(TAG, "MESSAGE_CONNECT_STATE_CHANGED newState:"+ convertHalState(halState)+", prevState:"+prevState); if (okToBroadcastConnectState(device, halState, prevState)) { broadcastConnectionState(device, convertHalState(halState)); } if (halState != CONN_STATE_CONNECTING) { mTargetDevice = null; } else { // CONN_STATE_CONNECTING is received only during // local initiated connection. mTargetDevice = device; } } break; }
这里会通过broadcastConnectionState广播蓝牙的连接结果,
private void broadcastConnectionState(BluetoothDevice device, int newState) { Integer prevStateInteger = mInputDevices.get(device); log("broadcastConnectionState:device=" + device + " prevState=" + prevStateInteger + "->" + "newState=" + newState); int prevState = (prevStateInteger == null) ? BluetoothInputDevice.STATE_DISCONNECTED : prevStateInteger; if (prevState == newState) { Log.w(TAG, "no state change: " + newState); return; } mInputDevices.put(device, newState); /* Notifying the connection state change of the profile before sending the intent for connection state change, as it was causing a race condition, with the UI not being updated with the correct connection state. */ log("Connection state " + device + ": " + prevState + "->" + newState); notifyProfileConnectionStateChanged(device, BluetoothProfile.INPUT_DEVICE, newState, prevState); Intent intent = new Intent(BluetoothInputDevice.ACTION_CONNECTION_STATE_CHANGED); intent.putExtra(BluetoothProfile.EXTRA_PREVIOUS_STATE, prevState); intent.putExtra(BluetoothProfile.EXTRA_STATE, newState); intent.putExtra(BluetoothDevice.EXTRA_DEVICE, device); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); sendBroadcast(intent, BLUETOOTH_PERM); }这里会想系统广播最终连接的结果,至此,蓝牙连接分析完毕。
相关文章推荐
- Android4.4(MT8685)源码蓝牙解析--搜索
- Android4.4(MT8685)源码蓝牙解析--BLE搜索
- Android4.4(MT8685)源码蓝牙解析--配对
- Android4.4(MT8685)源码蓝牙解析--概述
- Android4.4(MT8685)源码WIFI--扫描和连接
- 蓝牙 BCSP 解析 源码分析
- 蓝牙连接电子称以及解析电子称返回的数据
- 飞信源码深度解析——连接
- 蓝牙通话功能源码解析
- 基于源码开机蓝牙一直扫描并自动连接指定的蓝牙设备
- Android4.4 蓝牙源码部分分析
- Android4.4(MT8685)源码WIFI--初始化2
- Android蓝牙源码分析——Gatt连接(一)
- [Android源码解析]蓝牙扫描结果反馈的分析
- Android4.4 Camera Gallery 分离及源码解析
- 在VM中安装Android4.4连接小米手环 之 设置蓝牙
- Curator源码解析(五)连接和重试机制分析
- [Android源码分析]蓝牙文件传输过程解析之UI实现
- 蓝牙文件传输之obex层之上的分析【Android源码解析】
- Memcached源码解析之连接队列