Android系統的Binder機制之一——Service Manager

Android雖然構建在Linux上面,可是在IPC(進程間)機制方面,沒有利用Linux提供IPC機制,而是本身實現了一套輕量級的IPC機制——binder機制。而且Android Binder機制之上,Android框架提供了一套封裝,能夠實現對象代理(在本地進程中代理遠程進程的對象)。本文簡單分析一下Android Binder機制。服務器

Binder情景分析

    一個IPC通信咱們能夠理解成客戶端-服務器模式,所以咱們先在這裏分析一下典型的Binder應用模式:框架

一、客戶端經過某種方式(後文會詳細介紹)獲得服務器端的代理對象。從客戶端角度看來代理對象和他的本地對象沒有什麼差異。它能夠像其餘本地對象同樣調用其方法,訪問其變量。 
二、客戶端經過調用服務器代理對象的方法向服務器端發送請求。 
三、代理對象把用戶請求經過Android內核(Linux內核)的Binder驅動發送到服務器進程。 
四、服務器進程處理用戶請求,並經過Android內核(Linux內核)的Binder驅動返回處理結果給客戶端的服務器代理對象。 
五、客戶端收到服務器端的返回結果。
函數

    若是你對COM或者Corba熟悉的話,以上的情景是否會讓你聯想到什麼呢?沒錯!都是對象代理。以上的情景,在Android中常常會被用到。若是你尚未注意到這點兒,那麼本文很是適合你。oop

Binder機制的組成

一、Binder驅動

    binder是內核中的一個字符驅動設備位於:/dev/binder。這個設備是Android系統IPC的核心部分,客戶端的服務代理用來經過它向服務器(server)發送請求,服務器也是經過它把處理結果返回給客戶端的服務代理對象。咱們只須要知道它的功能就能夠了,本文咱們的重點不在這裏,因此後面不會專門介紹這部分,由於不多會有人會顯示打開這個設備去開發Android程序。若是想深刻了解的話,請研究內核源碼中的binder.c。ui

二、Service Manager

    負責管理服務。對應於第一步中,客戶端須要向Service Manager來查詢和得到所須要服務。服務器也須要向Service Manager註冊本身提供的服務。能夠看出Service Manager是服務的大管家。spa

三、服務(Server)

    須要強調的是這裏服務是指的是System Server,而不是SDK server,請參考《(轉)高煥堂——Android框架底層結構知多少?》關於兩種Server的介紹(其實應該是三種,丟掉了init調用的server,在init.rc中配置)。.net

四、客戶端

    通常是指Android系統上面的應用程序。它能夠請求Server中的服務。代理

五、對象代理

    是指在客戶端應用程序中生成的Server代理(proxy)。從應用程序角度看代理對象和本地對象沒有差異,均可以調用其方法,方法都是同步的,而且返回相應的結果。unix

大內總管——Service Manager

    Android系統Binder機制的總管是Service Manager,全部的Server(System Server)都須要向他註冊,應用程序須要向其查詢相應的服務。可見其做用是多麼的重要,因此本文首先介紹Service Manager。rest

    經過上面介紹咱們知道Service Manager很是重要,責任重大。那麼怎樣才能成爲Service Manager呢?是否是誰均可以成爲Service Manager呢?怎樣處理server的註冊和應用程序的查詢和獲取服務呢?爲了回答這些問題先查看,Android中Service Manager的源碼,其源碼位於:

frameworks\base\cmds\servicemanager\service_manager.c

咱們發現了main函數,說明他本身就是一個進程,在init.rc中咱們發現:

service servicemanager /system/bin/servicemanager
    user system     critical
    onrestart restart zygote
    onrestart restart media

說明其是Android核心程序,開機就會自動運行。

    下面咱們在研究一下它的代碼,main函數很簡單:

int main(int argc, char **argv)
{
    struct binder_state *bs;
    void *svcmgr = BINDER_SERVICE_MANAGER;

    bs = binder_open(128*1024);

    if (binder_become_context_manager(bs)) {
        LOGE("cannot become context manager (%s)\n", strerror(errno));
        return -1;
    }

    svcmgr_handle = svcmgr;
    binder_loop(bs, svcmgr_handler);
    return 0;
}

咱們看到它先調用binder_open打開binder設備(/dev/binder),其次它調用了binder_become_context_manager函數,這個函數使他本身變爲了「Server大總管」,其代碼以下:

int binder_become_context_manager(struct binder_state *bs)
{
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

也就是經過ioctl向binder設備聲明「我就是server大總管」。

    Service Manager做爲一個Server大總管,自己也是一個server。既然是一個server就要時刻準備爲客戶端提供服務。最好Service Manager調用binder_loop進入到循環狀態,並提供了一個回調函數,等待用戶的請求。注意他的Service Manager的客戶端既包括應用程序(查詢和獲取服務),也包括Server(註冊服務)。

    Service Manager的客戶怎樣才能請求其服務呢?答案是上文咱們提到的情景同樣。客戶須要在本身進程中建立一個服務器代理。如今沒有地方去查詢服務,那麼怎樣它的客戶怎樣生成他的服務代理對象呢?答案是binder設備(/devbinder)爲每個服務維護一個句柄,調用binder_become_context_manager函數變爲「Server大總管」的服務,他的句柄永遠是0,是一個「衆所周知」的句柄,這樣每一個程序均可以經過binder機制在本身的進程空間中建立一個

Service Manager代理對象了。其餘的服務在binder設備在設備中的句柄是不定的,須要向「Server大總管」查詢才能知道。

    如今咱們須要研究Server怎樣註冊服務了,仍是在其源碼中,咱們能夠看到在其服務處理函數中(上文提到binder_loop函數註冊給binder設備的回調函數)有以下代碼:

case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = bio_get_ref(msg);
        if (do_add_service(bs, s, len, ptr, txn->sender_euid))
            return -1;
        break;

有server向binder設備寫入請求註冊Service時,Service Manager的服務處理回調函數將會被調用。咱們在仔細看看do_add_service函數的實現:

int do_add_service(struct binder_state *bs,
                   uint16_t *s, unsigned len,
                   void *ptr, unsigned uid)
{
    struct svcinfo *si;// LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);     if (!ptr || (len == 0) || (len > 127))
        return -1;

    if (!svc_can_register(uid, s)) {
        LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
             str8(s), ptr, uid);
        return -1;
    }

    si = find_svc(s, len);
    if (si) {
        if (si->ptr) {
            LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",
                 str8(s), ptr, uid);
            return -1;
        }
        si->ptr = ptr;
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {
            LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
                 str8(s), ptr, uid);
            return -1;
        }
        si->ptr = ptr;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
        si->name[len] = '\0';
        si->death.func = svcinfo_death;
        si->death.ptr = si;
        si->next = svclist;
        svclist = si;
    }

    binder_acquire(bs, ptr);
    binder_link_to_death(bs, ptr, &si->death);
    return 0;
}

咱們看到首先檢查是否有權限註冊service,沒權限就對不起了,出錯返回;而後檢查是否已經註冊過,註冊過的service將不能再次註冊。而後構造一個svcinfo對象,並加入一個全局鏈表中svclist中。最後通知binder設備:有一個service註冊進來

    咱們再來看看客戶端怎樣經過Service Manager得到Service,仍是在服務處理函數中(上文提到binder_loop函數註冊給binder設備的回調函數)有以下代碼:

case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len);
        if (!ptr)
            break;
        bio_put_ref(reply, ptr);
        return 0;

    咱們能夠看到經過do_find_service查找Service若是查找到的話,寫入reply中返回給客戶端。

    本文咱們簡單分析了一下Service Manager,後續咱們會繼續分析Android binder機制的其餘部分。

相關文章
相關標籤/搜索