最近在学习Android内核设计思想,看书的过程中将一些小知识点积累了一下。
需要解决的问题
- 因为发送请求的Binder client可能是应用程序,所以必须提供Java层的==接口==(需要找出这个接口是什么)
- 每个调用binder服务的程序,不需要亲自去执行如下步骤,所以需要封装如下功能
- 打开binder设备
- 执行mmap
- 通过binder驱动向ServiceManager发送请求
- 返回结果
- 如果每次调用都必须打开servicemanager服务,那么将会消耗很多资源,所以每个进程只能打开一次Binder设备,且只做一次内存映射,所有需要使用binder驱动的线程共享这一资源
相关类的解析
序号 | 相关内容 | 作用 |
---|---|---|
1 | ProcessState | 专门管理每个应用进程当中对应的Binder操作 |
2 | IPCThreadState | 与Bnder驱动进行实际命令通信 |
3 | ServiceManagerProxy | 接口,用来封装ServiceManeger提供的服务 |
4 | ServiceManager.java | 封装了3的类 |
- 采用1和2两个类,已经可以实现与Binder驱动进行通信
- 为了实现这个接口,实现对服务的获取,有以下两步要做:
- 与Binder建立联系
因为已经有了1,2两个类,所以与Binder驱动的通信实际上是通过他们来实现,因此称他们为BpBinder - 向Binder发送命令
Binder机制的简要说明图
ServiceManagerProxy
- 当想要调用getService的时候,需要先查询缓存,再向SM发送请求
public static IBinder getService(String name) {
try {
//cache结构为:private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
//这部分的代码是8.0的代码与书上的不太一致
return Binder.allowBlocking(getIServiceManager().getService(name));
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
- 可以看到,当缓存里没有的时候,需要使用getIServiceManager().getService(name)来获取,而这个方法,返回的也是一个Ibinder对象
private static IServiceManager getIServiceManager() {
if (sServiceManager != null) {
return sServiceManager;
}
// Find the service manager
sServiceManager = ServiceManagerNative
.asInterface(Binder.allowBlocking(BinderInternal.getContextObject()));
return sServiceManager;
}
在这里可以看到,也是先检查时候已经有了IServiceManager,否则也要获取一个新的。这里又出现了一个新的类IserviceManagerNative来获取一个IserviceManager,可以看到,他传入的参数是一个BinderInternal.getContextObject()是一个IBinder的变量,通过这个变量来获取一个IserviceManager,或者再借用这个来使用ServiceManagerProxy()。
static public IServiceManager asInterface(IBinder obj)
{
if (obj == null) {
return null;
}
IServiceManager in =
(IServiceManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ServiceManagerProxy(obj);
}
可以看到,作为与Binder进行交互的接口,需要使用IBinder作为SerivceManagerProxy初始化的一个参数。
public ServiceManagerProxy(IBinder remote) {
mRemote = remote;
}
- 以getService为例:
public IBinder getService(String name) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
IBinder binder = reply.readStrongBinder();
reply.recycle();
data.recycle();
return binder;
}
可以看到,主要分为三步:
- 准备数据 利用Parcel进行封装传递
- IBinder.transact 这个函数就实现了在内部使用ProcessState以及IPCThreadState与Binder进行通信
- 获取结果
- 最后需要注意的一点就是,客户端与服务端所使用的业务代码必须一致,比如:
在IBinder当中定义的业务码为:
int FIRST_CALL_TRANSACTION = 0x00000001;
在ISerivceManager当中定义的业务码为:
int GET_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
int CHECK_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
int ADD_SERVICE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
int LIST_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
int CHECK_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
int SET_PERMISSION_CONTROLLER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+5;