Binder的Native實現libbinder


libbinder – Binder的Native實現

出於性能和代碼統一性的角度考慮,Binder IPC並不Java和Native環境里各實現一次,而只是分別在不同的執行環境里提供使用的接口。使用Binder的Java代碼,通過一些使用Binder的Java類之后,必須會走入到Native環境,將具體的分發的工作交給執行效率更高的Native代碼。

最后這些接口都將被統一到一個統一的Binder交互環境,這一環境可以被稱為Binder環境,而Binder IPC通信的過程,最終是在libbinder這樣一種庫文件里實現,最終會通過libbinder.so提供到Android系統里。

 libbinder是由C++編寫的,這便Binder傳輸在實現上也具備面向對象的特點,這種能力不僅給Java環境里的概念映射提供了方便,同時,也使在Native環境里也以面向對象的方向來使用Binder進行多種環境的互相通信提供了一種機制。於是,直接使用libbinder提供的編程接口,也可以編寫Native環境里的System Service,由C++語言直接給Java語言提供服務端實現,這就得到了NativeService。

對於libbinder的使用,可以還是先從Java環境的Binder類開始分析。

 

Java環境如何訪問到libbinder

在對於Java環境的Remote Service分析時,我們可以看到Binder在Java環境里的表現形式,除去只作為接口類的IInterface、IBinder,實際上在Android系統里,只會使用一個Binder基類來托管一個遠程對象。從交互過程來看,使用某個Binder上托管的對象,都可以通過Binder之上搭建的IPC消息“橋”進行互通過,在實現上,一個通過繼承的Binder的對象,分別將在發送端產生Proxy部分,而在接收端生成Stub部分。這樣的Binder通過IInterface將對象暴露出來之后,發送端就可以使用這一引用找到Proxy,通過Proxy對象的transact()方法發送,而接收端對應的也使用同一IInterface,通過其上onTransact()回調接收。這樣便構成了交互的能力。

但從Java環境里,實際上,我們根本不知道是如何處理完成的,我們跟蹤所有的Binder相關的Java實現,也不看不出來。比如,我們在客戶端經常會使用這樣的方法來寫Proxy端方法:

 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;  
}  

這種Proxy端的大部分代碼,都可以在Java源代碼里跟蹤到其具體實現,但mRemote.transact()這行,則沒有跟蹤代碼到具體是如何完成Binder通信的,我們前面只是說這一行便是送數據從BinderIPC通道上發送了出去,但並沒有解釋如何發送出去的。

這就會涉及到Binder的“跨界”實現,Binder這種特殊跨進程對象,實際上會映射到三層環境里,Kernel層,C/C++層,Java層。

如圖:

其中Kernel的Binder驅動是提供跨進程實現的基礎,能夠支持訪問Binder驅動只有C/C++層,Java層則必須要通過JNI訪問到C/C++層。Java語言實現里並不會支持任何對於底層操作系統功能,因為這樣勢必會破壞Java在各平台之上直接運行能力,但Java語言又將訪問幾乎所有的操作系統功能,這些都得通過JNI整合到Java環境的。在JNI編程這種限制之下,如果Binder對象在Java環境里保持一份、C++環境一份,則將加大開發與維護的開銷。於是在Android世界里,JNI層一般都很薄(甚至大部分還很難理解),盡可能將代碼集中在C++層實現,這樣保持了實現上的簡潔,同時還收獲了執行上的更高的效率。

我們的Binder.java實現了IBinder接口類,於是它擁有如下的結構:

public class Binder implements IBinder {
    public static final native int getCallingPid();
    public static final native int getCallingUid();
    public static final int getOrigCallingUid();
    private static final native int getOrigCallingUidNative();
    public static final int getOrigCallingUser();
   
    public static final native long clearCallingIdentity();
    public static final native void restoreCallingIdentity(long token);
    public static final native void setThreadStrictModePolicy(int policyMask);
    public static final native int getThreadStrictModePolicy();
    public static final native void flushPendingCommands();
    public static final native void joinThreadPool();
   
    public Binder() {
        init();
        ...
    }
   
    public void attachInterface(IInterface owner, Stringdescriptor) ;
    public String getInterfaceDescriptor();
    public boolean pingBinder() ;
    public boolean isBinderAlive();
    public IInterface queryLocalInterface(Stringdescriptor);
    protected boolean onTransact(int code, Parcel data, Parcel reply,
                                 int flags) throws RemoteException;
    public void dump(FileDescriptor fd, String[] args);
 
    protected void dump(FileDescriptor fd, PrintWriter fout,String[] args);
    public final boolean transact(int code, Parcel data, Parcel reply,
                                  int flags) throws RemoteException;
 
    public void linkToDeath(DeathRecipient recipient, int flags) ;
    public boolean unlinkToDeath(DeathRecipient recipient, int flags);
   
    protected void finalize() throws Throwable {
            destroy();
    }
   
    private native final void init();
    private native final void destroy();
 
    private boolean execTransact(int code, int dataObj, int replyObj,
            int flags) {
        res = onTransact(code, data, reply,flags);
        return res;
    }
}

作為一個繼承至IBinder接口的類,Binder這個類勢必要實現所有的接口方法。但比較特殊的是Binder類的構造方法Binder()會調用到一個init()方法,析構方法finalize()會調用到一個destroy()方法,這兩個方法並不是由Java實現,而是被標識為native的JNI實現的方法。另外需要注意到的是,Binder類本身實現了transact()與onTransact()收發兩端的代碼,但只是進程類的直接交互,並不會進程間的Binder交互。

另外,我們在同一Binder.java類里,還可以找到另一個BinderProxy類的定義,在這一類里會使用一個native標識的transact()方法。雖然在源代碼里找不到任何使用這一類的地方,但從命名方式上來看,這一類應該會是被創建的默認的Proxy端。BinderProxy.java的定義如下:

final class BinderProxy implements IBinder {
    public native boolean pingBinder();
    public native boolean isBinderAlive();
    public IInterface queryLocalInterface(Stringdescriptor);
    public native String getInterfaceDescriptor() throws RemoteException;
    public native boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException; public native void linkToDeath(DeathRecipient recipient,int flags)
            throws RemoteException;
    public native boolean unlinkToDeath(DeathRecipient recipient,int flags);
    public void dump(FileDescriptor fd, String[] args) throws RemoteException;
    public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException;
 
    BinderProxy() {
        mSelf = new WeakReference(this);
    }
   
    @Override
    protected void finalize() throws Throwable {
            destroy();
    }
   
    private native final void destroy(); 
    private static final void sendDeathNotice(DeathRecipient recipient) {
            recipient.binderDied();
    }
   
    final private WeakReference mSelf;
    private int mObject;
    private int mOrgue;
}

BinderProxy的transact會調用android_util_Binder.cpp

android_os_BinderProxy_transact

static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
    jint code, jobject dataObj, jobject replyObj, jint flags)
{
    ...
    //java Parcel轉為native Parcel
    Parcel* data = parcelForJavaObject(env, dataObj);
    Parcel* reply = parcelForJavaObject(env, replyObj);
    ...

    //gBinderProxyOffsets.mObject中保存的是new BpBinder(0)對象
    IBinder* target = (IBinder*)
        env->GetLongField(obj, gBinderProxyOffsets.mObject);
    ...

    //此處便是BpBinder::transact(), 經過native層
    status_t err = target->transact(code, *data, reply, flags);
    ...
    return JNI_FALSE;
}

BpBinder::transact

BpBinder.cpp

status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

IPCThreadState.transact

IPCThreadState.cpp

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) {
         // 傳輸數據
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }
    ...

    // 默認情況下,都是采用非oneway的方式, 也就是需要等待服務端的返回結果
    if ((flags & TF_ONE_WAY) == 0) {
        if (reply) {
            //等待回應事件
            err = waitForResponse(reply);
        }else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }
    return err;
}

IPCThreadState.waitForResponse

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    uint32_t cmd;
    int32_t err;
    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break; //與Binder驅動進行數據收發的函數
        err = mIn.errorCheck();
        if (mIn.dataAvail() == 0) continue;
        cmd = (uint32_t)mIn.readInt32();
        switch (cmd) {
        case BR_TRANSACTION_COMPLETE:
            if (!reply && !acquireResult) goto finish;break;
        case BR_DEAD_REPLY:
            err = DEAD_OBJECT; goto finish;
        case BR_FAILED_REPLY:
            err = FAILED_TRANSACTION; goto finish;
        case BR_ACQUIRE_RESULT:
            {
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;
        case BR_REPLY: //解析來自服務器端的回應,由Binder進行回應
            {
                binder_transaction_data tr;
                err = mIn.read(&tr, sizeof(tr));
                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                if (err != NO_ERROR) goto finish;
                if (reply) {
                    if ((tr.flags & TF_STATUS_CODE) == 0) {
                        reply->ipcSetDataReference(
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t),
                            freeBuffer, this);
                    } else {
                        err = *reinterpret_cast<const status_t*>(tr.data.ptr.buffer);
                        freeBuffer(NULL,
                            reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                            tr.data_size,
                            reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                            tr.offsets_size/sizeof(binder_size_t), this);
                    }
                } else {
                    freeBuffer(NULL,
                        reinterpret_cast<const uint8_t*>(tr.data.ptr.buffer),
                        tr.data_size,
                        reinterpret_cast<const binder_size_t*>(tr.data.ptr.offsets),
                        tr.offsets_size/sizeof(binder_size_t), this);
                    continue;
                }
            }
            goto finish;

        default:
            err = executeCommand(cmd); //主要用來解析Binder驅動對命令BC_TRANSACTION的回應命令BR_TRANSACTION
            if (err != NO_ERROR) goto finish;
            break;
        }
    }

finish:
    if (err != NO_ERROR) {
        if (acquireResult) *acquireResult = err;
        if (reply) reply->setError(err);
        mLastError = err;
    }
    return err;
}

IPCThreadState::talkWithDriver

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    binder_write_read bwr;
    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize(); //mIn數據訪問位置大於等於mIn數據空間大小
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
    bwr.write_size = outAvail;  //需要發送的數據長度
    bwr.write_buffer = (uintptr_t)mOut.data();//需要發送的數據的起始地址賦值到bwr.write_buffer

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();  //讀取回應的結果數據的大小
        bwr.read_buffer = (uintptr_t)mIn.data(); //讀取數據bwr.read_buffer即mIn.data()開始的地址 
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }
    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
    bwr.write_consumed = 0;
    bwr.read_consumed = 0;
    status_t err;
    do {
    // 與Binder驅動實際進行數據收發的接口,命令BINDER_WRITE_READ,此接口既要發送數據,
    // 又要讀取驅動的回應數據(當然是在需要回復的情況下)
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0) 
            err = NO_ERROR;
        else
            err = -errno;
    } while (err == -EINTR);
    return err;
}

binder_send_reply

 servicemanager/binder.c

void binder_send_reply(struct binder_state *bs, struct binder_io *reply, binder_uintptr_t buffer_to_free, int status) {
    struct {
        uint32_t cmd_free;
        binder_uintptr_t buffer;
        uint32_t cmd_reply;
        struct binder_transaction_data txn;
    } __attribute__((packed)) data;

    data.cmd_free = BC_FREE_BUFFER; //free buffer命令
    data.buffer = buffer_to_free;
    data.cmd_reply = BC_REPLY; // reply命令
    data.txn.target.ptr = 0;
    data.txn.cookie = 0;
    data.txn.code = 0;
    if (status) {
        ...
    } else {=
    
        data.txn.flags = 0;
        data.txn.data_size = reply->data - reply->data0;
        data.txn.offsets_size = ((char*) reply->offs) - ((char*) reply->offs0);
        data.txn.data.ptr.buffer = (uintptr_t)reply->data0;
        data.txn.data.ptr.offsets = (uintptr_t)reply->offs0;
    }
    //向Binder驅動通信
    binder_write(bs, &data, sizeof(data));
}

binder_write將BC_FREE_BUFFER和BC_REPLY命令協議發送給驅動,進入驅動。binder_ioctl -> binder_ioctl_write_read -> binder_thread_write,由於是BC_REPLY命令協議,則進入binder_transaction, 該方法會向請求服務的線程Todo隊列插入事務。

接下來,請求服務的進程在執行talkWithDriver的過程執行到binder_thread_read(),處理Todo隊列的事務。

 readStrongBinder

Parcel.java

readStrongBinder的過程基本是writeStrongBinder逆過程。

static jobject android_os_Parcel_readStrongBinder(JNIEnv* env, jclass clazz, jlong nativePtr) {
    Parcel* parcel = reinterpret_cast<Parcel*>(nativePtr);
    if (parcel != NULL) {
        return javaObjectForIBinder(env, parcel->readStrongBinder());
    }
    return NULL;
}

javaObjectForIBinder 將native層BpBinder對象轉換為Java層BinderProxy對象。

readStrongBinder(C++)

Parcel.cpp

sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}

unflatten_binder

Parcel.cpp

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    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:
                //進入該分支
                *out = proc->getStrongProxyForHandle(flat->handle);
                //創建BpBinder對象
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }
    }
    return BAD_TYPE;
}

getStrongProxyForHandle

ProcessState.cpp

    //查找handle對應的資源項
    handle_entry* e = lookupHandleLocked(handle);

    if (e != NULL) {
        IBinder* b = e->binder;
        if (b == NULL || !e->refs->attemptIncWeak(this)) {
            ...
            //當handle值所對應的IBinder不存在或弱引用無效時,則創建BpBinder對象
            b = new BpBinder(handle);
            e->binder = b;
            if (b) e->refs = b->getWeakRefs();
            result = b;
        } else {
            result.force_set(b);
            e->refs->decWeak(this);
        }
    }
    return result;
}

經過該方法,最終創建了指向Binder服務端的BpBinder代理對象。回到[小節4.8] 經過javaObjectForIBinder將native層BpBinder對象轉換為Java層BinderProxy對象。 也就是說通過getService()最終獲取了指向目標Binder服務端的代理對象BinderProxy。

 

 

對於Framework層實現,其基本功能都是通過frameworks/base/core/jni目錄里,可以找到所有JNI實現。對應於Java環境里Binder實現,我們可以找到frameworks/base/core/jni/android_util_Binder.cpp。可以在這一JNI實現里看到,實際上所有基於Binder的交互,會通過javaObjectForIBinder()方法基於IBinder引用來創建或是找到對應的Java對象,通過ibinderForJavaObject()通過Java對象找到IBinder引用:

jobject javaObjectForIBinder(JNIEnv* env, constsp<IBinder>& val)
{
    if (val == NULL) return NULL;
    if(val->checkSubclass(&gBinderOffsets)) {
       jobject object = static_cast<JavaBBinder*>(val.get())->object();
       LOGDEATH("objectForBinder%p: it's our own %p!\n", val.get(), object);
       return object;
    }
   AutoMutex _l(mProxyLock);
   jobject object = (jobject)val->findObject(&gBinderProxyOffsets); //1
    if (object != NULL) {
       jobject res = env->CallObjectMethod(object,gWeakReferenceOffsets.mGet);     //2
       if(res != NULL) {
           ALOGV("objectForBinder%p: found existing %p!\n", val.get(), res);
           return res;
       }
       LOGDEATH("Proxyobject %p of IBinder %p no longer in working set!!!", object, val.get());
       android_atomic_dec(&gNumProxyRefs);
       val->detachObject(&gBinderProxyOffsets);
       env->DeleteGlobalRef(object);
    }
 
   object = env->NewObject(gBinderProxyOffsets.mClass, gBinderProxyOffsets.mConstructor);         //3
    if (object != NULL) {
       LOGDEATH("objectForBinder%p: created new proxy %p !\n", val.get(), object);
       env->SetIntField(object, gBinderProxyOffsets.mObject, (int)val.get());
       val->incStrong(object);
       jobject refObject = env->NewGlobalRef(
                env->GetObjectField(object,gBinderProxyOffsets.mSelf));
       val->attachObject(&gBinderProxyOffsets, refObject,
                jnienv_to_javavm(env),proxy_cleanup);
       sp<DeathRecipientList> drl = new DeathRecipientList;
       drl->incStrong((void*)javaObjectForIBinder);
       env->SetIntField(object, gBinderProxyOffsets.mOrgue, reinterpret_cast<jint>(drl.get()));
       android_atomic_inc(&gNumProxyRefs);
        incRefsCreated(env);
    }
    return object;
}

在javaObjectForIBinder()方法里,

1.先會通過傳入的IBinder引用,來查找是否已經存在所需要使用的BinderProxy對象;

2.如果存在,則通過BinderProxy的WeakReference引用,然后返回該引用;

3.如果沒有,則在后面會創建這一BinderProxy對象。除去這幾行,實際上其他代碼都是在進行引用計數的維護。而在3代碼的操作里之后,調用incRefsCreated()方法,於是又會索引到另一個BinderInternal對象,使用其ForceGc()方法。

而對於Binder類本身,我們也會看到其init()的native實現,

static void android_os_Binder_init(JNIEnv* env, jobject obj)
{
   JavaBBinderHolder* jbh = new JavaBBinderHolder();
    if (jbh == NULL) {
       jniThrowException(env, "java/lang/OutOfMemoryError",NULL);
       return;
    }
   jbh->incStrong((void*)android_os_Binder_init);
   env->SetIntField(obj, gBinderOffsets.mObject, (int)jbh);
}

有了這三部分的代碼,我們的Java環境里的Binder,便與Native態的Binder結合到一起了,最終會得到如下所示的即有Java,也有C++代碼的復雜關系:

在Java環境里,某個Binder對象的IBinder引用,則可以通過javaObjectForIBinder()創建或是取得某個已有的BinderProxy對象,BinderProxy對象的transact()是以JNI的方式實現的,於是有可能進一步通過它來構建底層的Binder交互。同時,Java環境里的Binder對象,會通過init()方法來為該對象創建JavaBBinderHolder,從而使自己被映射到Native環境里的Binder(在Native環境里叫BBinder),最終將兩個環境里的Binder對象被映射到一起。

在這時不光需要完成Binder的實現由Java層轉入Native層,更重要是需要一種機制,可以使Native態發生的變動,再回到Java層。Java語言環境本身提供自動垃圾回收機制,我們需要將Binder對象能夠自動地被Java的GC所管理,同時,我們大部分使用Binder通信的代碼還是Java寫的,我們需要能夠在合適的狀態點回調到Javag玩意。JavaBBinderHolder本身只是JavaBBinder的包裝類,在JavaBBinder之上再包裝上引用計數(繼承Refbase),於是同時使用一個能處理GC的BinderInternal便可以自動處理。另外,值得注意的是Java環境里的Binder類,Binder類提供一個不常見的private的execTransact()方法,這其實就是Binder環境的回調,JNI代碼在執行Native環境的onTransact()方法時,會通過回調Java環境里的execTransact()方法,從而回調到Java里實現的onTransact()方法。於是,Java環境里的Binder,實際上只是一層封裝,直正的Binder通訊是由底層來完成的,由Android系統里使用C++編寫的一個libBinder庫來完成,如下所示:

ibbinder的構成

實現了從Java環境到Native實現的Binder環境之間的交互之后,還需要可以在多個范圍內完成對象的映射。Binder這個概念在Java環境里大量使用了面向對象的重構技巧,盡可能實現通用操作,而只預留出來需要定制的接口。於是,我們為了支持給Java環境提供的靈活功能,在Native層的Binder,也需要具備面向對象的能力。綜合這兩種需求,我們得到了frameworks/base/libs/binder目錄里,用C++實現的libbinder(在Android 4.1里,為了更好地兼容NDK被移到frameworks/native/libs/binder)。當然,C++跟Java的分析方式則有不同,C++的頭文件與實現,跟C一樣,是分開的,從頭文件更容易分析其構成,與實現對應,一般我們都可以在同級目錄里找到頭文件,libbinder的頭文件位於frameworks/base/include/binder。

出於跟Java層代碼進行不同語言空間的映射之用,C++實現的Binder庫也會與Java環境里的Binder概念有着互通之處。

IInterface.h,定義IInterface接口類。與Java的IInterface接口類對應,用於通過統一的asBinder()接口方法返回IBinder引用。但與Java環境不同,C++環境里需要提供Binder通信實現,於是IInterface類,在內部被進一步拆分成BpInterface(Proxy端對象)、BnInterface(Stub端對象)兩個模板,從而使用不同模板參數,可以使用對同一IInterface接口的訪問,得到不同功能實現。
IBinder.h,定義IBinder接口類。與Java環境的IBinder對應,提供Binder引用,並定義Binder對象所應實現的方法。跟Java環境一樣,IBinder對象會是分別引用到Proxy對象或是Stub對象,通過localBinder()方法返回Binder Stub端的BBinder對象,或是通過remoteBinder()方法返回Binder Proxy端的BpBinder對象。但與Java環境不同,C++環境里沒有標准的自動化內存管理(GabageCollection),於是會內置一個DeathRecipient類,通過Refbase來進行垃圾管理,就像我們前面分析JNI部分,這一管理內容,最終會通過BinderInternal類回調到Java的自動化內存管理。
Binder.h,定義BBinder類與BpRefBase類。BBinder類與Java環境里的Binder類對應,是Binder的Stub實現,通過onTransact()回調方法接收與處理Binder事件。但它更屬於Binder通訊的基礎類,並不會被直接使用,系統只會通過BBinder類的派生類進行通信,所以它的類名是BBinder,Base Binder的意思。BBinder里維護了Extras對象,可在線程完全情況下訪問到BpBinder里實現的objectManager,從而自動管理Proxy對象。BpRefBase類,用於通過IBinder引用來找到合適的BpBinder類,進一步被應用於BpInterface模板類。
BpBinder.h,定義BpBinder類。與Java環境里的Stub.Proxy對象對應,是Binder的Proxy端實現。作為Proxy端,又是Binder最底層的封裝,這一類的本質作用只是提供一個transact()方法,從而給上層封裝的RPC請求提供最終的Binder通信接口。與此同時,BpBinder創建的對象,必須與BBinder加入綁定,於是也提供objectManager類,用於提供Proxy端的對象管理,但與BBinder使用單一objectManager對象不同,這里存在多重映射的可能性,在Proxy對象里的objectManager會以隊列形式被管理。
Parcel.h,定義Parcel類。雖然概念上與Java里實現序列化的Parcel類是對應的,也提供同樣的操作方法。但在實現上,Native環境里的Parcel是提供Java環境里的Parcel概念的一種基礎,所有的Parcel的read|write_*()系列的方法,底層全是由Native代碼來實現具體的讀寫操作。這也是基於Binder的RPC操作的基礎,我們進行進程間的方法調用時,都會基於Parcel來完成參數與返回值的序列化,然后再通過Binder進行傳輸。最終,所有通過實現Parcelable方法得到的對象,都將在傳遞時被映射到Binder驅動所需要的一種平滑過的對象結構,被存入一種叫flat_binder_object的變量里,從而可以以線性空間的方式保存並傳輸。
上面的這些基本類,便構成了Binder通信的基礎。通過這些基本類,不但完成了Java環境與Binder的Native在實現上的概念統一,兩種環境里的對象都有一一對應的關系。而且這些概念上也通過JNI被關聯到一起,Java環境里的Binder最終會通過底層的Binder類來進行操作,而底層Binder對象,則會通過RefBase嵌入到Java環境的垃圾回收池。libBinder便擁有了如下所示的構成:

但此時,我們還是沒有解決最核心的問題,這些在Native環境里進行Binder通信封裝的類,如何操作Binder驅動來達到通信的目的。在libbinder的實現里,我們都會通過兩個專門的類來完成真正的Binder消息的讀寫操作,ProcessState與IPCThreadState,因為此時已經是全系統唯一的概念了,則不會提供Java代碼的映射,只由C++代碼來實現。

ProcessState.h,定義ProcessState類。正如這個類的名字所表述的,這個類的作用就是維護與IPC相關的進程狀態,對於任一使用Binder的進程而言,進程空間里只會有一個ProcessState對象。Binder通信與其他的IPC機制不同,其他的IPC基本上都是基於文件描述符fd來標識出不同的通信過程,而Binder在整個傳輸過程里都是以進程為單位來進行傳輸。Binder通信在傳輸時雖然也會使用/dev/binder的文件描述符,但只是用於與驅動通信,IPC消息只以進程為單位進行傳輸,並且也可以通過binder知道進程是否還處於存活狀態,從而可以實現整個系統的垃圾回收。
IPCThreadState.h,定義類IPCThreadState。這個類描述以線程為基礎的IPC傳輸狀態,Binder通信的讀寫過程便在這個類里完成。在Binder提供底層的跨進程通信能力之后,基於其上建立通信過程,可以以單線程循環方式完成,也可以使用多線程。如果使用單線程,在處理某個大數據量的消息的收發過程里容易發生阻塞,數據傳遞的效率降低,同時也會使底層的Binder驅動承載的壓力變大。如果使用簡單多線程,有線程則創建線程加以接收處理,則又產生線程維護開銷,並引發多線程編程失控。在IPCThreadState類的實現里,是以線程池的方式來維護Binder的通信請求,對於/dev/binder設備的讀寫請求都是通過線程方式並行執行的IPCThreadState的線程對象來完成,但並非總是創建,而只是通過IPCThreadState的self()方法取回一個合適的實例來進行處理。
多了這兩個與Binder進行通信的基本類之后,libbinder的構成便進一步被擴大,但此時已經可以完成Binder通信,並提供對上層的封裝功能了。於是,從Binder通信的功能上來看,libbinder的構成實際上是如下如示的樣子:

在libbinder的構成里,ProcessState,只是一個用於描述進程狀態的類,於是並不直接跟Binder通信。但Binder驅動會在ProcessState對象里被打開,對於進程來說,Binder的使用實例是唯一的,被保存到mDriverFD里。同時,由Binder派生出來的遠程對象,也會在ProcessState里通過getContextObject()和setContextObject()來維護。最后,對於進程當前的線程池環境,也是通過ProcessState對象來維護。

至於IPCThreadState類,則實現上會復雜一些,所有的Binder命令,最終都會通過一個IPCThreadState來進行處理。一個IPCThreadState對象,就是通過talkWitheDriver()方法來循環地操作ProcessState的mDriverFD,完成Binder驅動的實際讀寫操作。所有命令的發送操作,都是通過IPCThreadState的transact()方法來完成,而Binder驅動返回過來的消息,會通過executeCommand()回調到具體的onTransact()實現。

綜合libbinder的實現,與Java環境的Remote Service,最終得到的Binder通信便是如下的流程:

Remote Service的訪問者,也就是應用程序進程,會使用Stub.Proxy對象來調用transact()方法,而Proxy對象本身會在使用里創建一個BinderProxy對象,並調用這一BinderProxy對象的transact()方法。而Java環境里的BinderProxy對象的使用,會在libbinder里創建BpBinder與之對應,BinderProxy的transact()本身是使用JNI實現的,會調用BpBinder的transact()實現。這時,在BpBinder的transact()方法里,Binder命令便會經由IPCThreadState對象的transact()、waiteForResponse()、talkWithDriver(),寫入當當前進程維護的mDriverFD,也就是Binder驅動里。

Remote Service則是Binder命令的接收與處理者,會一直在自己的ProcessState對象維護的mDriverFD上監聽,Remote Service則都使用joinThreadPool()來創建監聽Binder的線程。當Binder命令過來之后,監聽的IPCThreadState對象會從talkWithDriver()方法里返回,讀回相應的命令,然后調用executeCommand()方便處理這一命令。在executeCommand()方法里,當接收到交互請求(命令是BR_TRANSACTION)時,會調用Binder命令里指定BBinder對象的transact()方法。此時,因為Java環境里Binder對象,在JNI實現里會自動創建JavaBBinder類,於是BBinder對象的transact()方法,會通過JavaBBinder的onTransact()回調到Java環境里Binder對象的execTransact()方法,然后再調用到最終的RemoteService里實現的onTransact()方法。

當然,前面通過aidl編程也可以看出,雖然底層實現上如此復雜,九轉十八彎才得到了這樣的遠程調用,但對於編程使用卻異常簡單,只是需要簡單地使用一個Stub對象即可,所有的底層操作都將系統封裝掉了,在aidl編程時甚至都不知道有Proxy對象,全由aidl自動生成。這便是Android的優點之一,無論底層多么復雜,但上層都是很簡單的接口。而對於系統設計的一個可借鑒之處是,當我們把這套邏輯封裝得非常易於編程時,對於底層的改進也將更加平滑,因為用戶並不知道底層發生了怎樣的變動,仍使用同樣的編程方式進行調用。

這種方式,繞來繞去的,不太容易理解,Java環境與Native環境的互相穿越,也容易迷失方向。這是否有必要呢?如果沒有Java,這種復雜邏輯是沒有理由的,復雜便會效率低下。而且在整個Binder概念的實現上,大量使用面向對象技巧,即便是在C++實現的部分,也會通過虛擬繼承來實現訪問上的靈活性,在嵌入式環境里使用虛擬繼承來進行動態訪問,本身就是低效之源。但是,因為有了Java語言的需求,這樣設計就很合理了。通過Binder,不但完成了Binder在Java環境與Native環境的成功映射,在Java環境的Binder概念之下通過機器代碼實現了高效安全的Binder通信,更進一步的好處是,Binder被托管到了Java虛擬機的自動化垃圾回收機制里。假設Android並沒有選擇Java語言,而是選擇了另一種支持垃圾回收的編程語言,我們只需要簡單地將Java態的綁定,也就是Binder概念相關的Java類、JNI實現實現一次即可。

至此,基本上libbinder的基本功能便已經完備了,可以支持上層的基於Binder傳遞對象、使用IBinder引用來進行調用遠程進程中的方法、以及通過Parcel來傳遞復雜對象的功能。

除了基本功能之外,libbinder里還會實現一些C++環境里的輔助類:

實現在C++環境里的ServiceManager類,從而在C++環境里可以直接調用getService()方法取得其他System Service
實現IMemory接口方法,從而可以靈活實現多種內存共享方式
libbinder里實現的ServiceManager

ServiceManager本身就是Native Service的一個典型的例子,Java環境里編程會使用ServiceManager,調用到SystemServer里實現的系統功能。而整個Android系統各個組成部分也會不停地進行交互,Native Service之間也會進行相互調用。我們可以看到servicemanager是一個C語言寫的獨立進程,Stub端的功能便會由這一servicemanager進程來完成,於是從Binder領域來說,所有以面向對象實現的ServiceManager類,只需要提供Proxy功能。

以Native Service方式來提供ServiceManager功能,則是一個跟我們的前面的ITask很類似一種實現。出於代碼完整性角度考慮,在IServiceManager里也提供了BnServiceManager的實現,但由於沒有將這一Service加入到IPCThreadState里,於是只是空的實現。

在frameworks/native/include/binder/IServiceManager.h定義了以Native方式實現的Service,

namespace android {
    class IServiceManager: publicIInterface   1
    {
    public:
       DECLARE_META_INTERFACE(ServiceManager); 2
       virtual sp<IBinder> getService( const String16& name) const = 0;  3
       virtual sp<IBinder> checkService( const String16& name) const = 0;
       virtual status_t      addService( const String16&name,
                                     constsp<IBinder>& service,
                                     bool allowIsolated =false) = 0;
       virtual Vector<String16>   listServices() =0;
       enum {            4
GET_SERVICE_TRANSACTION=  
IBinder::FIRST_CALL_TRANSACTION,
           CHECK_SERVICE_TRANSACTION,
           ADD_SERVICE_TRANSACTION,
           LIST_SERVICES_TRANSACTION,
       };
    };
   
   sp<IServiceManager> defaultServiceManager();
   
    template<typename INTERFACE>
   status_t getService(const String16& name, sp<INTERFACE>* outService) 5
    {
       const sp<IServiceManager> sm = defaultServiceManager();
       if(sm != NULL) {
           *outService = interface_cast<INTERFACE>(sm->getService(name));
           if((*outService) != NULL) return NO_ERROR;
       }
       return NAME_NOT_FOUND;
    }
   
    boolcheckCallingPermission(const String16& permission);   6
    boolcheckCallingPermission(const String16& permission,
                                int32_t*outPid, int32_t* outUid);
    bool checkPermission(const String16&permission, pid_t pid, uid_t uid);
   
    class BnServiceManager: publicBnInterface<IServiceManager>   7
    {
    public:
       virtual status_t    onTransact(uint32_t code,
                                       const Parcel&data,
                                       Parcel*reply,
                                       uint32_t flags = 0);
    };
}; // namespace android

 IServiceManager這一接口類,繼承自IInterface
 進入IServiceManager的類定義部分,就會通過DECLARE_META_INTERFACE來完成通用部分的定義。
 定義所需要的接口方法,所有接口方法必然會是純虛方法。
 定義IServiceManager所支持的Binder命令,跟Java環境里的ServiceManager類一致,支持四種命令,分別對應到第3步里定義的四個接口方法。並且跟其他Native Service一樣,Binder命令都是從IBinder::FIRST_CALL_TRANSACTION開始。
 這里使用了C++的多態,一般的getService()是直接通過一個Service的名字來取回一個IBinder實現,通過返回的IBinder引用是否為NULL來判斷是否成功完成調用。而在這里定義的getService()方法,進一步封裝了一次,可以返回一個調用的狀態值,並且會直接通過interface_cast()宏來確保Proxy對象被創建。
 checkCallingPermission()、checkPermission()相當於IServiceManager里提供的一層Proxy功能,這部分的功能是由IPermissionController.cpp來提供,而這部分功能並不適合暴露出來,於是會透過IServiceManager將權限檢測功能提供出來。
 出於實現上的統一性考慮,在這里也會提供BnServiceManager的實現。
有了這個IServiceManager接口類的定義,在IServiceManager實現就跟

sp<IServiceManager>defaultServiceManager()     1
{
    if(gDefaultServiceManager != NULL) return gDefaultServiceManager;
    {
       AutoMutex _l(gDefaultServiceManagerLock);
       if(gDefaultServiceManager == NULL) {
           gDefaultServiceManager = interface_cast<IServiceManager>(
                ProcessState::self()->getContextObject(NULL));    2
       }
    }
    returngDefaultServiceManager;
}
…
class BpServiceManager : public BpInterface<IServiceManager> 3
{
public:
   BpServiceManager(const sp<IBinder>& impl)
       : BpInterface<IServiceManager>(impl)
    {
}
…
    virtualsp<IBinder> checkService( const String16& name) const    4
    {
       Parcel data, reply;
       data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
       remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
       return reply.readStrongBinder();
}
     …
IMPLEMENT_META_INTERFACE(ServiceManager, "android.os.IServiceManager"); 5
…
}

defaultServiceManager(),每個進程都需要通過getService()來取回RemoteService,所以必然需要調用到defaultServiceManager()來取回一個IServiceManager的Proxy對象。
在defaultServiceManager()里使用了Singleton模式,對於某個進程只會創建一個唯一的IServiceManager的Proxy實例。值得注意的是getContextObject()會通過一個handle變量來取得一個IBinder引用,然后再通過interface_cast()轉換成IServiceManager接口類。getContextObject()方法的參數會是整型的handle,handle的值會隨着不同Service的引用,每使用一個,handle的值便會加1,這樣每個進程空間會擁有各自不同的handle值,使得基於Binder通信的安全變高,不容易簡單地抓取Binder命令來分析程序的行為。這里使用的handle值為0,於是對於每個進程,handle為0的Service都會是IServiceManager。
實現IServiceManager的Proxy類,於是實現上便會繼承自BpInterface的模板。
跟Java環境的ServiceManager一致,getService()內部也會是調用checkService()來取得Service的IBinder引用。所有的Proxy端方法,都使用統一的模式,就是將調用的方法轉換成Binder命令,然后發送出去。
IMPLEMENT_META_INTERFACE()宏,會實現通用部分的代碼,同時也會設定特定的descriptor。
       通過這樣的方式,最終就得到了簡單而且高效的,並且與ServiceManager.java實現並行的ServiceManager的Proxy端。

通過libbinder靈活使用內存

在我們傳統的Unix/Linux編程環境里,為了保持進程之間的互相獨立性,都是用戶進程空間里的內容互相獨立,使用不同的內存映射,內核空間便會共享同一份內容,使用同一份內存映射。這樣的情況下,如果需要在進程之間傳遞數據,必然是先通過copy_from_user()系統調用從用戶空間先拷貝到內核空間,然后再在另一個進程空間里通過copy_from_user()系統調用從內核空間拷貝回用戶空間。這種方式就保證了不同進程可以傳遞數據,同時進程之間互相不會有干擾,任一進程出錯,對另一進程完全沒有影響,因為進程空間本身是獨立的。在Linux內核之上,任何IPC機制都采用了這種實現,Binder也不例外。比如Remote Service,在任一交互過程里,數據始終會有三份,內核一份、進程空間各一份拷貝:

但這種方式比較低效,多次內存拷貝會造成內存的開銷,同時由於copy_from_user()和copy_to_user()系統調用,會造成計算上的開銷。假設已經確定內存的傳遞時一方只讀,此時就可以改進內存的使用,在發生內存寫請求的進程里,仍然使用copy_from_user(),而讀取內存的部分,則不再使用copy_to_user(),而是通過mmap()直接映射一段內存到自己的進程空間內,這樣只會發生一次內存拷貝。

最后,還有一種可能性,所有進程都共享同一塊內存區域,不管內存里保存的內容發生了任何改變,所有進程都應該見得到。這種使用在Linux編程里也很普遍,但一般只用於驅動訪問,很少被用於IPC進程間通信。這種使用情境下,如果所共享的頁源自於用戶空間,則難以保證在物理分配上的連續性,更重要的是不要求,如果承載內存頁的進程掛掉,則所有涉及交互的進程都不得不掛掉,所以內存頁要在內核空間里。同時,在內核態則需要有一定的實體存放這樣的頁面映射引用,IPC機制並不支持這樣的頁面映射管理。但Binder IPC不受限於此,Binder驅動實際上只是一個基於內存映射的虛擬字符設備,於是可以天然地在傳輸過程里使用內存頁的映射功能。於是,又有了第三種使用內存頁的方式,就是靈活地內存映射功能:

如上所示,內存頁實際上是在使用時通過內核態來分配的,內存只在內核態有一份拷貝,所有的用戶進程都只通過mmap()系統調用來引用這樣的頁。但是這樣的方式會引發內存管理上的混亂,內核空間的頁面在分配上的優先級要遠大於用戶空間,而且必須以連續物理頁來分配,也容易造成內存使用上的失控。於是,Android在原有的內存管理機制上拓展出來兩種“特殊”內存管理機制,准確地說是共享內存的實現機制,pmem和ashmem,這兩種機制可以將內核里內存分配機制暴露到用戶態來操作。Pmem是一種預留出來一段物理內存供用戶態分配連續物理內存來使用,而ashmem則是Android對原有的Shared Memory(共享內存機制)的一種改進,這兩種機制我們后台再詳細。雖然這種共享內存方式本身跟Binder機制沒有關系的,並非由Binder IPC來實現這樣共享功能,但得益於Binder通信與Java垃圾回收的綁定,於是Binder為這種內存共享提供了自動的內存管理功能。

IMemory.h,定義兩個基於IBinder的遠程類,生成兩個遠程接口類,IMemory與IMemoryHeap,分別用於使用內存和分配內存。這是Android在系統設計上靈活性的一種體現,我們也知道IBinder是提供遠程引用的,對於內存使用兩個基於IBinder的接口類,則意味着申請內存與分配內存可分別由單獨進程來提供。試想一下,比如一個照相機應用程序,通過IMemory接口向mediaserver進程申請內存,但在mediaserver進程里發出內存申請之后,則會由負責顯示的surfaceflinger來負責分配所需要的空間。這樣復雜的供給關系,只取決於代碼如何實現,也不受限於進程空間,而且不會影響效率,因為無論多少進程交互,在底層實際上還是只有一份拷貝。當然,同時使用IMemory與IMemoryHeap遠程接口,並不一定要發生在多進程環境里,當兩個接口都在同一進程空間里提供Proxy與Stub時,實際上只是多繞了一層Binder IPC,但還是當前進程空間內,也不影響效率。另外,這兩個接口類,出於性能的考慮,會是以Native Service的方式來提供。
MemoryDealer.h,定義一個默認的分配內存的MemoryDealer類。在這一類里內置了一個最簡化的列表式內存管理算法,這樣需要提供內存分配部分,可以使用這一類來創建內存空間,並通過IMemoryHeap共享出去。
MemoryBase.h,通過MemoryBase類來提供IMemory接口類的Stub端實現。MemoryBase會通過getMemory()的遠程方法來返回一個IMemoryHeap實例,同時也會是MemoryDealer的操作對象。命名為Base,就說明這會是該類型的基類定義,如果有其他使用IMemory接口的地方可以繼承該類,再派出生新的特性。
MemoryHeapBase.h,通過MemoryHeapBase類來實現IMemoryHeap接口類的Stub端。在這個類里實現可用於遠程共享的堆空間分配,如果不用於遠程共享,則直接使用malloc()即可,IMemoryHeap接口相當於是遠程實現的malloc(),new()等操作方法。在這一方法里會定義一些基本的Heap分配操作,根據不同的應用情境分配不同類型的內存(基於文件的、匿名空間等)。
MemoryHeapPmem.h,實現基於Pmem機制並實現IMemoryHeap接口的MemoryHeapHmem類。如果有特殊內存堆的使用需求,則可以通過MemoryHeadBase類派生出新的MemoryHead類,比如在MemoryHeapPmem。所有的的特殊
最終,針對內存的分配與使用,在底層也會靈活地組織起來,在內存使用“食物鏈”最上流的使用內存的部分,只需要調用MemoryBase對象的getMemory()接口方法,這一請求會通過IMemory接口轉發到能處理該請求的另一進程。而getMemory()又會返回一個IMemoryHeap引用,這樣會自動地又將請求分發到可以處理這一IMemoryHeap分配的進程來處理內存分配。於是,在libbinder實現里針對跨進程的內存使用與分配,又可以得到如下的關系圖:

有了IMemory這樣的接口類之后,在Android系統里就可以更靈活地定義不同的內存使用方法。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM