首先看SystemServer.java 里 蓝牙服务的启动。
if (isEmulator) {
Slog.i(TAG, "No Bluetooh Service (emulator)");
} else if (mFactoryTestMode == FactoryTest.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "No Bluetooth Service (factory test)");
} else if (!context.getPackageManager().hasSystemFeature
(PackageManager.FEATURE_BLUETOOTH)) {
Slog.i(TAG, "No Bluetooth Service (Bluetooth Hardware Not Present)");
} else if (disableBluetooth) {
Slog.i(TAG, "Bluetooth Service disabled by config");
} else {
Slog.i(TAG, "Bluetooth Service");
class BluetoothManagerService extends IBluetoothManager.Stub {
public BluetoothService(Context context) {
super(context);
mBluetoothManagerService = new BluetoothManagerService(context);
}
/**
* Retrieve the Bluetooth Adapter's name and address and save it in
* in the local cache
*/
private void loadStoredNameAndAddress() {
if (DBG) Log.d(TAG, "Loading stored name and address");
if (mContext.getResources().getBoolean
(com.android.internal.R.bool.config_bluetooth_address_validation) &&
Settings.Secure.getInt(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDR_VALID, 0) == 0) {
// if the valid flag is not set, don't load the address and name
if (DBG) Log.d(TAG, "invalid bluetooth name and address stored");
return;
}
mName = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_NAME);
mAddress = Settings.Secure.getString(mContentResolver, SECURE_SETTINGS_BLUETOOTH_ADDRESS);
if (DBG) Log.d(TAG, "Stored bluetooth Name=" + mName + ",Address=" + mAddress);
}
判断蓝牙是否打开,是否处于飞行模式。 /**
* Returns true if airplane mode is currently on
*/
private final boolean isAirplaneModeOn() {
return Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, 0) == 1;
}
/**
* Returns true if the Bluetooth saved state is "on"
*/
private final boolean isBluetoothPersistedStateOn() {
int bluetoothState = Settings.Global.getInt(mContentResolver,
Settings.Global.BLUETOOTH_ON, 0);
if (DBG) Log.d(TAG, "isBluetoothPersistedStateOn, bluetoothState = " + bluetoothState);
return (bluetoothState != BLUETOOTH_OFF);
}
* Get a handle to the default local Bluetooth adapter.
* Currently Android only supports one Bluetooth adapter, but the API
* could be extended to support more. This will always return the default
* adapter.
* @return the default local adapter, or null if Bluetooth is not supported
* on this hardware platform
*/
public static synchronized BluetoothAdapter getDefaultAdapter() {
if (sAdapter == null) {
IBinder b = ServiceManager.getService(BLUETOOTH_MANAGER_SERVICE);
if (b != null) {
IBluetoothManager managerService = IBluetoothManager.Stub.asInterface(b);
sAdapter = new BluetoothAdapter(managerService);
} else {
Log.e(TAG, "Bluetooth binder is null");
}
}
return sAdapter;
这里我们首先来总结下AIDL .AIDL 可以跨进程访问其他应用程序。(广播【应用A 在manifest.xml 注册Action.应用B发送指定的广播。A就可以收到信息。这种通信是单向的】、ContentProvider 通过URI 接口暴露数据给其他应用)。官方的解释是“当你允许不同的客户端访问你的服务并且需要处理多线程问题时你才必须使用AIDL”.可见AIDL 是处理多线程多客户端并发访问。
AIDL 的使用
(1)定义IRemoteService.aidl 文件
// IRemoteService.aidl
package com.example.android;
// Declare any non-default types here with import statements
/** Example service interface */
interface IRemoteService {
/** Request the process ID of this service, to do evil things with it. */
int getPid();
/** Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
}
这段代码也是官方文档的。命名为IRemoteService.aidl,放在com.example.android包下(这个可以随意),保存后Android编译器会在gen目录下自动生成IRemoteService.java文件。第二、定义我们的服务,DDService.java,并且需要在AndroidManifest.xml中注册,并添加“duanqing.test.aidl” 的ACTION
package com.example.service;
import com.example.android.IRemoteService;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.Process;
public class DDService extends Service {
@Override
public void onCreate() {
super.onCreate();
System.out.println("DDService onCreate........" + "Thread: " + Thread.currentThread().getName());
}
@Override
public IBinder onBind(Intent arg0) {
System.out.println("DDService onBind");
return mBinder;
}
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public int getPid(){
System.out.println("Thread: " + Thread.currentThread().getName());
System.out.println("DDService getPid ");
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
System.out.println("Thread: " + Thread.currentThread().getName());
System.out.println("basicTypes aDouble: " + aDouble +" anInt: " + anInt+" aBoolean " + aBoolean+" aString " + aString);
}
};
}
这样我们的服务端就完成了,把服务端运行到模拟器(或者手机上),等一会可以看一下打印信息,重点看“线程名”package com.example.aidlclient;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.view.View;
import com.example.android.IRemoteService;
public class MainActivity extends Activity {
private IRemoteService remoteService;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
remoteService = IRemoteService.Stub.asInterface(service);//这个地方获得方法重要
try {
int pid = remoteService.getPid();
int currentPid = Process.myPid();
System.out.println("currentPID: " + currentPid +" remotePID: " + pid);
remoteService.basicTypes(12, 1223, true, 12.2f, 12.3, "我们的爱,我明白");
} catch (RemoteException e) {
e.printStackTrace();
}
System.out.println("bind success! " + remoteService.toString());
}
};
/**
* 监听按钮点击
* @param view
*/
public void buttonClick(View view) {
System.out.println("begin bindService");
Intent intent = new Intent("duanqing.test.aidl");
bindService(intent, conn, Context.BIND_AUTO_CREATE);
}
@Override
protected void onDestroy() {
super.onDestroy();
unbindService(conn);
}
}
看服务端打印,DDService onCreate..........Thread: main,主线程,当客户端调用服务端getPid方法时,服务端是在Thread: Binder2中执行,当客户端调用服务端basicType方法时,服务端是在Thread:Binder1中执行.
了解了AIDL后,继续看bluetoothAdapter.enable()的方法究竟走了哪里?
@RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
public boolean enable() {
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 {
if (DBG) Log.d(TAG, "enable");
return mManagerService.enable();
} catch (RemoteException e) {Log.e(TAG, "", e);}
return false;
}
查看代码发现调用的是mManagerService.enable()。继续追踪发现mManagerService 是IBluetoothManager 的对象。根据ADIL 的知识知一定会有个类(或者是内部匿名实现类)实现IBluetoothManager.Stub接口。 重写了enable()这个方法。通过全局搜素发现BluetoothManagerService.java 刚好满足以上所说。
class BluetoothManagerService extends IBluetoothManager.Stub {
继续追踪它是如何实现enable()方法。在enable()方法里追踪到handleEnable(boolean quietMode).其中一段代码如下所示:
if ((mBluetooth == null) && (!mBinding)) {
if (DBG) Log.d(TAG, "Bind AdapterService");//根据注释得知绑定的是AdapterService服务
//Start bind timeout and bind
Message timeoutMsg=mHandler.obtainMessage(MESSAGE_TIMEOUT_BIND);
mHandler.sendMessageDelayed(timeoutMsg,TIMEOUT_BIND_MS);
mConnection.setGetNameAddressOnly(false);
Intent i = new Intent(IBluetooth.class.getName());
if (!doBind(i, mConnection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT,
UserHandle.CURRENT)) {
mHandler.removeMessages(MESSAGE_TIMEOUT_BIND);
Log.e(TAG, "Fail to bind to: " + IBluetooth.class.getName());
} else {
mBinding = true;
}
}
根据代码看是证实了确实启动一个service,并且是IBluetooth.class.getName()相关的。追踪doBind()方法,就是绑定一个服务。
boolean doBind(Intent intent, ServiceConnection conn, int flags, UserHandle user) {
ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
intent.setComponent(comp);
if (comp == null || !mContext.bindServiceAsUser(intent, conn, flags, user)) {
Log.e(TAG, "Fail to bind to: " + intent);
return false;
}
return true;
}
接下来我们看看传递的参数conn 的类是怎么实现的。
private class BluetoothServiceConnection implements ServiceConnection {
private boolean mGetNameAddressOnly;
public void setGetNameAddressOnly(boolean getOnly) {
mGetNameAddressOnly = getOnly;
}
public boolean isGetNameAddressOnly() {
return mGetNameAddressOnly;
}
public void onServiceConnected(ComponentName className, IBinder service) {
if (DBG) Log.d(TAG, "BluetoothServiceConnection: " + className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_CONNECTED);
// TBD if (className.getClassName().equals(IBluetooth.class.getName())) {
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
// } else if (className.getClassName().equals(IBluetoothGatt.class.getName())) {
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Log.e(TAG, "Unknown service connected: " + className.getClassName());
return;
}
msg.obj = service;
mHandler.sendMessage(msg);
}
public void onServiceDisconnected(ComponentName className) {
// Called if we unexpected disconnected.
if (DBG) Log.d(TAG, "BluetoothServiceConnection, disconnected: " +
className.getClassName());
Message msg = mHandler.obtainMessage(MESSAGE_BLUETOOTH_SERVICE_DISCONNECTED);
if (className.getClassName().equals("com.android.bluetooth.btservice.AdapterService")) {
msg.arg1 = SERVICE_IBLUETOOTH;
} else if (className.getClassName().equals("com.android.bluetooth.gatt.GattService")) {
msg.arg1 = SERVICE_IBLUETOOTHGATT;
} else {
Log.e(TAG, "Unknown service disconnected: " + className.getClassName());
return;
}
mHandler.sendMessage(msg);
}
}
主要做的就是 在让msg 携带不同的参数值。我们看看MESSAGE_BLUETOOTH_SERVICE_CONNECTED这一个消息的值为SERVICE_IBLUETOOTH是怎么处理的。追踪发现如下这两句有用的代码。
(1)mBluetooth = IBluetooth.Stub.asInterface(service);mBluetooth 指向的父类是IBluetooth这是典型的AIDL 里获取远程服务的对象。
(2)mBluetooth.enable() ;.这是获取对象后真正调用远程服务里实现AIDL的接口里方法。绕了一大圈,打开蓝牙目前还是调用mBluetooth.enable() 这个方法。我们继续查找究竟是谁实现了AIDL的接口,重写了这个方法。通过全局搜素发现AdapterService.java 这个服务里有个静态内部类实现了接口,重写了这个方法。源代码注释是这样说,对于Binder 类型的接口实现声明必须是一个静态类,并且在构造函数中传递对应Service(AdapterService)的实例。并且当这个Service关闭的时候,和它相关的必须显式移除。否则会发生内存溢出在服务反复的开启和关闭之中。
private static class AdapterServiceBinder extends IBluetooth.Stub {
public boolean enable() {
if ((Binder.getCallingUid() != Process.SYSTEM_UID) &&
(!Utils.checkCaller())) {
Log.w(TAG, "enable() - Not allowed for non-active user and non system user");
return false;
}
AdapterService service = getService();
if (service == null) return false;
return service.enable();
}
继续追踪AdapterService.java 的enable()方法。最终调用如下:public synchronized boolean enable(boolean quietMode) {
enforceCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM, "Need BLUETOOTH ADMIN permission");
debugLog("enable() - Enable called with quiet mode status = " + mQuietmode);
mQuietmode = quietMode;
Message m = mAdapterStateMachine.obtainMessage(AdapterState.BLE_TURN_ON);
mAdapterStateMachine.sendMessage(m);
return true;
}
mAdapterStateMachine(状态机)是AdapterState.java的对象。源码注释这样说:状态机处理蓝牙的状态。OnState 打开状态。OffState 关闭状态,也是初始化状态。在该类里找到内部类OffState的 processMessage(Message msg)方法里我们看看是如何处理AdapterState.BLE_TURN_ON 的消息。
switch(msg.what) {
case BLE_TURN_ON:
notifyAdapterStateChange(BluetoothAdapter.STATE_BLE_TURNING_ON);
mPendingCommandState.setBleTurningOn(true);
transitionTo(mPendingCommandState);
sendMessageDelayed(BLE_START_TIMEOUT, BLE_START_TIMEOUT_DELAY);
adapterService.BleOnProcessStart();
break;
这个方法又回到了AdapterService.java这个类里。它里面会用到JNI的接口,如 initNative(),classInitNative(),enableNative().下面我们再补充另外一个Android知识JNI.这张Android 的平台框架图我已经看到过10次以上。可是从来没有跟随源码阅读到Librairies库,所以对于这张图的理解还是停留在只是见过的阶段。我也不知道我这点能力到底能对它的认知有多深,我也不知道我用这样记录阅读源码情况、整合网络源码分析资源的方式对于我今后的职业生涯有什么帮助?我甚至不知道我将来到底还会不会从事编程职业。但是我唯一清楚的是不管是爱还是讨厌还是平淡对于目前的职业,不管我现在负责的蓝牙模块是有多不重要或者别人看来多没技术含量或者太难做早已被部分人放弃的模块,只要我有时间有精力我必须要咬着牙啃下去,直到吃出别人不一样的味道。存在我内心一致的信仰就是不管多么普通的事情你都要用心去做到你自己水平的极致就好。
我们看到的是上层Applicaton层和Application Framework 层都是用Java 编写。据了解众多Libraries都是c/c++ 编写。所以上层的Java 调用底层的c do