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閱讀 227,488評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,034評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,327評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,554評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,337評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,883評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,975評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,114評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,625評論 1 332
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,555評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,737評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,244評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,973評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,615評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,343評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,699評論 2 370