Android內核學習筆記—Binder分析

進程間通信——Binder

概述

Binder是Android中使用最廣泛的IPC機制。如果統觀Binder中的各個組成元素,就會驚奇地發現它和TCP/IP網絡有很多相似之處:
.Binder驅動——路由器
.Service Manager——DNS
.Binder Client——客戶端
.Binder Server——服務器

Service Manager在Binder通信過程中的唯一標誌永遠都是0.

Binder驅動與協議

Android系統是基於Linux內核的,因而它所依賴的Binder驅動也必須是一個標準的Linux驅動。具體而言,Binder Driver會將自己註冊成
一個misc device,並向上提供一個/dev/binder節點——值得一提的是,Binder節點並不對應真實的硬件設備。Binder驅動運行於內核態,
可以提供open(),ioctl(),mmap()等常用的文件操作。

Binder驅動源碼在Kernel工程的drivers/staging/android目錄中。

Android系統爲什麼把Binder註冊成misc device類型的驅動呢?
這種”雜項”驅動的主設備號統一爲10,次設備號則是每種設備獨有的。驅動程序也可以通過設置MISC_DYNAMIC_MINOR來由系統動態分配次設備號。Linux中的字符設備通常要經過alloc_chrdev_region(),cdev_init()等一系列操作才能在內核中註冊自己。而misc類型驅動則相對簡單,只需要調用misc_register()就可輕鬆解決。

Binder驅動總共爲上層應用程序提供了6個接口:
(1)binder_poll(2)binder_ioctl(3)binder_mmap(4)binder_open(5)binder_flush(6)binder_release.其中使用最多的binder_ioctl,binder_mmap
和binder_open。而一般文件操作需要用到的read()和write()則沒有出現,這是因爲它們的功能完全可以用ioctl()和mmap()來代替;而且後兩者還更加靈活。

binder_open:上層進程在訪問Binder驅動時,首先就需要開/dev/binder節點,這個操作最終的實現是 在binder_open()中。在binder_open函數中,Binder驅動會爲用戶創建一個它自己的 binder_proc實體。即Binder驅動會在/proc系統目錄下生成各種管理信息(比如/proc/binder/proc,
/proc/binder/state,/proc/binder/stats等),binder_proc就是管理數據的記錄體(每個進程都有 獨立記錄),用戶對Binder設備的操作就是以binder_proc對象爲基礎的。

binder_mmap:該函數主要是對內存的管理,主要是對某塊物理內存的共享,以便實現兩個進程間的數據交互。

binder_ioctl:這是Binder接口函數中工作量最大的一個,它承擔了Binder驅動的大部分業務。Binder並不提供read() 和write()等常規文件操作,因爲binder_ioctl就可以完全替代它們。

binder_ioctl支持的命令:
1.BINDER_WRITE_READ:讀寫操作,可以用此命令向Binder讀取或寫入數據.
2.BINDER_SET_MAX_THREADS:設置支持的最大線程數,因爲客戶端可以併發向服務器端發送請求,如果Binder驅動發現當 前的線程數量已經超過設定值,就會告知Binder Server停止啓動新的線程。
3.BINDER_SET_CONTEXT_MGR:Service Manager專用,將自己設置爲”Binder大管家”。系統中只能有一個SM存在。
4.BINDER_THREAD_EXIT:通知Binder線程退出。每個線程在退出時都應該告知Binder驅動,這樣才能釋放相關資源,否則可能會造成內存泄露。
5.BINDER_VERSION:獲取Binder版本號。

Binder驅動並沒有脫離Linux的典型驅動模型,提供了多個文件操作接口。其中binder_ioctl實現了應用進程與Binder驅動之間的命令交互,可以說承載了Binder驅動中的大部分業務。

ServiceManager(Binder Server)

ServiceManager(以下簡稱SM)的功能可以類比爲互聯網中的”DNS”服務器,”IP地址”爲0.另外,和DNS本身也是服務器一樣,SM也是一個標準的Binder Server,Binder驅動中提供了專門爲SM服務的相關命令。

ServiceManager的啓動

ServiceManager是在init程序解析init.rc時啓動的,另外需要注意的是:一旦ServiceManager發生問題後重啓,其他系統服務zygote,media,surfaceflinger和drm 也會被重新加載。這個servicemanager是用c/c++編寫的,源碼路徑在工程的
/frameworks/native/cmds/servicemanager目錄中,如下所示:
image
要特別提醒的是,servicemanager所對應的c文件是service_manager.c和binder.c。源碼工程中還有其他諸如ServiceManager.cpp的文件存在,但並不屬於SM程序。

ServiceManager的構建

在Android系統中,Binder Server的另一個常見稱謂是”XXX Service”,如Media Service,ActivityService等。
我們看下SM啓動後都做了哪些工作,找到main函數.

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/service_manager.c
int main(int argc, char **argv)
{
    struct binder_state *bs;

    bs = binder_open(128*1024);//打開Binder設備
    if (!bs) {
        ALOGE("failed to open binder driver\n");
        return -1;
    }
    //將自己設置爲Binder“大管家”,整個Android系統只允許一個ServiceManager存在,因而如果後面還
    //有人調用這個函數就會失敗
    if (binder_become_context_manager(bs)) {
        ALOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }
    .................................................//代碼省略
    svcmgr_handle = BINDER_SERVICE_MANAGER;
    binder_loop(bs, svcmgr_handler);//進入循環,等待客戶請求

    return 0;
}

我們可以看到main函數裏主要做了以下幾件事:
1.打開Binder設備,做好初始化
2.將自己設置爲Binder大管家
3.進入主循環
下面我們再深入一些看一下這幾件事:

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/binder.c
struct binder_state *binder_open(size_t mapsize)
{
    struct binder_state *bs;//這個結構體記錄了SM中關於Binder的所有信息,如fd,map的大小等
    struct binder_version vers;

    bs = malloc(sizeof(*bs));
    if (!bs) {
        errno = ENOMEM;
        return NULL;
    }

    bs->fd = open("/dev/binder", O_RDWR);//打開Binder驅動節點
    if (bs->fd < 0) {
        fprintf(stderr,"binder: cannot open device (%s)\n",
                strerror(errno));
        goto fail_open;
    }

    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
        (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        fprintf(stderr, "binder: driver version differs from user space\n");
        goto fail_open;
    }

    bs->mapsize = mapsize;//mapsize是SM自己設的,爲128*1024,即128k
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    if (bs->mapped == MAP_FAILED) {
        fprintf(stderr,"binder: cannot map device (%s)\n",
                strerror(errno));
        goto fail_map;
    }

    return bs;

fail_map:
    close(bs->fd);//關閉file
fail_open:
    free(bs);
    return NULL;
}
/*
關於open和mmap最終都是調用的驅動層的binder_open和binder_mmap。
根據上面代碼段中的參數設置可知:
1.由Binder驅動決定被映射到進程空間中的內存起始地址。
2.映射區塊大小爲128k
3.映射區只讀
4.映射區的改變是私有的,不需要保存文件。
5.從文件的起始地址開始映射。
*/

接着我們來看第二件事,即將servicemanager註冊成Binder機制的”大管家”.

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/binder.c
int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
/*正如前面驅動部分的命令描述所陳述的那樣,只要向Binder Driver發送BINDER_SET_CONTEXT_MGR的ioctl命令即可
。因爲servicemanager啓動得很早,能保證它是系統中的第一個向Binder驅動註冊成"管家"的程序*/

第三件事就是看看SM是如何處理請求的:

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/binder.c
void binder_loop(struct binder_state *bs, binder_handler func)
{
    int res;
    struct binder_write_read bwr;//這是執行BINDER_WRITE_READ命令所需的數據格式
    uint32_t readbuf[32];//一次讀取容量

    bwr.write_size = 0;
    bwr.write_consumed = 0;
    bwr.write_buffer = 0;

    readbuf[0] = BC_ENTER_LOOPER;//命令
    binder_write(bs, readbuf, sizeof(uint32_t));

    for (;;) {
        bwr.read_size = sizeof(readbuf);
        bwr.read_consumed = 0;
        bwr.read_buffer = (uintptr_t) readbuf;

        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);//讀取消息

        if (res < 0) {
            ALOGE("binder_loop: ioctl failed (%s)\n", strerror(errno));
            break;
        }

        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);//處理讀取到的消息
        if (res == 0) {
            ALOGE("binder_loop: unexpected reply?!\n");
            break;
        }
        if (res < 0) {
            ALOGE("binder_loop: io error %d %s\n", res, strerror(errno));
            break;
        }
    }
}
/*由此可見,SM遵循以下幾個步驟:
1.從Binder驅動讀取消息:通過發送BINDER_WRITE_READ命令實現——z這個命令既可讀取也可寫入,具體
                      要看bwr.write_size和bwr.read_size。因爲這裏write_size的初始化值爲
                      0,而read_size爲sizeof(readbuf),所以Binder驅動只執行讀取操作。
2.處理消息:調用binder_parse來解析消息。
3.不斷循環,而且永遠不會主動退出(除非出現致命錯誤)
*/

在binder_parse的處理過程中,需要重點關注下BR_TRANSACTION。

BR_TRANSACTION

對BR_TRANSACTION命令的處理主要由func來完成,然後將結果返回給Binder驅動。因爲ServiceManager是爲了完成”Binder Server Name”(域名)和”Server Handle”(IP地址)間對應關係的查詢而存在的,所以可推測出它提供的服務應該至少包括以下幾種:(1)註冊:當一個Binder Server創建後,它們要將自己的名稱,Binder句柄對應的關係告知SM進行備案。(2)查詢:即應用程序可以向SM發起查詢請求,以獲知某個Binder Server所對應的句柄(3)其他信息查詢:比如SM版本號,當前的狀態等。當然,這一部分不是必需的,可以不實現。

注意在這裏func函數指向svcmgr_handler函數。所以我們這裏需要來看一下svcmgr_handler的實現:

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/cmds/servicemanager/service_manager.c
int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    size_t len;
    uint32_t handle;
    uint32_t strict_policy;
    int allow_isolated;

    //ALOGI("target=%x code=%d pid=%d uid=%d\n",
    //  txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid);

    if (txn->target.handle != svcmgr_handle)
        return -1;

    if (txn->code == PING_TRANSACTION)
        return 0;

    // Equivalent to Parcel::enforceInterface(), reading the RPC
    // header with the strict mode policy mask and the interface name.
    // Note that we ignore the strict_policy and don't propagate it
    // further (since we do no outbound RPCs anyway).
    strict_policy = bio_get_uint32(msg);
    s = bio_get_string16(msg, &len);//bio_XX系列函數爲取出各種類型的數據提供了便利。
    if (s == NULL) {
        return -1;
    }

    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s, len));
        return -1;
    }

    if (sehandle && selinux_status_updated() > 0) {
        struct selabel_handle *tmp_sehandle = selinux_android_service_context_handle();
        if (tmp_sehandle) {
            selabel_close(sehandle);
            sehandle = tmp_sehandle;
        }
    }

    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE://根據server名稱查找它的handle值。
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        //do_find_service這個函數執行查找操作。SM中維護有一個全局的svclist變量,用於保存所有server的註冊信息。
        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
        if (!handle)
            break;
        bio_put_ref(reply, handle);//保存查詢結果,以返回給客戶端
        return 0;

    case SVC_MGR_ADD_SERVICE://用於註冊一個Binder Server
        s = bio_get_string16(msg, &len);
        if (s == NULL) {
            return -1;
        }
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        //這個函數具體執行添加操作
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
            allow_isolated, txn->sender_pid))
            return -1;
        break;

    case SVC_MGR_LIST_SERVICES: {//獲取列表中對應Server
        uint32_t n = bio_get_uint32(msg);

        if (!svc_can_list(txn->sender_pid)) {
            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                    txn->sender_euid);
            return -1;
        }
        si = svclist;//所有的Server信息都保存於此。
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:
        ALOGE("unknown code %d\n", txn->code);
        return -1;
    }

    bio_put_uint32(reply, 0);
    return 0;
}

ServiceManager的功能架構比較簡潔——其內部維護着一個svclist列表,用於存儲所有Server相關信息(以svcinfo爲數據結構),查詢和註冊都是基於這個表展開的。函數svcmgr_handler處理完成後,binder_parse會進一步通過binder_send_reply來將執行結果回覆給底層Binder驅動,進而傳遞給客戶端。然後binder_parse會進入下一輪的while循環,知道ptr < end爲False——此時說明Service Manager上一次從驅動層讀取的消息都已處理完成,因而它還會繼續向Binder Driver發送BINDER_WRITE_READ以查詢有沒有消息。如果有的話就處理,否則會進入休眠等待。

我們來回憶一下順序:init—>init.rc—>ServiceManager start->service_manager.c/main->binder.c/binder_open
->binder.c/binder_become_context_manager->binder.c/binder_loop->binder.c/binder_parse.

獲取ServiceManager服務

所有Binder Client或者Binder Server都是圍繞Binder驅動展開的。每個進程只允許打開一次Binder設備,且只做一次內存映射,所有需要使用Binder驅動的線程共享這一資源。與Binder驅動進行實際命令通信的是IPCThreadState.

ServiceManagerProxy

在Java層ServiceManagerProxy的封裝類是ServiceManager.java.該類的部分代碼如下:

//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/os/ServiceManager.java
public final class ServiceManager {
    private static final String TAG = "ServiceManager";
    private static IServiceManager sServiceManager;
    //用於記錄getService的歷史查詢結果,以加快查詢速度。
    private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }
    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
    public static void addService(String name, IBinder service) {
           try {
                getIServiceManager().addService(name, service, false);
            } catch (RemoteException e) {
                Log.e(TAG, "error in addService", e);
            }
        }
    /*

    */
    .........................//代碼省略
}

通過上面的這部分代碼我們可以發現,getService與addService的最終實現依賴IServiceManager的 某個實現類,我們看到sServiceManager的創建是依賴於 ServiceManagerNative.asInterface這方法.

下面我們繼續查看這個函數的代碼

 //http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/os/ServiceManagerNative.java

  // Cast a Binder object into a service manager interface, generating a proxy if needed.
   static public IServiceManager asInterface(IBinder obj)
    {
        if (obj == null) {
            return null;
        }
        IServiceManager in =
            (IServiceManager)obj.queryLocalInterface(descriptor);//查詢本地是否已經有IServiceManager存在
        if (in != null) {
            return in;
        }
        //如果沒有查詢到,則新建一個ServiceManagerProxy.
        return new ServiceManagerProxy(obj);
    }

哈哈,看SM的代理ServiceManagerProxy終於出現了,可想而知ServiceManagerProxy必定是要與Binder驅動通信的,因而它的構造函數中傳入了IBinder對象。我們看一下這個代理類的代碼:


//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/android/os/ServiceManagerNative.java
class ServiceManagerProxy implements IServiceManager {
    public ServiceManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    public IBinder asBinder() {
        return mRemote;
    }

    public IBinder getService(String name) throws RemoteException {
       //準備打包數據
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();//保存通訊結果
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name)
        //打包數據結束
        //利用IBinder的transact將請求發送出去,而不用理會Binder驅動的open,mmap以及一大堆具體
        //的Binder協議中的命令。所以這個IBinder一定會在內部使用ProcessState和IPCThreadState來
        //與Binder驅動進行通信,
        mRemote.transact(GET_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

    public IBinder checkService(String name) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IServiceManager.descriptor);
        data.writeString(name);
        mRemote.transact(CHECK_SERVICE_TRANSACTION, data, reply, 0);
        IBinder binder = reply.readStrongBinder();
        reply.recycle();
        data.recycle();
        return binder;
    }

    public void addService(String name, IBinder service, boolean allowIsolated)
            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);
        mRemote.transact(ADD_SERVICE_TRANSACTION, data, reply, 0);
        reply.recycle();
        data.recycle();
    }

   ..........................................................................//代碼省略
    private IBinder mRemote;
    /*
    以上代碼中的getService,checkService,addService這些函數的函數體的重要區別點在於命令的不同。
    */

}

IBinder和BpBinder

在創建ServiceManagerProxy時,傳入了一個IBinder對象,然後藉助於它的transact方法,可以方便地與Binder驅動進行通信。
那麼我們的這個IBinder對象怎麼來的呢?
我們可以看到在ServiceManager類中有這麼一句ServiceManagerNative.asInterface(BinderInternal.getContextObject());然後再根據asInterface的代碼我們可以肯定的是,這個IBinder對象是由BinderInternal.getContextObject()產生的。

 //http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/java/com/android/internal/os/BinderInternal.java
  /**
     * Return the global "context object" of the system.  This is usually
     * an implementation of IServiceManager, which you can use to find
     * other services.
     */
    public static final native IBinder getContextObject();//這個方法是native,所以我們得找到對應的jni實現
//http://androidxref.com/5.1.0_r1/xref/frameworks/base/core/jni/android_util_Binder.cpp
static jobject android_os_BinderInternal_getContextObject(JNIEnv* env, jobject clazz)
{
    sp<IBinder> b = ProcessState::self()->getContextObject(NULL);//這裏我們引出了ProcessState
    return javaObjectForIBinder(env, b);//將native層創建的對象轉換爲Java層的IBinder對象。即BpBinder->BinderProxy
    /*
    這裏有人可能會有疑問爲什麼取名爲ContextObject呢?
    Context即"背景,上下文",這裏可以理解爲運行時態的上下文。換句話說,是因爲IPC和整個Process或者
    Thread都是有緊密關聯的。更進一步,基本上每個Process都需要IPC通信。既然如此,IPC就可以作爲進程
    的基礎配置存在。作爲IPC中的基礎元素之一,Binder就是這個Context中的重要一環,因爲稱爲ContexObject。
    */
}

IBinder只是一個接口類,顯然還會有具體的實現類繼承於它。在Native層,這就是BpBinder(BpBinder.cpp);而在Java層,則是Binder.java中的BinderProxy。事實上,ProcessState::self()->getContextObject(NULL)返回的就是一個BpBinder對象。BinderProxy和BpBinder分別繼承自Java和Native層的IBinder接口。其中BpBinder是由ProcessState創建的,而BinderProxy是由javaObjectForIBinder()函數通過JNI的NewObject()創建的。

ProcessState和IPCThreadState

實現ProcessState的關鍵點在於:
1.保證同一個進程中只有一個ProcessState實例存在,而且只有在ProcessState對象創建時纔打開Binder設備以及做內存映射。
2.向上層提供IPC服務
3.與IPCThreadState分工合作,各司其職。
我們來看一下ProcessState的代碼:

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/libs/binder/ProcessState.cpp
//這個函數我們在之前的獲取ContextObject的時候用到過,訪問ProcessState需要使用ProcessStata::Self()。
//如果當前已經有實例(gProcess不爲空)存在,就直接返回這個對象;否則,新建一個ProcessState。
sp<ProcessState> ProcessState::self()
{
    Mutex::Autolock _l(gProcessMutex);
    if (gProcess != NULL) {
        return gProcess;
    }
    gProcess = new ProcessState;//創建對象
    return gProcess;
}
ProcessState::ProcessState()
    : mDriverFD(open_driver())//注意這裏打開驅動
    , mVMStart(MAP_FAILED)
    , mManagesContexts(false)
    , mBinderContextCheckFunc(NULL)
    , mBinderContextUserData(NULL)
    , mThreadPoolStarted(false)
    , mThreadPoolSeq(1)
{
    if (mDriverFD >= 0) {//成功打開/dev/binder
        // XXX Ideally, there should be a specific define for whether we
        // have mmap (or whether we could possibly have the kernel module
        // availabla).
#if !defined(HAVE_WIN32_IPC)
        // 開始執行mmap,內存塊大小爲:BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)),即接近1M的空間
        mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
        if (mVMStart == MAP_FAILED) {
            // *sigh*
            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
            close(mDriverFD);
            mDriverFD = -1;
        }
#else
        mDriverFD = -1;
#endif
    }

    LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver could not be opened.  Terminating.");
}

void ProcessState::setContextObject(const sp<IBinder>& object)
{
    setContextObject(object, String16("default"));
}

<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
{
    return getStrongProxyForHandle(0);//傳入0,代表Service Manager
}
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
    sp<IBinder> result;//需要返回的IBinder

    AutoMutex _l(mLock);
    /**查找一個Vector表mHandleToObject,這裏保存了這個進程已經建立的Binder相關信息。
    如果沒有找到相應節點,會自動添加一個。所以返回值正常情況下爲非空。
    mHandleToObject記錄所有與Binder對象相關的信息,而每個表項是一個handle_entry,包含了
    如下數據:
    struct handle_entry{IBinder * binder;RefBase::weakref_type * refs;};
    其中的binder屬性實際上是一個BpBinder,而且程序只有在以下兩種情況下才會生成一個BpBinder:
    1.在列表中沒有找到對應的BpBinder。
    2.雖然從列表中查找到了對應的節點,但是沒有辦法順利對這個BpBinder增加weakreference.
    **/
    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;
            }

            b = new BpBinder(handle);//BpBinder出現了。
            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;
}


ProcessState::handle_entry* ProcessState::lookupHandleLocked(int32_t handle)
{
    const size_t N=mHandleToObject.size();
    if (N <= (size_t)handle) {
        handle_entry e;
        e.binder = NULL;
        e.refs = NULL;
        status_t err = mHandleToObject.insertAt(e, N, handle+1-N);
        if (err < NO_ERROR) return NULL;
    }
    return &mHandleToObject.editItemAt(handle);
}
static int open_driver()
{
    int fd = open("/dev/binder", O_RDWR);
    if (fd >= 0) {
        fcntl(fd, F_SETFD, FD_CLOEXEC);
        int vers = 0;
        status_t result = ioctl(fd, BINDER_VERSION, &vers);
        if (result == -1) {
            ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
            close(fd);
            fd = -1;
        }
        if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
            ALOGE("Binder driver protocol does not match user space protocol!");
            close(fd);
            fd = -1;
        }
        size_t maxThreads = 15;
        result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
        if (result == -1) {
            ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
        }
    } else {
        ALOGW("Opening '/dev/binder' failed: %s\n", strerror(errno));
    }
    return fd;
}
...........................................................//代碼省略

上面的代碼註釋中講到了什麼情況下才會生成一個BpBinder,那我們看一下BpBinder的構造函數

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/libs/binder/BpBinder.cpp
BpBinder::BpBinder(int32_t handle)
    : mHandle(handle)//如果是SM,handle爲0
    , mAlive(1)
    , mObitsSent(0)
    , mObituaries(NULL)
{
    ALOGV("Creating BpBinder %p handle %d\n", this, mHandle);

    extendObjectLifetime(OBJECT_LIFETIME_WEAK);
    IPCThreadState::self()->incWeakHandle(handle);//IPCThreadState出現了
}
status_t BpBinder::transact(
    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
    // Once a binder has died, it will never come back to life.
    if (mAlive) {
        status_t status = IPCThreadState::self()->transact(
            mHandle, code, data, reply, flags);//在ServiceManagerProxy中的mRemote.transact最終調用的是IPCThreadState:self()->transact
        if (status == DEAD_OBJECT) mAlive = 0;
        return status;
    }

    return DEAD_OBJECT;
}

我們前面說過IPCThreadState負責與Binder驅動進行具體的命令交互(ProcessState只是負責打開了Binder節點並做mmap),下面我們看看IPCThreadState的代碼:

//http://androidxref.com/5.1.0_r1/xref/frameworks/native/libs/binder/IPCThreadState.cpp
IPCThreadState* IPCThreadState::self()
{
   /*當第一次被調用時,gHaveTLS爲false,因而不會進入第一個if判斷中,也不會創建IPCThreadState.但是隨後
   它就會進入第二個if判斷並啓動TLS,然後返回restart處新建一個IPCThreadState。當以後再被調用時,gHaveTLS
   爲true,如果本線程已經創建過IPCThreadState,那麼pthread_getspecific就不爲空;否則返回一個新建的IPCThreadState
   */
    if (gHaveTLS) {//這個變量初始值是false
    restart://當啓用TLS後,重新回到這
        const pthread_key_t k = gTLS;
        IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
        if (st) return st;
        return new IPCThreadState;
    }

    if (gShutdown) return NULL;

    pthread_mutex_lock(&gTLSMutex);
    if (!gHaveTLS) {
        if (pthread_key_create(&gTLS, threadDestructor) != 0) {
            pthread_mutex_unlock(&gTLSMutex);
            return NULL;
        }
        gHaveTLS = true;//以後都是TLS了
    }
    pthread_mutex_unlock(&gTLSMutex);
    goto restart;//返回restart接着執行
}
IPCThreadState::IPCThreadState()
    : mProcess(ProcessState::self()),//ProcessState整個進程只有一個
      mMyThreadId(androidGetTid()),//當前的線程id
      mStrictModePolicy(0),
      mLastTransactionBinderFlags(0)
{
    pthread_setspecific(gTLS, this);
    clearCaller();
    mIn.setDataCapacity(256);//mIn是一個Parcel,從名稱可以看出來,它是用於接收Binder發過來的數據的,最大容量爲256
    mOut.setDataCapacity(256);//mOut也是一個Parcel,它是用於存儲要發送給Binder的命令數據的,最大容量爲256
}
void IPCThreadState::incWeakHandle(int32_t handle)
{
    LOG_REMOTEREFS("IPCThreadState::incWeakHandle(%d)\n", handle);
    mOut.writeInt32(BC_INCREFS);
    mOut.writeInt32(handle);
}

void IPCThreadState::decWeakHandle(int32_t handle)
{
    LOG_REMOTEREFS("IPCThreadState::decWeakHandle(%d)\n", handle);
    mOut.writeInt32(BC_DECREFS);
    mOut.writeInt32(handle);
}
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_LOG_TRANSACTIONS() {
        TextOutput::Bundle _b(alog);
        alog << "BC_TRANSACTION thr " << (void*)pthread_self() << " / hand "
            << handle << " / code " << TypeCode(code) << ": "
            << indent << data << dedent << endl;
    }

    if (err == NO_ERROR) {
        LOG_ONEWAY(">>>> SEND from pid %d uid %d %s", getpid(), getuid(),
            (flags & TF_ONE_WAY) == 0 ? "READ REPLY" : "ONE WAY");
        /*將數據打包成Binder驅動協議規定的格式,這個過程由writeTransactionData來完成(注意:
        這個函數只是整理數據,並把結果存入mOut中。而在talkWithDriver()方法中才會將命令真正發
        送給Binder驅動)*/
        err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
    }

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

    if ((flags & TF_ONE_WAY) == 0) {
        #if 0
        if (code == 4) { // relayout
            ALOGI(">>>>>> CALLING transaction 4");
        } else {
            ALOGI(">>>>>> CALLING transaction %d", code);
        }
        #endif
        if (reply) {
            err = waitForResponse(reply);
        } else {
            Parcel fakeReply;
            err = waitForResponse(&fakeReply);
        }
        #if 0
        if (code == 4) { // relayout
            ALOGI("<<<<<< RETURNING transaction 4");
        } else {
            ALOGI("<<<<<< RETURNING transaction %d", code);
        }
        #endif

        IF_LOG_TRANSACTIONS() {
            TextOutput::Bundle _b(alog);
            alog << "BR_REPLY thr " << (void*)pthread_self() << " / hand "
                << handle << ": ";
            if (reply) alog << indent << *reply << dedent << endl;
            else alog << "(none requested)" << endl;
        }
    } else {
        err = waitForResponse(NULL, NULL);
    }

    return err;
}

status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
    int32_t cmd;
    int32_t err;

    while (1) {
        if ((err=talkWithDriver()) < NO_ERROR) break;//將已有數據進行必要的包裝,然後發送給Binder驅動
        err = mIn.errorCheck();//錯誤檢查
        if (err < NO_ERROR) break;//數據有錯誤
        if (mIn.dataAvail() == 0) continue;//如果沒有可用數據,進入下一輪循環

        cmd = mIn.readInt32();//讀取cmd

        IF_LOG_COMMANDS() {
            alog << "Processing waitForResponse Command: "
                << getReturnString(cmd) << endl;
        }

        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:
            {
                ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                const int32_t result = mIn.readInt32();
                if (!acquireResult) continue;
                *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
            }
            goto finish;

        case BR_REPLY:
            {
                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);
            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;
}

status_t IPCThreadState::talkWithDriver(bool doReceive)
{
    if (mProcess->mDriverFD <= 0) {//Binder驅動設備還沒打開
        return -EBADF;
    }

    binder_write_read bwr;//讀寫都使用這個數據結構

    // Is the read buffer empty?
    const bool needRead = mIn.dataPosition() >= mIn.dataSize();

    // We don't want to write anything if we are still reading
    // from data left in the input buffer and the caller
    // has requested to read the next data.
    const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;

    bwr.write_size = outAvail;
    bwr.write_buffer = (uintptr_t)mOut.data();

    // This is what we'll read.
    if (doReceive && needRead) {
        bwr.read_size = mIn.dataCapacity();
        bwr.read_buffer = (uintptr_t)mIn.data();
    } else {
        bwr.read_size = 0;
        bwr.read_buffer = 0;
    }

    IF_LOG_COMMANDS() {
        TextOutput::Bundle _b(alog);
        if (outAvail != 0) {
            alog << "Sending commands to driver: " << indent;
            const void* cmds = (const void*)bwr.write_buffer;
            const void* end = ((const uint8_t*)cmds)+bwr.write_size;
            alog << HexDump(cmds, bwr.write_size) << endl;
            while (cmds < end) cmds = printCommand(alog, cmds);
            alog << dedent;
        }
        alog << "Size of receive buffer: " << bwr.read_size
            << ", needRead: " << needRead << ", doReceive: " << doReceive << endl;
    }

    // Return immediately if there is nothing to do.
    if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;

    bwr.write_consumed = 0;//>0說明Binder驅動消耗了mOut中的數據
    bwr.read_consumed = 0;//>0說明Binder驅動已經成功幫我們讀取到了數據,並寫入了mIn.data().
    status_t err;
    do {
        IF_LOG_COMMANDS() {
            alog << "About to read/write, write size = " << mOut.dataSize() << endl;
        }
#if defined(HAVE_ANDROID_OS)
        /*執行完ioctl後,通過bwr.write_consumed和bwr.read_consumed可以知道Binder驅動對
        我們請求的BINDER_WRITE_READ命令的處理情況,然後對mIn和mOut做善後處理*/
        if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
            err = NO_ERROR;
        else
            err = -errno;
#else
        err = INVALID_OPERATION;
#endif
        if (mProcess->mDriverFD <= 0) {
            err = -EBADF;
        }
        IF_LOG_COMMANDS() {
            alog << "Finished read/write, write size = " << mOut.dataSize() << endl;
        }
    } while (err == -EINTR);

    IF_LOG_COMMANDS() {
        alog << "Our err: " << (void*)(intptr_t)err << ", write consumed: "
            << bwr.write_consumed << " (of " << mOut.dataSize()
                        << "), read consumed: " << bwr.read_consumed << endl;
    }

    if (err >= NO_ERROR) {
        if (bwr.write_consumed > 0) {
            if (bwr.write_consumed < mOut.dataSize())
                mOut.remove(0, bwr.write_consumed);
            else
                mOut.setDataSize(0);
        }
        if (bwr.read_consumed > 0) {
            mIn.setDataSize(bwr.read_consumed);
            mIn.setDataPosition(0);
        }
        IF_LOG_COMMANDS() {
            TextOutput::Bundle _b(alog);
            alog << "Remaining data size: " << mOut.dataSize() << endl;
            alog << "Received commands from driver: " << indent;
            const void* cmds = mIn.data();
            const void* end = mIn.data() + mIn.dataSize();
            alog << HexDump(cmds, mIn.dataSize()) << endl;
            while (cmds < end) cmds = printReturnCommand(alog, cmds);
            alog << dedent;
        }
        return NO_ERROR;
    }

    return err;
}

注意不管是讀取還是寫入,Binder驅動只是發揮中間人的作用,真正處理請求的還是Binder Client和Binder Server通信雙方。

下面我們簡單的來總結一下:
1.ServiceManagerProxy

當某個Binder Server在啓動時,會把自己的名稱name與對應的Binder句柄值保存在ServiceManager中。調用者通常只知道Binder Server的名稱,所以必須先向Service Manager發起查詢請求,就是getService(name)。任何Binder Client都可以直接通過
0這個Binder句柄創建一個BpBinder,再通過Binder驅動去獲取Service Manager的服務,具體而言,就是調用BinderInternal的 getContextObject()來獲得Service Manager的BpBinder.Android系統同時支持Java與C/C++層的Binder機制,因而很多對象 都必須有”雙重身份”,如BpBinder在Java層以IBinder來表示。對於Service Manager而言,IBinder的真正持有者與使用者是ServiceManagerProxy.

2.ProcessState和IPCThreadState

大多數程序都有IPC的需要,而進程間通信本身又是非常煩瑣的,因而Android系統特別爲程序進程使用Binder機制封裝了兩個實現類,即ProcessState和IPCThreadState。從名稱上可以看出,前者是進程相關的,而後者是線程相關的。ProcessState負責打開Binder驅動設備,進行mmap()等準備工作,而如何與Binder驅動進行具體的命令通信則由IPCThreadState來完成。在getService()這個場景中,調用者是從Java層的IBinder.transact()開始,層層往下調用到IPCThreadState.transact(),然後通過waitForResponse進入主循環,直至收到Service Manager的回覆後才跳出循環,並將結果再次層層回傳到應用層。

注意:真正與Binder驅動打交道的地方是talkWithDriver中的ioctl(),整個流程中多次調用了這個函數。

3.Binder驅動

Binder驅動通過巧妙的機制來使數據的傳遞更加高效,即只需要一次複製就可以把數據從一個進程複製到另一個進程。Binder中還保存着大量的全局以及進程相關的變量,用於管理每個進程/線程的狀態,內存申請和待辦事項等一系列複雜的數據信息。正是這些變量的有效協作,才使得整個Binder通信真正”動”了起來。

4.Service Manager的實現

ServiceManager在Android系統啓動之後就運行起來了,並通過BINDER_SET_CONTEXT_MGR把自己註冊成Binder”“大管家”.它在做完一系列初始
化後,在最後一次ioctl的read操作中會進入等待,直到有Binder Client發起服務請求而被Binder驅動喚醒。Service Manager喚醒後,程序分爲兩條主線索。其一,Service Manager端將接着執行read操作,把調用者的具體請求讀取出來,然後利用binder_parse解析,再根據實際情況填寫transaction信息,最後把結果BR_REPLY命令(也是ioctl)返回Binder驅動。其二,發起getService請求的Binder Client在等待Service Manager回覆的過程中會進入休眠,直到被Binder驅動再次喚醒——它和Service Manager一樣也是在read中睡眠的,因而醒來後繼續執行讀取操作。這一次得到的就是Service Manager對請求的執行結果。程序先把結果填充到reply這個Parcel中,然後通過層層返回到ServiceManagerProxy,再利用Parcel.readStrongBinder生成一個BpBinder,最終經過類型轉換爲IBinder對象後傳給調用者。

Binder客戶端——Binder Client

Binder的最大”“消費者”是Java層的應用程序。關於Binder Client,我們只需要知道的是Binder的Client端和Server端需要繼承同樣的公共接口類。Binder Client提供了與Binder Sever一樣的函數原型,使用戶感覺不出Server是運行在本地還是遠端。

Android接口描述語言——AIDL

AIDL是Android Interface Description Language 的簡寫。從名稱上看它是一種語言,而且是專門用於描述接口的語言。準確地說,它是用於定義客戶端/服務端通信接口的一種描述語言。

這裏我們先看一下構建一個Binder Server所需的工作是怎樣的,主要考慮的因素如下:

1.啓動的時機:主要考慮什麼時候啓動,比如SM是開機的時候通過init.rc文件啓動的,這就保證了它是系統中第一個註冊成”“服務大管家”的Service。

2.提供一致的服務接口:顯然,一個Binder Server應該向公衆暴露它所能提供的服務;而且客戶端使用的服務接口和服務端實現的服務接口必須是完全 一致的。注意這裏有個不一樣的地方,SM中的服務接口是IServiceManager。客戶端本地進程中的ServiceManagerProxy及 ServiceManagerNative都繼承自這個接口。而它的服務端是直接用C語言實現的(Service_mananger.c)。不過通過分析其內部 binder_parse函數可知,它還是保持了與客戶端接口的一致。

3.與Binder驅動的交互方式:一個Binder Server需要與Binder Driver做哪些交互呢?除去一系列必要的初始化以外(open,mmap等),就是要通過不斷地ioctl來循環讀寫數據。比如SM就是通過binder_loop函數中的一個for死循環來完成這一工作的。

4.外界如何能訪問到這個Server的服務:訪問Server主要有兩種方法:
(1)Server在ServiceManager中註冊:這種方法普遍存在於Android系統服務中,如ActivityManagerService,WindowManagerService等都在ServiceManager中做了註冊。調用者只要通過ServiceManager.getService(SERVICE_NAME)就可以獲取到Binder Server的本地代理,然後與之通信
(2)通過其他Server作爲中介:這是一種”“匿名”的方法。換句話說,這種類型的Binder Server不需要在ServiceManager中註冊,通過一個”“第三方”的”實名”Sever——因爲是實名的,調用者可以通過ServiceManager來首先訪問到
它,然後由它提供的接口獲取”匿名”者的Binder句柄。

關於匿名Binder Server與實名Server的差異主要就在於後者是通過ServiceManager來獲得對它的引用,而前者則是以其他實名Server爲中介來傳遞這一引用信息。

注:關於Android系統的深入知識也是之前一年的主要學習內容,由於沒有去記錄,導致了看過的許多東西都忘記了,感覺就是沒有學習一樣,最近的一段時間會陸續的整理出一些東西,Android系統的深入知識,主要參考資料爲博客與《深入理解Android內核設計思想》等,當然還有源碼。另:需要說明一點的是,文章標題以說明爲筆記,所以大部分內容爲摘抄,主要來源書籍。

轉載請註明出處:http://blog.csdn.net/android_jiangjun/article/details/76691860

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章