您的位置:首页 > 移动开发 > Android开发

Android4.4(MT8685)源码蓝牙解析--连接

2014-12-13 15:31 447 查看
在BluetoothSetting的onResume生命周期方法中会执行updateContent方法,当蓝牙状态为开时,会执行其中这么一段代码:

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);
}
这里会想系统广播最终连接的结果,至此,蓝牙连接分析完毕。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: