以 AMS 为例
//ActivityManagerService.java
public void setSystemProcess( ){
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
}
//ServiceManager.java
public static addService(String name, IBinder service, boolean allowIsolated){
getIServiceManager( ).addService(name, service, allowIsloted)
}
private static IServiceManager getIServiceManager(){
sServiceManager = ServiceManagerNative.getInterface(BinderInternal.getContextObject);
}
//android_utils_Binder.cpp
//该方法返回一个 Java 层的BinderProxy 对象,同时持有下面的 BpBinder(handle = 0)的句柄
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz){
sp<IBinder> b = ProcessState::self()->getContextObject(NULL);
return javaObjectForIBinder(env, b);
}
//ProcessState.cpp
//改方法返回一个 BpBinder(handle = 0)
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>&){
return getStrongProxyForHandle(0);
}
//ServiceManagerNative.java
static public IServiceManager asInterface(IBinder obj){
return new ServiceManagerProxy(obj)
}
经过一系列的反应,最后再 AMS 进程中,service_manager 在 AMS 中的代理表现为
ServiceManagerNativeBidnerProxy.java 对象内部有成员变量 mObject,表现为 native 层BpBinder.cpp对象。BpBinder.cpp 对象内部有一个 handle 为0,表示 service_manager 在 binder 驱动中的注册编号
--重头戏---
addService( )@ServiveManager.java
⤵️
addService( )@ServiceManagerNative$ServiceManagerProxy.java
⤵️
transact(ADD_SERVICE_TRANSACTION)@Binder$BinderProxy.java
⤵️
android_os_BinderProxy_transact()@android_util_Binder.cpp
⤵️
transact( )@BpBinder.cpp
⤵️
transact( )@IPCThreadState.cpp
⤵️
ioctl()@IPCThreadState.cpp使用的 cmd 就是 BINDER_WRITE_READ
接下来看每一层的数据打包过程。
①
//参数,name = "activity", service 是 ActivityManagerService, allowIsolated=true
public void addService(String name,IBinder service, boolean allowIsolated){
Parcel data = Parcel.obtain( )
Parcel reply = Parcel.obtain( )
data.writeInterfaceToken(IServiceManager.descriptor);
data.writeString(name);
data.writeStrongBinder(service);
data.writeInt(allowIsolated? 1 : 0);
mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
reply.recycle( );
data.recycle( );
}
关于 Parcel 打包,参见link
此时 Parcel data 打包了一些基础数据类型,将 ActivityManagerService.java 封装成了 flat_binder_object 打包进 Parcel。
//BinderProxy
//code 就是 ADD_SERVICE_TRANSACT, data 是封装了请求信息,reply 没有内容,flags=0
public boolean transact(int code, Parcel data, Parcel reply, int flags){
return transactNative(code, data, reply, flags)
}
//android_utils_Binder.cpp
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj, jint code, jobject dataObject, jobject replyObj, jint flags){
//从 Parcel.java 中的 mNativePtr 获得 native 层的 Parcel.cpp
Parcel* data = parcelForJavaObject(env, dataObj);
Parcel* reply = parcelForJavaObject(env, replyObj);
//从 BinderProxy.java 获得 BpBinder
//此处 BpBinder 中的 handle = 0,代表 service_manager
IBinder* target = (IBinder*) env->GetLongField(obj, gBinderProxyOffsets.mObject);
status_t err = target->transact(code, *data, reply, flags)
}
//BpBinder.cpp
status BpBinder::transact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags){
status_t status = IPCThreadState::self()->transact(mHandle, code, data, reply. flags);
}
//IPCThreadState.cpp
status_t IPCThreadState::transact(int32_t handle, uint32_T code, const Parcel& data, Parcel* reply, uint32_t flags){
//表示通讯 cmd 是 BC_TRANSACTION,表示向 Binder 驱动发送消息
//handle = 0 表示向 handle = 0 的服务,即 service_manager 发送消息
//code = ADD_SERVICE,该码用来给目标服务表示要调用的方法
//data 包含了请求的参数
//于是 handle,code,data 包含了目标对象,目标方法,方法参数
writeTransactionData(BC_TRANSACTION, flags, handle, code, data);
//真正发起 RPC 通讯
waitForResponse(reply)
}
status_t IPCThreadStatus::writeTransactionData(int32_t cmd, uint32_t binderFlags, int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer){
//IPCThreadStatus 层的包装协议是 binder_transaction_data,在目标进程也按照该协议进行拆箱
//cmd = BC_TRANSACTION 是该层的命令协议
//封装的 binder_transaction_data 连同 cmd 打包进了 mOut
binder_transaction_data tr;
tr.target.ptr = 0;
tr.target.handle = handle;
tr.code = code;
tr.flags = binderFlags;
tr.cookie=0
tr.sender_pid = 0;
tr.sender_euid = 0;
tr.data_size = data.ipcDataSize( );
tr.data.ptr.buffer = data.ipcData();
tr.offsets_size = data.ipcObjecCount()*sizeof(binder_size_t);
tr.data.ptr.offet = data.ipcObjects( );
mOut.writeInt32(cmd)
mout.write(&tr, sizeof(tr))
}
status_t IPCThreadStatus::waitForResponse(Parcel * reply, status_t *acquireResult){
//进行 PRC
talkWithDriver();
//处理 RPC 返回结果
...
}
status_t IPCThreadStatus::talkWithDriver(boolean doReceive){
//与 Binder 驱动交换数据
binder_write_read bwr;
bwr.write_siez = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data()
ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr)
}
- 一级通讯 cmd 为 BINDER_WRITE_READ,像 Binder 驱动表示此次 RPC 需求读写内容
- 二级 cmd 为 BC_TRANSACTION
- 三级 cmd 为 ADD_VERSION
接下来看通讯的解包装
//binder.c,此时是在 kernel中运行
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long args){
//获得发起请求的进程 binder_proc 结构
struct binder_proc *proc = filp->private_data;
struct binder_thread *thread;
//用户空间的 binder_write_read 的指针
void __user *ubuf = (void __user *)arg;
//kernal将当前进程,即发起请求的进程进行休眠。直到被唤醒
//如果 binder_stop_on_user_error < 2则直接跳过不会挂起
wait_event_interruptible(binder_user_error_wait, binder_stop_on_user_error <2);
//获得发起 RPC 请求的现场
thread = binder_get_thread(proc);
switch(cmd){
//符合一级通讯 cmd
case BINDER_WRITE_READ{
struct binder_write_read bwr;
//将用户进程的 binder_write_read 拷贝到内核空间
copy_from_user(&bwr, ubuf, sizeof(bwr))
//本次请求符合
if(bwr.write_size >0){
binder_thread_write(proc, thread, bwr.write_buffer, bwr.write_size, &bwr.write_consumed);
}
}
}
}
int binder_thread_write(struct binder_proc *proc, struct binder_thread *thread, binder_uintptr_t binder_buffer, size_t size, binder_size_t *consumed){
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t) binder_buffer;
void __user *ptr = buffer+*consumed;//此时指针子 bwr 中 write_buffer 的 data
void __user *end = buffer+size
swicth(cmd){
//二级通讯 cmd
case BC_TRANSACTION:
binder_transaction_data tr;
//再次拆箱,拆出 binder_transaction_data
copy_from_user(&tr, ptr, sizeof(tr));
//真正发起 RPC,这里可以看到,binder 驱动将 BC_TRANSACTION换成了 BC_REPLY
binder_transaction(proc, thread, &tr, cmd = BC_REPLY);
}
}
binder_transaction( )函数格外复杂。简而言之是根据请求中目标进程的 handle(此处为 0),多啰嗦一句,所有的 Binder 实体经过 Binder 驱动,都会被记录到一个 binder_node 节点并且插入到 Binder 驱动的 2 颗红黑树(key 不同)。在这里因为 handle 为 0,于是找到对应的 Binder 实体对应的进程,随后创建一个事务binder_transaction,将其挂载到目标进程 traget_list 即 todo 队列。随后唤醒目标进程。
在此处,调用wait_event_interruptible()尝试休眠 AMS 进程是,因为 binder_stop_on_user_error < 2成立,因此不会休眠进程。在进行binder_thread_write()进行 rpc 调用后,在binder_thread_read()会通过wait_event_freezable_exclusive()休眠当前线程,知道 service_manager.cpp 返回请求结果。
而 service_manager.cpp 进入 loop 后,就是一直阻塞在binder_thread_read()中的wait_event_freezable_exclusive()去尝试获取请求。当 binder_has_proc_work()符合条件,即进程所造的 todo 队列有内容,才会唤醒。
当 AMS 将此次 RPC 请求投递到 service_manager.cpp 所在的 todo 队列,service_manager.cpp 就会被唤醒,读取处理请求。同事 AMS 会在wait_event_freezable_exclusive()挂起线程,直到有某个事务(其他进程或者 service_manager.cpp 返回了结果)被投递到 AMS 进程所在的 todo 队列
Binder 的通讯大致过程都相似,如果是同步请求 A 进程像 Binder 发送 RPC,内核休眠 A 进程,唤醒目标 B 进程,处理请求,回复 Binder 驱动,唤醒 A 进程。
网友评论