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

來源:互聯網
上載者:User

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

Binder情景分析

    一個IPC通訊我們可以理解成用戶端-伺服器模式,因此我們先在這裡分析一下典型的Binder應用模式:

1、用戶端通過某種方式(後文會詳細介紹)得到伺服器端的代理對象。從用戶端角度看來代理對象和他的本機物件沒有什麼差別。它可以像其他本機物件一樣調用其方法,訪問其變數。
2、用戶端通過調用伺服器代理對象的方法向伺服器端發送請求。
3、代理對象把使用者請求通過Android核心(Linux核心)的Binder驅動發送到伺服器處理序。
4、伺服器處理序處理使用者請求,並通過Android核心(Linux核心)的Binder驅動返回處理結果給用戶端的伺服器代理對象。
5、用戶端收到伺服器端的返回結果。

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

Binder機制的組成1、Binder驅動

   
binder是核心中的一個字元驅動裝置位於:/dev/binder。這個裝置是Android系統IPC的核心部分,用戶端的服務代理用來通過它向服
務器(server)發送請求,伺服器也是通過它把處理結果返回給用戶端的服務代理對象。我們只需要知道它的功能就可以了,本文我們的重點不在這裡,所以
後面不會專門介紹這部分,因為很少會有人會顯示開啟這個裝置去開發Android程式。如果想深入瞭解的話,請研究核心源碼中的binder.c。

2、Service Manager

    負責管理服務。對應於第一步中,用戶端需要向Service Manager來查詢和獲得所需要服務。伺服器也需要向Service Manager註冊自己提供的服務。可以看出Service Manager是服務的大管家。

3、服務(Server)

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

4、用戶端

    一般是指Android系統上面的應用程式。它可以請求Server中的服務。

5、對象代理

    是指在用戶端應用程式中產生的Server代理(proxy)。從應用程式角度看代理對象和本機物件沒有差別,都可以調用其方法,方法都是同步的,並且返回相應的結果。

大內總管——Service Manager

    Android系統Binder機制的總管是Service Manager,所有的Server(System Server)都需要向他註冊,應用程式需要向其查詢相應的服務。可見其作用是多麼的重要,所以本文首先介紹Service Manager。

    通過上面介紹我們知道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機制的其他部分。

原文

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.