上一篇文章中,分析了Bluetooth.apk启动过程,启动Bluetooth.apk时,一般启动了AdapterService这一对应的服务。查看package/app/Bluetooth的源码,里面主要是一些具体的协议,其中每一个协议对应一个具体的服务。那么,这些服务是何时以及如何启动的呢?
在android 5.1 中,打开蓝牙时,在AdapterService的setProfileServiceState中就会逐个启动支持的服务,方法如下:
private void setProfileServiceState(Class[] services, int state) {
if (state != BluetoothAdapter.STATE_ON && state != BluetoothAdapter.STATE_OFF) {
debugLog("setProfileServiceState() - Invalid state, leaving...");
return;
}
int expectedCurrentState= BluetoothAdapter.STATE_OFF;
int pendingState = BluetoothAdapter.STATE_TURNING_ON;
if (state == BluetoothAdapter.STATE_OFF) {
expectedCurrentState= BluetoothAdapter.STATE_ON;
pendingState = BluetoothAdapter.STATE_TURNING_OFF;
}
for (int i=0; i
但是在android 6.0 中,在打开蓝牙,最后调用AdapterService的
setGattProfileServiceState的仅仅启动GattService这一服务,紧接着的调用
BluetoothAdapter的enable方法, notifyUserAction方法最后会调用setProfileServiceState方法启动其他的服务,但是这样做好像意义不大。
public boolean enable() {
android.util.SeempLog.record(56);
int state = STATE_OFF;
if (isEnabled() == true){
if (DBG) Log.d(TAG, "enable(): BT is already enabled..!");
return true;
}
//Use service interface to get the exact state
if (mService != null) {
try {
state = mService.getState();
} catch (RemoteException e) {Log.e(TAG, "", e);}
}
if (state == BluetoothAdapter.STATE_BLE_ON) { // 蓝牙已经打开
Log.e(TAG, "BT is in BLE_ON State");
notifyUserAction(true); // 发出通知
return true;
}
try {
return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
在android 6.0中,其他协议的服务启动我有些疑惑,到底在什么时候启动的呢?
请看下节。
在手机里面,这些服务应该都有获取,并且服务端和客户端已经绑定,那么代码在哪儿呢?
在这里android 5.1和android 6.0还是有些微小的区别,代码路径不一样,在android6.0 中,设置里面之外,还有一个文件夹,路径如下,
frameworks\base\packages\SettingsLib\src\com\android\settingslib\bluetooth
包含的文件:
基本上每一个profile文件就对应;而在android 5.1 中,这些文件都包含在
packages\apps\Settings\src\com\android\settings\bluetooth之中。其他的基本原理是完全一样的。
启动设置,打开蓝牙设置,设置里的协议客户端就会创建,然后启动服务端并且和服务端绑定在一起,流程图如下:
这里以PanProfile为例来说明, PanProfile的构造函数如下,
PanProfile(Context context) {
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
adapter.getProfileProxy(context, new PanServiceListener(),
BluetoothProfile.PAN);
}
private BluetoothPan mService;
private boolean mIsProfileReady;
private final class PanServiceListener
implements BluetoothProfile.ServiceListener {
public void onServiceConnected(int profile, BluetoothProfile proxy) {
if (V) Log.d(TAG,"Bluetooth service connected");
mService = (BluetoothPan) proxy;
mIsProfileReady=true;
}
public void onServiceDisconnected(int profile) {
if (V) Log.d(TAG,"Bluetooth service disconnected");
mIsProfileReady=false;
}
}
getProfileProxy方法下节再论述。
在蓝牙开发中,服务端的各种协议已经封装好了,如果是我们自己开发,我们怎么样才能调用呢?对应的客户端是啥呢?开发时,比如现在想进行蓝牙通话,获取蓝牙通话的客户端对象。
private final BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
private BluetoothHeadsetClient mHfpClient = null;
一般在组件的oncreate方法中调用enableHFP方法来获取蓝牙通话的客户端对象,代码如下:
private void enableHFP() {
mBluetoothAdapter.getProfileProxy(getApplicationContext(), new ServiceListener() {
public void onServiceConnected(int profile,BluetoothProfile proxy) {
if (profile == BluetoothProfile.HEADSET_CLIENT) {
android.util.Log.d("fang ", "init mBluetoothHeadset");
mHfpClient = (BluetoothHeadsetClient) proxy;
}
}
public void onServiceDisconnected(int profile) {
if (profile == BluetoothProfile.HEADSET_CLIENT) {
mHfpClient = null;
}
}
}, BluetoothProfile.HEADSET_CLIENT);
}
首先看看getProfileProxy方法
public boolean getProfileProxy(Context context, BluetoothProfile.ServiceListener listener,
int profile) {
if (context == null || listener == null) return false;
if (profile == BluetoothProfile.HEADSET) {
BluetoothHeadset headset = new BluetoothHeadset(context, listener);
return true;
} else if (profile == BluetoothProfile.A2DP) {
BluetoothA2dp a2dp = new BluetoothA2dp(context, listener);
return true;
} else if (profile == BluetoothProfile.A2DP_SINK) {
BluetoothA2dpSink a2dpSink = new BluetoothA2dpSink(context, listener);
return true;
} else if (profile == BluetoothProfile.AVRCP_CONTROLLER) {
BluetoothAvrcpController avrcp = new BluetoothAvrcpController(context, listener);
return true;
} else if (profile == BluetoothProfile.INPUT_DEVICE) {
BluetoothInputDevice iDev = new BluetoothInputDevice(context, listener);
return true;
} else if (profile == BluetoothProfile.PAN) {
BluetoothPan pan = new BluetoothPan(context, listener);
return true;
} else if (profile == BluetoothProfile.DUN) {
BluetoothDun dun = new BluetoothDun(context, listener);
return true;
} else if (profile == BluetoothProfile.HEALTH) {
BluetoothHealth health = new BluetoothHealth(context, listener);
return true;
} else if (profile == BluetoothProfile.MAP) {
BluetoothMap map = new BluetoothMap(context, listener);
return true;
} else if (profile == BluetoothProfile.HEADSET_CLIENT) {
BluetoothHeadsetClient headsetClient = new BluetoothHeadsetClient(context, listener);
return true;
} else if (profile == BluetoothProfile.SAP) {
BluetoothSap sap = new BluetoothSap(context, listener);
return true;
} else if (profile == BluetoothProfile.HID_DEVICE) {
BluetoothHidDevice hidd = new BluetoothHidDevice(context, listener);
return true;
} else {
return false;
}
}
这一共有12个服务,对应12个协议。这些客户端的类都是继承自
BluetoothProfile 典型的工厂模式,得到不同的实例对象。以
BluetoothHeadsetClient协议为例,论述如下流程,
BluetoothHeadsetClient的构造函数如下:
BluetoothHeadsetClient(Context context, ServiceListener l) {
mContext = context;
mServiceListener = l;
mAdapter = BluetoothAdapter.getDefaultAdapter();
IBluetoothManager mgr = mAdapter.getBluetoothManager();
if (mgr != null) {
try {
mgr.registerStateChangeCallback(mBluetoothStateChangeCallback);
} catch (RemoteException e) {
Log.e(TAG,"",e);
}
}
doBind();
}
boolean doBind() {
Intent intent = new Intent(IBluetoothHeadsetClient.class.getName());
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, mConnection, 0,
android.os.Process.myUserHandle())) {
Log.e(TAG, "Could not bind to Bluetooth Headset Client Service with " + intent);
return false;
}
return true;
}
AndroidManifest.xml中的HeadsetClientService定义如下,
bindServiceAsUser挂进程绑定在此就不论述了,直接看mConnection对象的方法,
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "Proxy object connected");
mService = IBluetoothHeadsetClient.Stub.asInterface(service);
if (mServiceListener != null) {
mServiceListener.onServiceConnected(BluetoothProfile.HEADSET_CLIENT,
BluetoothHeadsetClient.this);
}
}
@Override
public void onServiceDisconnected(ComponentName className) {
if (DBG) Log.d(TAG, "Proxy object disconnected");
mService = null;
if (mServiceListener != null) {
mServiceListener.onServiceDisconnected(BluetoothProfile.HEADSET_CLIENT);
}
}
};
所以,最后的结果是将运行于第三方apk的BluetoothHeadsetClient对象和运行于Bluetooth.apk的HeadsetClientService对应起来了。
mServiceListener就是enableHFP方法中的匿名ServiceListener类的对象。看到此,恍然大悟了, getProfileProxy方法根据第三个参数首先创建对应的客户端类,然后将客户端和Bluetooth.apk的服务端进行连接,最后返回客户端,这是典型的C/S模式。这样,12个客户端和服务端协议一一对应了,但是上层蓝牙不止这12个协议。好了,现在每个协议的客户端可以获取了,万事俱备了,接下来看看每个协议的使用场景和功能吧。
最开始的时候,每个协议的客户端都有一个connect方法,但是我一直都不知道是什么时候调用的,设备到底是如何连接的。过了很久很久之后才发现,还是在设置里,点击已配对的设备就可以进行连接,最后是每个协议独立的连接。这是基于android6.0,但是5.1的几乎完全一样,还是以BluetoothPan为例说明连接的部分流程,流程图如下
步骤其实很简单,就是从协议的客户端跨进程调用到对应的服务端,然后通过JNI机制调用C/C++最后来完成连接。只有设备的协议连接起来了,才可以进行进一步的操作。