如何利用关键问题,感性理解Binder
1.service_manager的启动
用来管理服务,所有的系统服务都会注册到这里。
本质上是服务的引用BpBinder的管理者,可以将服务引用BpBinder分发给其他Client。
当然了,这种分发在内核中是传递binder_node到其他进程,并在该进程中建立新的binder_ref和 BpBinder
思考:
service_manager是如何成为管理者的
{
必须是公共入口
提供了存储服务
}
如何与管理者通信 {
/dev/binder休眠唤醒
数据协议
}
复制代码
2.BpBinder、BBinder、IPCThreadState、ProcessState之间的关系
进程复用的底层与/dev/Binder的交互逻辑,全部放到了IPCThreadState中,数据的分发是靠Parcel + binder_transaction_data -> binder_write_read协议来实现的,所以只要将数据打包好,自然能够发送到目的地。
ProcessState主要缓存了BpBinder,实现放到IPCThreadState中也没有什么问题。
3.BpInterface、BnInterface、BpBinder、BBinder之间的关系
C++层的aidl而已,这个理解应用比较到位吧
Java层的
IXXXService.Stub继承自Binder映射了JNI中的JavaBBinder
IXXXService.Proxy继承自BinderProxy,从IPCProcessState传过来的Parcel,最终解析成为BpBinder,转化为了Java层的BinderProxy。
复制代码
4.如何划分Binder架构层次
Java层:
Binder.exeTransact
复制代码
C++层:
(BnInterface)
JavaBBinder.onTransact (data)
BBinder.transact (data、BBinder -> Parcel)
IPCThreadState::getAndExecuteCommand (Parcel -> binder_transaction_data ->
binder_write_read )
IPCThreadState::talkWifiDriver + waitForResponse
复制代码
内核层:
ioctl
/dev/binder (binder_write_read -> binder_transaction_data -> binder_write_read)
binder_ioctl
binder_write_read
binder_write_thread
binder_transaction
复制代码
5.一次有效的通信是如何实现的
无论是Java层还是C++层的上层调用,都是利用BpBinder -> IPCThreadState来发送数据,利用BBinder-> IPCThreadState来接收数据。一次有效的数据通信涉及到几个方面:
1.BBinder实体的注册
2.BpBinder引用的获取
3.利用上层数据(data + flat_binder_object + 协议) + 传输handle 进行传输
4.内核驱动数据转发实现
6.如和注册到实名binder的
要注册实名binder(service_manager进行一次add,其他binder先得获得引用,然后执行add操作) A.service_manager中执行add,先获取其引用BpBinder(0),Java层构建了ServiceManager_Proxy->Binder_Proxy->BpBinder(0),可以直接通信了。
1.一个服务在Java层注册
利用aidl生成Stub和Proxy,实现Stub的接口,利用ServiceManager.addService(name, Stub)注册到ServiceManager中.代码如下:
142 public void addService(String name, IBinder service, boolean allowIsolated)
143 throws RemoteException {
144 Parcel data = Parcel.obtain();
145 Parcel reply = Parcel.obtain();
146 data.writeInterfaceToken(IServiceManager.descriptor);
147 data.writeString(name);
148 data.writeStrongBinder(service);
149 data.writeInt(allowIsolated ? 1 : 0);
150 mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
151 reply.recycle();
152 data.recycle();
153 }
复制代码
Java层的Binder写到Parcel中变成了ibinderForJavaObject(env, object),即转换成了JavaBBinder,并与Stub构建了关系关系,即JavaBBinder (BBinder) <-> Stub (Binder)
2.一个服务在C++层注册
利用BpInterface和BnInterface约定关系,实现BnXXXService,并实现其中的code与函数调用关系。BnXXXService是BBinder的子类,最后调用C++层的IServiceManager.defaultServiceManager.addService(name, BBinder)来注册。
virtual status_t addService(const String16& name, const sp<IBinder>& service,
bool allowIsolated) {
Parcel data, reply;
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
复制代码
这里还需要记录一点:Binder节点基本上是第一次注册到实名Binder时,在通信的两个进程中,分别在内核中创建的binder_node。当然了,在发送端是创建binder_node节点,而在接收端是拷贝binder_node节点。
7.如何拿到引用以及引用如何找到目标
要拿到引用,只要跟实名binder通信一次(servcie_manager是一次、其他实名binder是两次) 如果要从service_manager中拿到引用,首先在IPCThreadState中找到BpBinder(0),利用其构造getService的通信handle + data + target binder -> Parcel -> binder_transaction_data -> binder_write_read,利用通信协议将binder_transaction_data.handle传递到内核,内核根据handle去查找binder_ref (两处查找,一个是binder_proc->refs_by_desc,一个是binder_context_mgr_node),进而查找到目标binder_node。利用binder_node通信的过程:唤醒目标binder线程、取数据、解析,于是到了service_manager的上层了,后续不详述了。
1.Java层如何找到服务
ServiceManager.getService在Java层是带有缓存的,如果有缓存那么直接取,如果没有那么利用ServiceManagerProxy -> BinderProxy -> BpBinder(0)来获取服务,看下代码吧。最后得到的是一个经JNI转换的BinderProxy。native得到的是BpBinder,而Java很显然不能使用,了解Binder层次的话,很自然能够确定一定是Binder_Proxy。
118 public IBinder getService(String name) throws RemoteException {
119 Parcel data = Parcel.obtain();
120 Parcel reply = Parcel.obtain();
121 data.writeInterfaceToken(IServiceManager.descriptor);
122 data.writeString(name);
123 mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
124 IBinder binder = reply.readStrongBinder();
125 reply.recycle();
126 data.recycle();
127 return binder;
128 }
复制代码
2.在C++层找到服务
同样利用BpInterface来找到服务,先构建了一个BpServiceManager (继承自BpInterface和IServiceManager),然后通信就好了。最后得到的是一个BpBinder
gDefaultServiceManager = interface_cast<IServiceManager>(ProcessState::self()->getContextObject(NULL));
146 virtual sp<IBinder> getService( const String16& name) const
147 {
148 Parcel data, reply;
149 data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
150 data.writeString16(name);
151 remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
152 return reply.readStrongBinder();
153 }
复制代码
8.Java层和C++层的映射关系
Binder构造时:
JavaBBinder 放到了JavaBBinderHolder 的mBinder域, JavaBBinderHolder放到了 Binder.mObject 域,而Binder引用放到了 JavaBBinder.mObject,因此Binder和JavaBBinder建立了Java到C++的双向关联引用关系。
BinderProxy构造时:
基本在C++里面出发,将BpBinder放到BinderProxy.mObject,而例如ServiceManagerProxy将BinderProxy放到了ServiceManagerProxy.mRemote域中。
9.Android层服务的注册和引用
首先注册Service到SystemServer进程,然后在Context中静态初始化Client,应用利用Context.getSystemServer即可找到IVibratorService.Proxy了。