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:

  1. Imlements some stubs side IXx funtions.
  2. Auto dispatching to those functions according to unmarshalling result.

stub implement both Binder and IXx.

  1. It implements Binder, and implements onTransact(), so it can be returned when OnBind, or addService as IBinder… as the stub.
  2. 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:

  1. 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.
  2. 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 的简单封装, 其中:

  1. Java Binder 对应 c++ 的 JavaBBinder
  2. 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,...)
    

Author: [email protected]
Date: 2017-04-04 Tue 00:00
Last updated: 2017-12-06 Wed 17:42

知识共享许可协议