Java Binder
Table of Contents
1. Java Binder
1.1. Parcel
1.1.1. Java Parcel 的 recycle
java 提供了一个 parcel pool, 可以通过 Parcel.obtain/Parcel.recycle 有快速的分配 Parcel. 比如 aidl 生成的代码:
@Override public int test(int x) throws android.os.RemoteException { android.os.Parcel _data = android.os.Parcel.obtain(); android.os.Parcel _reply = android.os.Parcel.obtain(); int _result; try { _data.writeInterfaceToken(DESCRIPTOR); _data.writeInt(x); mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0); _reply.readException(); _result = _reply.readInt(); } finally { _reply.recycle(); // case 1 _data.recycle(); // case 2 } return _result; }
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException { switch (code) { case INTERFACE_TRANSACTION: { reply.writeString(DESCRIPTOR); return true; } case TRANSACTION_test: { data.enforceInterface(DESCRIPTOR); int _arg0; _arg0 = data.readInt(); int _result = this.test(_arg0); reply.writeNoException(); reply.writeInt(_result); // case 3, why data not recycled? return true; } } return super.onTransact(code, data, reply, flags); }
其中 Parcle.recycle 除了和 Parcle pool 有关, 还会释放 binder_buffer.
若一个 parcel 通过 ipcSetDataReference 与 binder_buffer 关联, 则 Parcle.recycle 时调用到底层的 BC_FREE_BUFFER.
client 端的 reply parcel 和 server 端的 data parcel 与 binder_buffer 是关联的.
所以上面代码中, case 1 会释放 client 进程的 binder_buffer, case 2 并不会释放任务 binder_buffer, 因为 proxy 端的 _data 并不与 binder_buffer 关联.
case 3 中的 data 也是需要释放其 binder_buffer 的, 但 aidl 生成代码并没有做, 因为 c++ 一层的 IPCTheadState 会负责调用 parcel 的析构函数.
1.2. AIDL
1.2.1. IXx.stub
stub is essentially a binder, but it do additional two things:
- Imlements some stubs side IXx funtions.
- Auto dispatching to those functions according to unmarshalling result.
stub implement both Binder and IXx.
- It implements Binder, and implements onTransact(), so it can be returned when OnBind, or addService as IBinder… as the stub.
- It implements IXx, so it will implents those stub side functions of IXx, e.g. IXx.foo. stub.onTransact will call IXx.foo according to the unmarshalling result.
1.2.2. IXx.stub.proxy
proxy only implements IXx, and it will take an IBinder as ctor param. It should be taken as a helper utility for the ibinder. So:
- It implements IXx, so it will implements IXx proxy side functions, e.g. IXx.foo, those functions do nothing but marshalling the params and then call remote->transact.
- It take an IBinder as ctor param(the 'remote' var), so it can use the IBinder to do proxy works. e.g. Call ibinder->transact. IXx.asInterface(ibinder) actually call IXx.stub.proxy(ibinder) to convert the ibinder as an proxy interface.
1.3. Java Binder vs. C++ binder
Java binder 是 c++ binder 的简单封装, 其中:
- Java Binder 对应 c++ 的 JavaBBinder
- Java BinderProxy 对应 c++ 的 BpBinder
1.3.1. Java BinderProxy
初始化
// BinderProxy (或者说 BpBinder, binder_ref) 都是在 binder 在 parcel 中传递时被初始化的 // (除了 service_manager) Parcel.java::readStrongBinder nativeReadStrongBinder javaObjectForIBinder(env, parcel->readStrongBinder()) env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);
transact
IBinder.transact() // binder proxy in java is BinderProxy BinderProxy.transact() // native android_os_BinderProxy_transact() // in android_util_Binder.cpp IBinder* target = env->GetIntField(obj, gBinderProxyOffsets.mObject); //target is a BpBinder err=BpBinder->transact()->IPCThreadState->transact() ... signalExceptionForError(env, obj, err);
1.3.2. Java Binder
初始化
Binder() // ctor init(); // native android_os_Binder_init() // c++ JavaBBinderHolder(env, clazz); // JavaBBinderHolder is a lazy holder for JavaBBinder // lazy evaluation of JavaBBinderHolder.get() will init JavaBBinder and set to gBinderOffsets.mObject env->SetIntField(clazz, gBinderOffsets.mObject, (int)jbh);
onTransact
JavaBBinder.onTransact() // c++ env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact, ...) Binder.execTransact() Binder.onTransact() excep = env->ExceptionOccurred(); report_exception(env, excep,...)