Android Binder原理分析

Android Binder

1. 简介

Binder是Android最主要的进程间通信方式,Binder使用C-S通信方式,实现了高效,安全进程间通信.

2. Binder通信流程

2.1 native层的Binder通信流程

2.1.1 demo

首先看下怎样建立一个native的客户端和服务端,参考文章
Android深入浅出之Binder机制
中的例子

  1. XXXService服务进程初始化工作:
int main()

{

sp<ProcessState> proc(ProcessState::self());
//得到ServiceManagerProxy对象
sp<IServiceManager> sm = defaultServiceManager();
//在ServiceManager中注册服务,客户端调用时ServiceManager可根据名字查找到对应的binder实体,然后Binder驱动在根据请求方与binder实体定义是否为同一进程返回binder代理或者本身
sm->addService(“service.name”,new XXXService());
//打开binder驱动
ProcessState::self()->startThreadPool();
//线程循环从binder驱动读远程请求数据,然后回调BBinder的onTransact处理数据包
IPCThreadState::self()->joinThreadPool();

}

看看XXXService怎么定义呢?

我们需要一个Bn,需要一个Bp,而且Bp不用暴露出来。那么就在BnXXX.cpp中一起实现好了。

另外,XXXService提供自己的功能,例如getXXX调用
  1. 定义继承自IInterface的接口

定义服务可提供的方法,Binder实体和代理都需要实现这个接口

class IXXX: public IInterface
{
    public:
    DECLARE_META_INTERFACE(XXX);
    virtual getXXX() = 0;
    virtual setXXX() = 0;
}
  1. 定义BnXXX
class BnXXX: public BnInterface<IXXX>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
//由于IXXX是个纯虚类,而BnXXX只实现了onTransact函数,所以BnXXX依然是
一个纯虚类
};

IXXX.cpp实现BnXXX,实现onTransact函数,成为Binder实体

IMPLEMENT_META_INTERFACE(XXX, "android.xxx.IXXX");//IMPLEMENT宏
status_t BnXXX::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case GET_XXX: {
            CHECK_INTERFACE(IXXX, data, reply);
           读请求参数
           调用虚函数getXXX()
            return NO_ERROR;
        } break; //SET_XXX类似
  1. 定义BpXXX
    调用Binder代理BpBinder的transact方法,将打包的数据传给Binder驱动
class BpXXX: public BpInterface<IXXX>
{
public:
    BpXXX (const sp<IBinder>& impl)
        : BpInterface< IXXX >(impl)
    {
}

vitural getXXX()
{
  Parcel data, reply;
  data.writeInterfaceToken(IXXX::getInterfaceDescriptor());
  data.writeInt32(pid);
  remote()->transact(GET_XXX, data, &reply);
  return;
}

使用时首先通过ServiceManager得到binder代理对象,然后封装为BpXXX对象,就可以调用getXXX方法发送远程请求了

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("service.name"));
            
    //binder为BpBinder对象,通过interface_cast,以这个binder为参数创建BpXXX,需要在BnXXX中定义asInterface方法将BpBinder对象封装为BpXXX对象
    sp<IXXX> bpService = interface_cast<IXXX>(binder);

2.1.2 重要角色

上面例子中类图如下:

Bn.png
Bp.png
  • IBinder

    BBinder和BpBinder都继承该接口,Binder实体对象和引用对象的基类

  • IInterface

    规定了服务端可提供调用的接口

  • IPCThreadState

    IPCThreadState类负责与Binder驱动程序进行交互,它把从Binder驱动程序读出来的请求作简单的处理后,最后把这个请求扔给BBinder的onTransact函数来进一步处理。

  • BpBinder

    Binder代理,在ProcessState::getStrongProxyForHandle中创建对象.

  • BBinder

    Binder实体对象需要继承自BBinder, IPCThreadState::joinThreadPool循环读取Binder驱动的客户端请求数据发给BBinder::transact处理

  • ServiceManager

    服务端在ServiceManager中注册Binder实体,客户端可以将字符形式的Binder名字传给Binder驱动,Binder通过查询ServiceManager返回Binder的引用到Client.ServiceManager的Binder实体号为0.

    SMgr提供的Binder比较特殊,它没有名字也不需要注册,当一个进程使用BINDER_SET_CONTEXT_MGR命令将自己注册成SMgr时Binder驱动会自动为它创建Binder实体(这就是那只预先造好的鸡)。其次这个Binder的引用在所有Client中都固定为0而无须通过其它手段获得.

图解Android - Binder 和 Service
一文中的类图更为详细和清晰

Bn2.png
Bp2.png

2.1.3 流程

  1. 客户端像ServiceManager查找服务,并得到binder代理过程BpXXX
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("service.name"));
            
    //binder为BpBinder对象,通过interface_cast,以这个binder为参数创建BpXXX,需要在BnXXX中定义asInterface方法将BpBinder对象封装为BpXXX对象
    sp<IXXX> bpService = interface_cast<IXXX>(binder);

getService通过BnServiceManager查找到binder引用句柄,客户端循环读取binder驱动消息IPCThreadState::waitForResponse,将读取到的数据返回到父方法transact()中,进一步返回到IServiceManager的checkService()中,checkService()继续调用reply.readStrongBinder对reply的处理,接着调用unflatten_binder

/frameworks/native/libs/binder/Parcel.cpp

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    // 返回reply中的flat_binder_object
    const flat_binder_object* flat = in.readObject(false);

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                // 这里是BINDER_TYPE_HANDLE,flat->handle为binder引用句柄
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

目标进程("service.name"客户端)与binder(BnServiceManager)实体所在进程不是同一个进程,因此驱动发来的Binder type 为BINDER_TYPE_HANDLE,继续调用getStrongProxyForHandle将binder引用句柄BpBinder对象, 返回给查询服务的客户端,最后通过interface_cast将其转换为BpXXX即服务的代理对象

IServiceManager.checkService->readStrongBinder->unflatten_binder->getStrongProxyForHandle

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    // 通过binder引用句柄查找binder代理缓存项
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {    
            if (handle == 0) {
                ......
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            // 创建binder代理对象    
            b = new BpBinder(handle);
            // 缓存binder代理
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}
  1. 客户端调用BpXXX.getXXX方法->remote.transact(),remote为BpBinder,IPCThreadState::self()->transact像binder驱动发送请求,然后waitForResponse等待结果
  2. 服务端读取binder驱动消息,在IPCThreadState::executeCommand中回调BBinder.onTransact,因为BnXXX继承自BBinder, 继而调用到BnXXX的onTransact,然后在这里调用到服务端的getXXX
  • 客户端和服务端的两个循环:
    1. 客户端: BpBinder::transact writeTransactionData发送数据到binder, 然后循环读取binder驱动的回复消息: IPCThreadState::waitForResponse 读来自binder驱动的命令 cmd = (uint32_t)mIn.readInt32();
    status_t BpBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

//调用IPCThreadState的transact。
//reply是回复包,flags=0
        status_t status = IPCThreadState::self()->transact(

            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
...
}

再看看IPCThreadState的transact函数把

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();
    flags |= TF_ACCEPT_FDS;
    if (err == NO_ERROR) {
        //调用writeTransactionData 发送数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
      if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
      ....等回复
        err = waitForResponse(NULL, NULL);
   ....   
    return err;
}
  1. 服务端:
    服务端循环从binder驱动读取请求, IPCThreadState::joinThreadPool
void IPCThreadState::joinThreadPool(bool isMain)

{
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
     status_t result;
    do {
        int32_t cmd;
         result = talkWithDriver();
         //回调BBinder.onTransact()
         result = executeCommand(cmd);
        }
       } while (result != -ECONNREFUSED && result != -EBADF);
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

流程图:

workflow.PNG

2.2 java层的Binder通信

Binder是一个实体位于Server中的对象,该对象提供了一套方法用以实现对服务的请求,就象类的成员函数。遍布于client中的入口可以看成指向这个binder对象的‘指针’,一旦获得了这个‘指针’就可以调用该对象的方法访问server。

// IMyAidlInterface.aidl
package com.example.myapplication;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

}

IMyAidlInterface.java

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.example.myapplication;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface
{
  /** Default implementation for IMyAidlInterface. */
  public static class Default implements com.example.myapplication.IMyAidlInterface
  {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.example.myapplication.IMyAidlInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.example.myapplication.IMyAidlInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.myapplication.IMyAidlInterface interface,
     * generating a proxy if needed.
     */
    public static com.example.myapplication.IMyAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.myapplication.IMyAidlInterface))) {
        return ((com.example.myapplication.IMyAidlInterface)iin);
      }
      return new com.example.myapplication.IMyAidlInterface.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_basicTypes:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          long _arg1;
          _arg1 = data.readLong();
          boolean _arg2;
          _arg2 = (0!=data.readInt());
          float _arg3;
          _arg3 = data.readFloat();
          double _arg4;
          _arg4 = data.readDouble();
          java.lang.String _arg5;
          _arg5 = data.readString();
          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.example.myapplication.IMyAidlInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
      @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(anInt);
          _data.writeLong(aLong);
          _data.writeInt(((aBoolean)?(1):(0)));
          _data.writeFloat(aFloat);
          _data.writeDouble(aDouble);
          _data.writeString(aString);
          boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.example.myapplication.IMyAidlInterface sDefaultImpl;
    }
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public static boolean setDefaultImpl(com.example.myapplication.IMyAidlInterface impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.myapplication.IMyAidlInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}

定义服务继承自IMyAidlInterface.Stub

public class TestService extends IMyAidlInterface.Stub {
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString){

            }
}
  1. 服务端关联BBinder
    在ServiceManager中添加服务
ServiceManager.addService("test.service", new TestService());

/frameworks/base/core/java/android/os/Binder.java

    public Binder() {
        mObject = getNativeBBinderHolder();
        ... ...
    }

/frameworks/base/core/jni/android_util_Binder.cpp

static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    return (jlong) jbh;
}

创建一个JavaBBinderHolder对象,然后把这个对象的地址保存在上面的Binder类的mObject成员变量中

class JavaBBinderHolder
{
public:
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            mBinder = b;
            ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
                 b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
        }

        return b;
    }

    sp<JavaBBinder> getExisting()
    {
        AutoMutex _l(mLock);
        return mBinder.promote();
    }

private:
    Mutex           mLock;
    wp<JavaBBinder> mBinder;
};

然后ServiceManager.addService() -> ServiceManagerProxy.addService() ->data.writeStrongBinder(service)写binder实体到驱动

   public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
           throws RemoteException {
       Parcel data = Parcel.obtain();
       Parcel reply = Parcel.obtain();
       data.writeInterfaceToken(IServiceManager.descriptor);
       data.writeString(name);
       data.writeStrongBinder(service);
       data.writeInt(allowIsolated ? 1 : 0);
       data.writeInt(dumpPriority);
       mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
       reply.recycle();
       data.recycle();
   }

/frameworks/base/core/java/android/os/Parcel.java

736    public final void writeStrongBinder(IBinder val) {
737        nativeWriteStrongBinder(mNativePtr, val);
738    }

/frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    // Instance of Binder?
    //调用JavaBBinderHolder.get()创建JavaBBinder对象.JavaBBinder中
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh->get(env, obj);
    }

    // Instance of BinderProxy?
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return getBPNativeData(env, obj)->mObject;
    }

    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

JavaBBinder继承自BBinder,成员变量mObject为TestService对象

当addService添加TestService服务时,创建TestService对象,同事创建JavaBBinderHolder对象,地址保存在Binder的mObject成员变量中,调用ServiceManagerProxy 的transact将数据写到驱动时,创建JavaBBinder对象,JavaBBinder继承自BBinder,以便客户端请求发来请求时,回调这个BBinder的onTransact方法

JavaBinder.png
  1. 客户端关联BpBinder

ServiceManager.getService("test.service") -> ServiceManager.rawGetService() -> getIServiceManager().getService(name)

getIServiceManager这里是ServiceManagerProxy对象 ,所以这里看下ServiceManagerProxy.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;
   }

/frameworks/base/core/java/android/os/Parcel.java

   public final IBinder readStrongBinder() {
       return nativeReadStrongBinder(mNativePtr);
   }

/frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{   
    //java Parcel对象转换为native的Parcel对象
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

parcel->readStrongBinder()之前分析这个函数时返回一个BpBinder 对象,那么继续分析javaObjectForIBinder(env, new BpBinder(handle))

/frameworks/base/core/jni/android_util_Binder.cpp

// If the argument is a JavaBBinder, return the Java object that was used to create it.
// Otherwise return a BinderProxy for the IBinder. If a previous call was passed the
// same IBinder, and the original BinderProxy is still alive, return the same BinderProxy.
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    // For the rest of the function we will hold this lock, to serialize
    // looking/creation/destruction of Java proxies for native Binder proxies.
    AutoMutex _l(gProxyLock);

    BinderProxyNativeData* nativeData = gNativeDataCache;
    if (nativeData == nullptr) {
        nativeData = new BinderProxyNativeData();
    }
    // gNativeDataCache is now logically empty.
    //创建BinderProxy对象,对于同一个IBinder对象,一个进程中只有一个BinderProxy,在Java中用一个静态的类似于HashMap的数据结构sProxyMap缓存该BinderProxy对象
    jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
    if (env->ExceptionCheck()) {
        // In the exception case, getInstance still took ownership of nativeData.
        gNativeDataCache = nullptr;
        return NULL;
    }
    BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        // New BinderProxy; we still have exclusive access.
        nativeData->mOrgue = new DeathRecipientList;
        //BinderProxyNativeData.mObject是BpBinder对象的地址
        nativeData->mObject = val;
        gNativeDataCache = nullptr;
        ++gNumProxies;
        if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
            ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
            gProxiesWarned = gNumProxies;
        }
    } else {
        // nativeData wasn't used. Reuse it the next time.
        gNativeDataCache = nativeData;
    }

    return object;
}

javaObjectForIBinder最终返回了一个BinderProxy对象

BinderProxy与BpBinder 建立关联:

BinderProxy.mNativeData对应 native BinderProxyNativeData对象地址,而BinderProxyNativeData中的mObject成员即是BpBinder地址

struct BinderProxyNativeData {
    // Both fields are constant and not null once javaObjectForIBinder returns this as
    // part of a BinderProxy.

    // The native IBinder proxied by this BinderProxy.
    sp<IBinder> mObject;

    // Death recipients for mObject. Reference counted only because DeathRecipients
    // hold a weak reference that can be temporarily promoted.
    sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
};

至此java层的代理对象BinderProxy创建出来了,并且与native的BpBinder建立了一对一的关联


JavaBpBinder.png

2.3 匿名Binder处理流程

一般我们在应用中很少自己向ServiceManager注册Service,而是经常这样用:

Activity中binderService(serviceconnection)然后把一个ServiceConnection对象传给AMS,当远程Service起来后,onBinde方法中返回一个binder对象,再经由AMS传递这个IBinder对象给客户端的Activity,即回调Activity中定义的 ServiceConnection 子类的onServiceConnected 方法,然后在调用IMyAidlInterface.stub.asInterface(binder)将传过来的IBinder(BinderProxy)对象转换为IMyAidlInterface.Stub.Proxy对象

前面的分析都是通过ServiceManager.addService->data.writeStrongBinder(service)将Binder实体写到驱动中;

然后ServiceManager.getService->reply.readStrongBinder得到驱动返回的binder引用,封装为BinderProxy,返回给客户端.

我们常用的onBind传给AMS的是binder实体,那么客户端怎么得到binder代理对象的呢?

bindservice.png

这就涉及到binder对象在进程间传递,Binder驱动根据目标进程和定义binder实体进程是否为一个进程,如果是同一个进程返回binder实体,不是同一个进程则创建binder引用并返回给客户端,并分别设分为不同的type:

  • BINDER_TYPE_BINDER
  • BINDER_TYPE_HANDLE
static void binder_transaction(struct binder_proc *proc,
                               struct binder_thread *thread,
                               struct binder_transaction_data *tr, int reply)
{
     ......
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
                        // 这里类型为BINDER_TYPE_HANDLE
                        struct binder_ref *ref;
                        // 通过binder引用句柄找到binder引用对象
                        ref = binder_get_ref(proc, fp->handle,
                                             fp->type == BINDER_TYPE_HANDLE);
                        ......
                                       
                        if (ref->node->proc == target_proc) {
                                // binder引用对应的binder实体所在进程与客户端进程为同一进程 
                                if (fp->type == BINDER_TYPE_HANDLE)
                                        fp->type = BINDER_TYPE_BINDER;
                                else
                                        fp->type = BINDER_TYPE_WEAK_BINDER;
                                fp->binder = ref->node->ptr;
                                fp->cookie = ref->node->cookie;
                                binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
                                trace_binder_transaction_ref_to_node(t, ref);
                                ......
                        } else {
                                struct binder_ref *new_ref;
                                // 在客户端进程中为服务binder实体创建对应的binder引用
                                new_ref = binder_get_ref_for_node(target_proc, ref->node);
                                if (new_ref == NULL) {
                                        return_error = BR_FAILED_REPLY;
                                                                           goto err_binder_get_ref_for_node_failed;
                                }
                                // 修改flat_binder_object中handle为客户端进程binder引用句柄
                                fp->binder = 0;
                                fp->handle = new_ref->desc;
                                fp->cookie = 0;
                                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                                trace_binder_transaction_ref_to_ref(t, ref,
                                                                    new_ref);
                                binder_debug(BINDER_DEBUG_TRANSACTION,
                                             "        ref %d desc %d -> ref %d desc %d (node %d)\n",
                                             ref->debug_id, ref->desc, new_ref->debug_id,
                                             new_ref->desc, ref->node->debug_id);
                        }
                } break;
                ......
                }
        }
}

然后IPCThreadState根据type封装不同的对象,Binder或者BpBinder

3. 其他话题

3.1 异步管理

用oneway关键字生命的方法或接口客户端只是发送请求给Binder驱动,不必阻塞等待返回结果.在Binder驱动中叫做异步操作.

Binder驱动可以不管三七二十一,统统丢到接收端的to-do队列中一个个处理。但驱动并没有这样做,而是对异步交互做了限流,令其为同步交互让路,具体做法是:对于某个Binder实体,只要有一个异步交互没有处理完毕,例如正在被某个线程处理或还在任意一条to-do队列中排队,那么接下来发给该实体的异步交互包将不再投递到to-do队列中,而是阻塞在驱动为该实体开辟的异步交互接收队列(Binder节点的async_todo域)中,但这期间同步交互依旧不受限制直接进入to-do队列获得处理。一直到该异步交互处理完毕下一个异步交互方可以脱离异步交互队列进入to-do队列中。之所以要这么做是因为同步交互的请求端需要等待返回包,必须迅速处理完毕以免影响请求端的响应速度,而异步交互属于‘发射后不管’,稍微延时一点不会阻塞其它线程。所以用专门队列将过多的异步交互暂存起来,以免突发大量异步交互挤占Server端的处理能力或耗尽线程池里的线程,进而阻塞同步交互。

3.2 线程管理

默认binder线程池大小为15

/frameworks/native/libs/binder/ProcessState.cpp

#define DEFAULT_MAX_BINDER_THREADS 15

3.3 Binder内存限制

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

默认为1M,
可通过手写open,mmap自己定义,最大不超过4M

  • 如何解决binder传输数据过大

    Binder的缓冲区对数据大小的限制明显(不超过1M,而且是15个线程共享这块空间,实际上你操作的线程内,数据超过200K都可能挂掉),可用EventBus(或者自己用RxJava实现一个事件传递)。用EventBus的话,我们可以使用粘性事件,postStickyEvent,然后在下一个Activity中接收。

3.4 内存拷贝

一个进程空间分为 用户空间 & 内核空间(Kernel),所有进程共用1个内核空间:

进程间,用户空间的数据不可共享

进程间,内核空间的数据可共享

在 Android 系统中,这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder 驱动(Binder Dirver)。

Binder通信采用内存映射 mmap() 来实现,内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。

内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。两个空间各自的修改能直接反映在映射的内存区域,从而被对方空间及时感知。也正因为如此,内存映射能够提供对进程间通信的支持。

Binder 驱动使用 mmap() 并不是为了在物理介质和用户空间之间建立映射,而是用来在内核空间创建数据接收的缓存空间。

Android Binder机制全面解析 文章关于内存映射介绍比较详细

3.5 Binder对象生命周期

Binder驱动采取引用计数,没有引用,Binder对象生命周期结束

参考文档


Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析


Binder之获取服务


IBinder对象在进程间传递的形式


[007]一次Binder通信最大可以传输多大的数据?

Android Binder

1. 简介

Binder是Android最主要的进程间通信方式,Binder使用C-S通信方式,实现了高效,安全进程间通信.

2. Binder通信流程

2.1 native层的Binder通信流程

2.1.1 demo

首先看下怎样建立一个native的客户端和服务端,参考文章
Android深入浅出之Binder机制
中的例子

  1. XXXService服务进程初始化工作:
int main()

{

sp<ProcessState> proc(ProcessState::self());
//得到ServiceManagerProxy对象
sp<IServiceManager> sm = defaultServiceManager();
//在ServiceManager中注册服务,客户端调用时ServiceManager可根据名字查找到对应的binder实体,然后Binder驱动在根据请求方与binder实体定义是否为同一进程返回binder代理或者本身
sm->addService(“service.name”,new XXXService());
//打开binder驱动
ProcessState::self()->startThreadPool();
//线程循环从binder驱动读远程请求数据,然后回调BBinder的onTransact处理数据包
IPCThreadState::self()->joinThreadPool();

}

看看XXXService怎么定义呢?

我们需要一个Bn,需要一个Bp,而且Bp不用暴露出来。那么就在BnXXX.cpp中一起实现好了。

另外,XXXService提供自己的功能,例如getXXX调用
  1. 定义继承自IInterface的接口

定义服务可提供的方法,Binder实体和代理都需要实现这个接口

class IXXX: public IInterface
{
    public:
    DECLARE_META_INTERFACE(XXX);
    virtual getXXX() = 0;
    virtual setXXX() = 0;
}
  1. 定义BnXXX
class BnXXX: public BnInterface<IXXX>
{
public:
    virtual status_t    onTransact( uint32_t code,
                                    const Parcel& data,
                                    Parcel* reply,
                                    uint32_t flags = 0);
//由于IXXX是个纯虚类,而BnXXX只实现了onTransact函数,所以BnXXX依然是
一个纯虚类
};

IXXX.cpp实现BnXXX,实现onTransact函数,成为Binder实体

IMPLEMENT_META_INTERFACE(XXX, "android.xxx.IXXX");//IMPLEMENT宏
status_t BnXXX::onTransact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    switch(code) {
        case GET_XXX: {
            CHECK_INTERFACE(IXXX, data, reply);
           读请求参数
           调用虚函数getXXX()
            return NO_ERROR;
        } break; //SET_XXX类似
  1. 定义BpXXX
    调用Binder代理BpBinder的transact方法,将打包的数据传给Binder驱动
class BpXXX: public BpInterface<IXXX>
{
public:
    BpXXX (const sp<IBinder>& impl)
        : BpInterface< IXXX >(impl)
    {
}

vitural getXXX()
{
  Parcel data, reply;
  data.writeInterfaceToken(IXXX::getInterfaceDescriptor());
  data.writeInt32(pid);
  remote()->transact(GET_XXX, data, &reply);
  return;
}

使用时首先通过ServiceManager得到binder代理对象,然后封装为BpXXX对象,就可以调用getXXX方法发送远程请求了

    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("service.name"));
            
    //binder为BpBinder对象,通过interface_cast,以这个binder为参数创建BpXXX,需要在BnXXX中定义asInterface方法将BpBinder对象封装为BpXXX对象
    sp<IXXX> bpService = interface_cast<IXXX>(binder);

2.1.2 重要角色

上面例子中类图如下:

[图片上传失败...(image-a79b51-1574222476315)]
[图片上传失败...(image-aa6762-1574222476315)]

  • IBinder

    BBinder和BpBinder都继承该接口,Binder实体对象和引用对象的基类

  • IInterface

    规定了服务端可提供调用的接口

  • IPCThreadState

    IPCThreadState类负责与Binder驱动程序进行交互,它把从Binder驱动程序读出来的请求作简单的处理后,最后把这个请求扔给BBinder的onTransact函数来进一步处理。

  • BpBinder

    Binder代理,在ProcessState::getStrongProxyForHandle中创建对象.

  • BBinder

    Binder实体对象需要继承自BBinder, IPCThreadState::joinThreadPool循环读取Binder驱动的客户端请求数据发给BBinder::transact处理

  • ServiceManager

    服务端在ServiceManager中注册Binder实体,客户端可以将字符形式的Binder名字传给Binder驱动,Binder通过查询ServiceManager返回Binder的引用到Client.ServiceManager的Binder实体号为0.

    SMgr提供的Binder比较特殊,它没有名字也不需要注册,当一个进程使用BINDER_SET_CONTEXT_MGR命令将自己注册成SMgr时Binder驱动会自动为它创建Binder实体(这就是那只预先造好的鸡)。其次这个Binder的引用在所有Client中都固定为0而无须通过其它手段获得.

图解Android - Binder 和 Service
一文中的类图更为详细和清晰

[图片上传失败...(image-9811a9-1574222476315)]
[图片上传失败...(image-6b4b-1574222476315)]

2.1.3 流程

  1. 客户端像ServiceManager查找服务,并得到binder代理过程BpXXX
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> binder = sm->getService(String16("service.name"));
            
    //binder为BpBinder对象,通过interface_cast,以这个binder为参数创建BpXXX,需要在BnXXX中定义asInterface方法将BpBinder对象封装为BpXXX对象
    sp<IXXX> bpService = interface_cast<IXXX>(binder);

getService通过BnServiceManager查找到binder引用句柄,客户端循环读取binder驱动消息IPCThreadState::waitForResponse,将读取到的数据返回到父方法transact()中,进一步返回到IServiceManager的checkService()中,checkService()继续调用reply.readStrongBinder对reply的处理,接着调用unflatten_binder

/frameworks/native/libs/binder/Parcel.cpp

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    // 返回reply中的flat_binder_object
    const flat_binder_object* flat = in.readObject(false);

    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = reinterpret_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE:
                // 这里是BINDER_TYPE_HANDLE,flat->handle为binder引用句柄
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

目标进程("service.name"客户端)与binder(BnServiceManager)实体所在进程不是同一个进程,因此驱动发来的Binder type 为BINDER_TYPE_HANDLE,继续调用getStrongProxyForHandle将binder引用句柄BpBinder对象, 返回给查询服务的客户端,最后通过interface_cast将其转换为BpXXX即服务的代理对象

IServiceManager.checkService->readStrongBinder->unflatten_binder->getStrongProxyForHandle

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;

    AutoMutex _l(mLock);

    // 通过binder引用句柄查找binder代理缓存项
    handle_entry* e = lookupHandleLocked(handle);
    if (e != NULL) {
        // We need to create a new BpBinder if there isn't currently one, OR we
        // are unable to acquire a weak reference on this current one.  See comment
        // in getWeakProxyForHandle() for more info about this.
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {    
            if (handle == 0) {
                ......
                Parcel data;
                status_t status = IPCThreadState::self()->transact(
                        0, IBinder::PING_TRANSACTION, data, NULL, 0);
                if (status == DEAD_OBJECT)
                   return NULL;
            }
            // 创建binder代理对象    
            b = new BpBinder(handle);
            // 缓存binder代理
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            // This little bit of nastyness is to allow us to add a primary
            // reference to the remote proxy when this team doesn't have one
            // but another team is sending the handle to us.
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }

    return result;
}
  1. 客户端调用BpXXX.getXXX方法->remote.transact(),remote为BpBinder,IPCThreadState::self()->transact像binder驱动发送请求,然后waitForResponse等待结果
  2. 服务端读取binder驱动消息,在IPCThreadState::executeCommand中回调BBinder.onTransact,因为BnXXX继承自BBinder, 继而调用到BnXXX的onTransact,然后在这里调用到服务端的getXXX
  • 客户端和服务端的两个循环:
    1. 客户端: BpBinder::transact writeTransactionData发送数据到binder, 然后循环读取binder驱动的回复消息: IPCThreadState::waitForResponse 读来自binder驱动的命令 cmd = (uint32_t)mIn.readInt32();
    status_t BpBinder::transact(

    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)

{

//调用IPCThreadState的transact。
//reply是回复包,flags=0
        status_t status = IPCThreadState::self()->transact(

            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }
...
}

再看看IPCThreadState的transact函数把

status_t IPCThreadState::transact(int32_t handle,
                                  uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags)
{
    status_t err = data.errorCheck();
    flags |= TF_ACCEPT_FDS;
    if (err == NO_ERROR) {
        //调用writeTransactionData 发送数据
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
      if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
      ....等回复
        err = waitForResponse(NULL, NULL);
   ....   
    return err;
}
  1. 服务端:
    服务端循环从binder驱动读取请求, IPCThreadState::joinThreadPool
void IPCThreadState::joinThreadPool(bool isMain)

{
     mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
     status_t result;
    do {
        int32_t cmd;
         result = talkWithDriver();
         //回调BBinder.onTransact()
         result = executeCommand(cmd);
        }
       } while (result != -ECONNREFUSED && result != -EBADF);
    mOut.writeInt32(BC_EXIT_LOOPER);
    talkWithDriver(false);
}

流程图:

[图片上传失败...(image-5c1a74-1574222476315)]

2.2 java层的Binder通信

Binder是一个实体位于Server中的对象,该对象提供了一套方法用以实现对服务的请求,就象类的成员函数。遍布于client中的入口可以看成指向这个binder对象的‘指针’,一旦获得了这个‘指针’就可以调用该对象的方法访问server。

// IMyAidlInterface.aidl
package com.example.myapplication;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString);

}

IMyAidlInterface.java

/*
 * This file is auto-generated.  DO NOT MODIFY.
 */
package com.example.myapplication;
// Declare any non-default types here with import statements

public interface IMyAidlInterface extends android.os.IInterface
{
  /** Default implementation for IMyAidlInterface. */
  public static class Default implements com.example.myapplication.IMyAidlInterface
  {
    /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
    {
    }
    @Override
    public android.os.IBinder asBinder() {
      return null;
    }
  }
  /** Local-side IPC implementation stub class. */
  public static abstract class Stub extends android.os.Binder implements com.example.myapplication.IMyAidlInterface
  {
    private static final java.lang.String DESCRIPTOR = "com.example.myapplication.IMyAidlInterface";
    /** Construct the stub at attach it to the interface. */
    public Stub()
    {
      this.attachInterface(this, DESCRIPTOR);
    }
    /**
     * Cast an IBinder object into an com.example.myapplication.IMyAidlInterface interface,
     * generating a proxy if needed.
     */
    public static com.example.myapplication.IMyAidlInterface asInterface(android.os.IBinder obj)
    {
      if ((obj==null)) {
        return null;
      }
      android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
      if (((iin!=null)&&(iin instanceof com.example.myapplication.IMyAidlInterface))) {
        return ((com.example.myapplication.IMyAidlInterface)iin);
      }
      return new com.example.myapplication.IMyAidlInterface.Stub.Proxy(obj);
    }
    @Override public android.os.IBinder asBinder()
    {
      return this;
    }
    @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
    {
      java.lang.String descriptor = DESCRIPTOR;
      switch (code)
      {
        case INTERFACE_TRANSACTION:
        {
          reply.writeString(descriptor);
          return true;
        }
        case TRANSACTION_basicTypes:
        {
          data.enforceInterface(descriptor);
          int _arg0;
          _arg0 = data.readInt();
          long _arg1;
          _arg1 = data.readLong();
          boolean _arg2;
          _arg2 = (0!=data.readInt());
          float _arg3;
          _arg3 = data.readFloat();
          double _arg4;
          _arg4 = data.readDouble();
          java.lang.String _arg5;
          _arg5 = data.readString();
          this.basicTypes(_arg0, _arg1, _arg2, _arg3, _arg4, _arg5);
          reply.writeNoException();
          return true;
        }
        default:
        {
          return super.onTransact(code, data, reply, flags);
        }
      }
    }
    private static class Proxy implements com.example.myapplication.IMyAidlInterface
    {
      private android.os.IBinder mRemote;
      Proxy(android.os.IBinder remote)
      {
        mRemote = remote;
      }
      @Override public android.os.IBinder asBinder()
      {
        return mRemote;
      }
      public java.lang.String getInterfaceDescriptor()
      {
        return DESCRIPTOR;
      }
      /**
           * Demonstrates some basic types that you can use as parameters
           * and return values in AIDL.
           */
      @Override public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException
      {
        android.os.Parcel _data = android.os.Parcel.obtain();
        android.os.Parcel _reply = android.os.Parcel.obtain();
        try {
          _data.writeInterfaceToken(DESCRIPTOR);
          _data.writeInt(anInt);
          _data.writeLong(aLong);
          _data.writeInt(((aBoolean)?(1):(0)));
          _data.writeFloat(aFloat);
          _data.writeDouble(aDouble);
          _data.writeString(aString);
          boolean _status = mRemote.transact(Stub.TRANSACTION_basicTypes, _data, _reply, 0);
          if (!_status && getDefaultImpl() != null) {
            getDefaultImpl().basicTypes(anInt, aLong, aBoolean, aFloat, aDouble, aString);
            return;
          }
          _reply.readException();
        }
        finally {
          _reply.recycle();
          _data.recycle();
        }
      }
      public static com.example.myapplication.IMyAidlInterface sDefaultImpl;
    }
    static final int TRANSACTION_basicTypes = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
    public static boolean setDefaultImpl(com.example.myapplication.IMyAidlInterface impl) {
      if (Stub.Proxy.sDefaultImpl == null && impl != null) {
        Stub.Proxy.sDefaultImpl = impl;
        return true;
      }
      return false;
    }
    public static com.example.myapplication.IMyAidlInterface getDefaultImpl() {
      return Stub.Proxy.sDefaultImpl;
    }
  }
  /**
       * Demonstrates some basic types that you can use as parameters
       * and return values in AIDL.
       */
  public void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat, double aDouble, java.lang.String aString) throws android.os.RemoteException;
}

定义服务继承自IMyAidlInterface.Stub

public class TestService extends IMyAidlInterface.Stub {
    void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
            double aDouble, String aString){

            }
}
  1. 服务端关联BBinder
    在ServiceManager中添加服务
ServiceManager.addService("test.service", new TestService());

/frameworks/base/core/java/android/os/Binder.java

    public Binder() {
        mObject = getNativeBBinderHolder();
        ... ...
    }

/frameworks/base/core/jni/android_util_Binder.cpp

static jlong android_os_Binder_getNativeBBinderHolder(JNIEnv* env, jobject clazz)
{
    JavaBBinderHolder* jbh = new JavaBBinderHolder();
    return (jlong) jbh;
}

创建一个JavaBBinderHolder对象,然后把这个对象的地址保存在上面的Binder类的mObject成员变量中

class JavaBBinderHolder
{
public:
    sp<JavaBBinder> get(JNIEnv* env, jobject obj)
    {
        AutoMutex _l(mLock);
        sp<JavaBBinder> b = mBinder.promote();
        if (b == NULL) {
            b = new JavaBBinder(env, obj);
            mBinder = b;
            ALOGV("Creating JavaBinder %p (refs %p) for Object %p, weakCount=%" PRId32 "\n",
                 b.get(), b->getWeakRefs(), obj, b->getWeakRefs()->getWeakCount());
        }

        return b;
    }

    sp<JavaBBinder> getExisting()
    {
        AutoMutex _l(mLock);
        return mBinder.promote();
    }

private:
    Mutex           mLock;
    wp<JavaBBinder> mBinder;
};

然后ServiceManager.addService() -> ServiceManagerProxy.addService() ->data.writeStrongBinder(service)写binder实体到驱动

   public void addService(String name, IBinder service, boolean allowIsolated, int dumpPriority)
           throws RemoteException {
       Parcel data = Parcel.obtain();
       Parcel reply = Parcel.obtain();
       data.writeInterfaceToken(IServiceManager.descriptor);
       data.writeString(name);
       data.writeStrongBinder(service);
       data.writeInt(allowIsolated ? 1 : 0);
       data.writeInt(dumpPriority);
       mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
       reply.recycle();
       data.recycle();
   }

/frameworks/base/core/java/android/os/Parcel.java

736    public final void writeStrongBinder(IBinder val) {
737        nativeWriteStrongBinder(mNativePtr, val);
738    }

/frameworks/base/core/jni/android_os_Parcel.cpp

static void android_os_Parcel_writeStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr, jobject object)
{
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        const status_t err = parcel->writeStrongBinder(ibinderForJavaObject(env, object));
        if (err != NO_ERROR) {
            signalExceptionForError(env, clazz, err);
        }
    }
}

sp<IBinder> ibinderForJavaObject(JNIEnv* env, jobject obj)
{
    if (obj == NULL) return NULL;

    // Instance of Binder?
    //调用JavaBBinderHolder.get()创建JavaBBinder对象.JavaBBinder中
    if (env->IsInstanceOf(obj, gBinderOffsets.mClass)) {
        JavaBBinderHolder* jbh = (JavaBBinderHolder*)
            env->GetLongField(obj, gBinderOffsets.mObject);
        return jbh->get(env, obj);
    }

    // Instance of BinderProxy?
    if (env->IsInstanceOf(obj, gBinderProxyOffsets.mClass)) {
        return getBPNativeData(env, obj)->mObject;
    }

    ALOGW("ibinderForJavaObject: %p is not a Binder object", obj);
    return NULL;
}

JavaBBinder继承自BBinder,成员变量mObject为TestService对象

当addService添加TestService服务时,创建TestService对象,同事创建JavaBBinderHolder对象,地址保存在Binder的mObject成员变量中,调用ServiceManagerProxy 的transact将数据写到驱动时,创建JavaBBinder对象,JavaBBinder继承自BBinder,以便客户端请求发来请求时,回调这个BBinder的onTransact方法

[图片上传失败...(image-b5e075-1574222476315)]

  1. 客户端关联BpBinder

ServiceManager.getService("test.service") -> ServiceManager.rawGetService() -> getIServiceManager().getService(name)

getIServiceManager这里是ServiceManagerProxy对象 ,所以这里看下ServiceManagerProxy.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;
   }

/frameworks/base/core/java/android/os/Parcel.java

   public final IBinder readStrongBinder() {
       return nativeReadStrongBinder(mNativePtr);
   }

/frameworks/base/core/jni/android_os_Parcel.cpp

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr)
{   
    //java Parcel对象转换为native的Parcel对象
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

parcel->readStrongBinder()之前分析这个函数时返回一个BpBinder 对象,那么继续分析javaObjectForIBinder(env, new BpBinder(handle))

/frameworks/base/core/jni/android_util_Binder.cpp

// If the argument is a JavaBBinder, return the Java object that was used to create it.
// Otherwise return a BinderProxy for the IBinder. If a previous call was passed the
// same IBinder, and the original BinderProxy is still alive, return the same BinderProxy.
jobject javaObjectForIBinder(JNIEnv* env, const sp<IBinder>& val)
{
    if (val == NULL) return NULL;

    if (val->checkSubclass(&gBinderOffsets)) {
        // It's a JavaBBinder created by ibinderForJavaObject. Already has Java object.
        jobject object = static_cast<JavaBBinder*>(val.get())->object();
        LOGDEATH("objectForBinder %p: it's our own %p!\n", val.get(), object);
        return object;
    }

    // For the rest of the function we will hold this lock, to serialize
    // looking/creation/destruction of Java proxies for native Binder proxies.
    AutoMutex _l(gProxyLock);

    BinderProxyNativeData* nativeData = gNativeDataCache;
    if (nativeData == nullptr) {
        nativeData = new BinderProxyNativeData();
    }
    // gNativeDataCache is now logically empty.
    //创建BinderProxy对象,对于同一个IBinder对象,一个进程中只有一个BinderProxy,在Java中用一个静态的类似于HashMap的数据结构sProxyMap缓存该BinderProxy对象
    jobject object = env->CallStaticObjectMethod(gBinderProxyOffsets.mClass,
            gBinderProxyOffsets.mGetInstance, (jlong) nativeData, (jlong) val.get());
    if (env->ExceptionCheck()) {
        // In the exception case, getInstance still took ownership of nativeData.
        gNativeDataCache = nullptr;
        return NULL;
    }
    BinderProxyNativeData* actualNativeData = getBPNativeData(env, object);
    if (actualNativeData == nativeData) {
        // New BinderProxy; we still have exclusive access.
        nativeData->mOrgue = new DeathRecipientList;
        //BinderProxyNativeData.mObject是BpBinder对象的地址
        nativeData->mObject = val;
        gNativeDataCache = nullptr;
        ++gNumProxies;
        if (gNumProxies >= gProxiesWarned + PROXY_WARN_INTERVAL) {
            ALOGW("Unexpectedly many live BinderProxies: %d\n", gNumProxies);
            gProxiesWarned = gNumProxies;
        }
    } else {
        // nativeData wasn't used. Reuse it the next time.
        gNativeDataCache = nativeData;
    }

    return object;
}

javaObjectForIBinder最终返回了一个BinderProxy对象

BinderProxy与BpBinder 建立关联:

BinderProxy.mNativeData对应 native BinderProxyNativeData对象地址,而BinderProxyNativeData中的mObject成员即是BpBinder地址

struct BinderProxyNativeData {
    // Both fields are constant and not null once javaObjectForIBinder returns this as
    // part of a BinderProxy.

    // The native IBinder proxied by this BinderProxy.
    sp<IBinder> mObject;

    // Death recipients for mObject. Reference counted only because DeathRecipients
    // hold a weak reference that can be temporarily promoted.
    sp<DeathRecipientList> mOrgue;  // Death recipients for mObject.
};

至此java层的代理对象BinderProxy创建出来了,并且与native的BpBinder建立了一对一的关联
[图片上传失败...(image-224b4b-1574222476315)]

2.3 匿名Binder处理流程

一般我们在应用中很少自己向ServiceManager注册Service,而是经常这样用:

Activity中binderService(serviceconnection)然后把一个ServiceConnection对象传给AMS,当远程Service起来后,onBinde方法中返回一个binder对象,再经由AMS传递这个IBinder对象给客户端的Activity,即回调Activity中定义的 ServiceConnection 子类的onServiceConnected 方法,然后在调用IMyAidlInterface.stub.asInterface(binder)将传过来的IBinder(BinderProxy)对象转换为IMyAidlInterface.Stub.Proxy对象

前面的分析都是通过ServiceManager.addService->data.writeStrongBinder(service)将Binder实体写到驱动中;

然后ServiceManager.getService->reply.readStrongBinder得到驱动返回的binder引用,封装为BinderProxy,返回给客户端.

我们常用的onBind传给AMS的是binder实体,那么客户端怎么得到binder代理对象的呢?

[图片上传失败...(image-d75cd9-1574222476316)]

这就涉及到binder对象在进程间传递,Binder驱动根据目标进程和定义binder实体进程是否为一个进程,如果是同一个进程返回binder实体,不是同一个进程则创建binder引用并返回给客户端,并分别设分为不同的type:

  • BINDER_TYPE_BINDER
  • BINDER_TYPE_HANDLE
static void binder_transaction(struct binder_proc *proc,
                               struct binder_thread *thread,
                               struct binder_transaction_data *tr, int reply)
{
     ......
                case BINDER_TYPE_HANDLE:
                case BINDER_TYPE_WEAK_HANDLE: {
                        // 这里类型为BINDER_TYPE_HANDLE
                        struct binder_ref *ref;
                        // 通过binder引用句柄找到binder引用对象
                        ref = binder_get_ref(proc, fp->handle,
                                             fp->type == BINDER_TYPE_HANDLE);
                        ......
                                       
                        if (ref->node->proc == target_proc) {
                                // binder引用对应的binder实体所在进程与客户端进程为同一进程 
                                if (fp->type == BINDER_TYPE_HANDLE)
                                        fp->type = BINDER_TYPE_BINDER;
                                else
                                        fp->type = BINDER_TYPE_WEAK_BINDER;
                                fp->binder = ref->node->ptr;
                                fp->cookie = ref->node->cookie;
                                binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
                                trace_binder_transaction_ref_to_node(t, ref);
                                ......
                        } else {
                                struct binder_ref *new_ref;
                                // 在客户端进程中为服务binder实体创建对应的binder引用
                                new_ref = binder_get_ref_for_node(target_proc, ref->node);
                                if (new_ref == NULL) {
                                        return_error = BR_FAILED_REPLY;
                                                                           goto err_binder_get_ref_for_node_failed;
                                }
                                // 修改flat_binder_object中handle为客户端进程binder引用句柄
                                fp->binder = 0;
                                fp->handle = new_ref->desc;
                                fp->cookie = 0;
                                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                                trace_binder_transaction_ref_to_ref(t, ref,
                                                                    new_ref);
                                binder_debug(BINDER_DEBUG_TRANSACTION,
                                             "        ref %d desc %d -> ref %d desc %d (node %d)\n",
                                             ref->debug_id, ref->desc, new_ref->debug_id,
                                             new_ref->desc, ref->node->debug_id);
                        }
                } break;
                ......
                }
        }
}

然后IPCThreadState根据type封装不同的对象,Binder或者BpBinder

3. 其他话题

3.1 异步管理

用oneway关键字生命的方法或接口客户端只是发送请求给Binder驱动,不必阻塞等待返回结果.在Binder驱动中叫做异步操作.

Binder驱动可以不管三七二十一,统统丢到接收端的to-do队列中一个个处理。但驱动并没有这样做,而是对异步交互做了限流,令其为同步交互让路,具体做法是:对于某个Binder实体,只要有一个异步交互没有处理完毕,例如正在被某个线程处理或还在任意一条to-do队列中排队,那么接下来发给该实体的异步交互包将不再投递到to-do队列中,而是阻塞在驱动为该实体开辟的异步交互接收队列(Binder节点的async_todo域)中,但这期间同步交互依旧不受限制直接进入to-do队列获得处理。一直到该异步交互处理完毕下一个异步交互方可以脱离异步交互队列进入to-do队列中。之所以要这么做是因为同步交互的请求端需要等待返回包,必须迅速处理完毕以免影响请求端的响应速度,而异步交互属于‘发射后不管’,稍微延时一点不会阻塞其它线程。所以用专门队列将过多的异步交互暂存起来,以免突发大量异步交互挤占Server端的处理能力或耗尽线程池里的线程,进而阻塞同步交互。

3.2 线程管理

默认binder线程池大小为15

/frameworks/native/libs/binder/ProcessState.cpp

#define DEFAULT_MAX_BINDER_THREADS 15

3.3 Binder内存限制

#define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)

默认为1M,
可通过手写open,mmap自己定义,最大不超过4M

  • 如何解决binder传输数据过大

    Binder的缓冲区对数据大小的限制明显(不超过1M,而且是15个线程共享这块空间,实际上你操作的线程内,数据超过200K都可能挂掉),可用EventBus(或者自己用RxJava实现一个事件传递)。用EventBus的话,我们可以使用粘性事件,postStickyEvent,然后在下一个Activity中接收。

3.4 内存拷贝

一个进程空间分为 用户空间 & 内核空间(Kernel),所有进程共用1个内核空间:

进程间,用户空间的数据不可共享

进程间,内核空间的数据可共享

在 Android 系统中,这个运行在内核空间,负责各个用户进程通过 Binder 实现通信的内核模块就叫 Binder 驱动(Binder Dirver)。

Binder通信采用内存映射 mmap() 来实现,内存映射简单的讲就是将用户空间的一块内存区域映射到内核空间。映射关系建立后,用户对这块内存区域的修改可以直接反应到内核空间;反之内核空间对这段区域的修改也能直接反应到用户空间。

内存映射能减少数据拷贝次数,实现用户空间和内核空间的高效互动。两个空间各自的修改能直接反映在映射的内存区域,从而被对方空间及时感知。也正因为如此,内存映射能够提供对进程间通信的支持。

Binder 驱动使用 mmap() 并不是为了在物理介质和用户空间之间建立映射,而是用来在内核空间创建数据接收的缓存空间。

Android Binder机制全面解析 文章关于内存映射介绍比较详细

3.5 Binder对象生命周期

Binder驱动采取引用计数,没有引用,Binder对象生命周期结束

参考文档


Android系统进程间通信Binder机制在应用程序框架层的Java接口源代码分析


Binder之获取服务


IBinder对象在进程间传递的形式


[007]一次Binder通信最大可以传输多大的数据?

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270