Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android7.0 Binder通信(1) ServiceManger

Android7.0 Binder通信(1) ServiceManger

編輯:關於Android編程

背景
Android是基於Linux的操作系統,在其中運行的應用或者系統服務,實際上就是一個個Linux進程。這意味著它們彼此之間是隔離的,必須通過進程間通信(IPC)來相互傳輸數據。Binder就是Android實現的一種IPC通信方式。

然而我們知道,Linux已經提供了一些進程間通信的機制,例如socket和pipes等,為什麼Android還要重新“造輪子”,創造一種新的IPC機制呢?
為了弄明白這個問題,自己參考了一些外文資料,其中比較讓人信服的答案是:為了更好的性能。

我們知道Android中所有的系統功能都是由不同的服務進程提供的。
客戶進程如果想使用某個功能,必須發送請求給對應的服務進程,然後等待結果。
由於Android有大量的這種通信需求,因此整個系統內部可能會頻繁地發生進程間通信。也就是說,Android對進程間通信有高度的依賴性。
Android為了提高系統整體的傳輸效率,需要一種優化過的進程間通信方式。於是,Binder機制應運而生。

Binder機制起源於一個簡單的想法:將申請服務的請求和對應的響應信息,寫入一個所有進程均能夠訪問的地址空間中。
當進程需要使用這些數據時,只需要訪問對應的內存地址,以減小內容復制引入的開銷。
為此,Binder機制利用kernel空間作為共享區域,並由Binder driver來建立起每個進程的內存地址與kernel空間中存儲地址的映射。

 


 

版本
android 7.0

Binder通信的整體架構
引入了Binder機制後,Android中基於Binder的進程間通信,整體上仍是一種C/S結構。

 


 

1.如上圖所示,ServiceManger負責管理系統中的各種服務。Server進程首先要注冊一些服務一些服務到ServiceManager中,所以在這個過程中,Server進程是ServiceManager的客戶端。
2.如果某個Client進程要使用某個Service,必須先到ServiceManager中獲取該Service相關的信息,所以在此過程中,Client進程是ServiceManager的客戶端。
3.Client進程獲取到Service信息,與Server進程建立通信後,就可以直接與Server進程通信了,在此過程中Client進程是Server進程的客戶端。

以上3種通信方式,均是基於Binder通信的,我們將按照先後順序依次分析:ServiceManager,Server進程的注冊,Client進程的查詢及使用。
在這篇博客中,我們先一起看一下ServiceManager中主要的流程。

ServiceManager

1 服務啟動

service servicemanager /system/bin/servicemanager
    class core
    user system
    group system readproc
    critical
    onrestart restart healthd
    onrestart restart zygote
    onrestart restart audioserver
    onrestart restart media
    onrestart restart surfaceflinger
    onrestart restart inputflinger
    onrestart restart drm
    onrestart restart cameraserver
    writepid /dev/cpuset/system-background/tasks

如上所示,在android7.0中,文件frameworks/native/cmds/servicemanager/servicemanager.rc文件中定義了servicemanager,可以看到servicemanager對應的keyword是service。在分析init進程時,我們知道init進程解析rc文件時,遇到service關鍵字後,僅利用其後的信息構造出service對象,並不會立即啟動service。
那麼servicemanager是如何被加載的呢?

在init.rc中,定義了early-init, init, late-init, early-boot, boot這樣的字段,以定義命令的先後執行順序,在init.cpp的main函數中有:

.............
ActionManager& am = ActionManager::GetInstance();
am.QueueEventTrigger("early-init");
.............
am.QueueEventTrigger("init");
.............
am.QueueEventTrigger("late-init");

可以明顯的看到,這些字段對應的觸發事件被先後加入到執行隊列中。在init.rc中:

on late-init
    ......
    trigger early-boot
    trigger boot

可以看到在late-init對應的一系列執行命令的最後,將觸發操作early-boot和boot階段。

在boot階段的最後:

on boot
    .......
    class_start core

看到沒?在boot階段的最後,將要進行class_start core的操作。在system/core/init/builtins.cpp中,class_start對應的處理函數是do_class_start:

static int do_class_start(const std::vector& args) {
    //此時,args為“core”
    ServiceManager::GetInstance().
        ForEachServiceInClass(args[1], [] (Service* s) { s->StartIfNotDisabled(); });
    return 0;
}

從上面的代碼,我們容易看出,將對service對象中class字段等於“core”的所有服務,執行StartIfNotDisabled操作。

bool Service::StartIfNotDisabled() {
    if (!(flags_ & SVC_DISABLED)) {
        //啟動服務
        return Start();
    } else {
        flags_ |= SVC_DISABLED_START;
    }
    return true;
}

bool Service::Start() {
    //參數檢查等操作
    ..........
    pid_t pid = fork();
    if (pid == 0) {
        //fork出子進程後,為子進程設置參數
        ......
        //啟動對應的main函數
        if (execve(args_[0].c_str(), (char**) &strs[0], (char**) ENV) < 0) {
            ..............
        }
    }
    ......
}

至此我們終於知道servicemanager是如何啟動的。
根據上面的分析,可以於看出servicemanager運行於獨立的進程中,是init進程的子進程。相比之下,zygote進程的class字段為main,啟動順序在servicemanager之後。

2 Native層的service_manager
現在我們看看定義於frameworks/native/cmds/servicemanager/service_manager.c中的main函數:

int main(int argc, char **argv) {
    ........
    //打開binder驅動
    bs = binder_open(128*1024);
    ........
    //設置為service manager
    if (binder_become_context_manager(bs)) {
        ................
    }
    //配合selinux的一些工作
    .........
    //處理請求
    binder_loop(bs, svcmgr_handler);
}

2.1 binder_open

struct binder_state *binder_open(size_t mapsize) {
    ..........
    //打開binder設備
    bs->fd = open("/dev/binder", O_RDWR | O_CLOEXEC);
    ..........
    //判斷內核版本和用戶空間的版本是否一致
    if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) || (vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
        .............
    }
    ............
    //完成內存映射
    bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
    ............
}

2.2 binder_become_context_manager

int binder_become_context_manager(struct binder_state *bs)
{
    //將ServiceManager對應binder的句柄設為0
    return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}

可以看到,ServiceManager將自己的句柄定義為0,於是其它的進程與其通信時,不需要進行額外的查詢。

2.3 binder_loop

//此處func為svcmgr_handler
void binder_loop(struct binder_state *bs, binder_handler func) {
    ......
    for (;;) {
        .........
        //servicemanager打開binder設備,將自己的句柄設為0後,就不斷的監聽是否有發往自己的數據
        res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
        .........
        //當收到數據後,利用binder_parse解析數據,然後適當的條件下,調用svcmgr_handler處理
        res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
        ..........
    }
}

我們看看binder_parse函數:

int binder_parse(struct binder_state *bs, struct binder_io *bio,
        uintptr_t ptr, size_t size, binder_handler func) {
    ...........
    //ptr指向將讀取數據的首地值,size為數據的總長度
    uintptr_t end = ptr + (uintptr_t) size;

    while (ptr < end) {
        //解析出數據
        uint32_t cmd = *(uint32_t *) ptr;
        //移動ptr
        ptr += sizeof(uint32_t);
        switch(cmd) {
        ...........
        //收到一個實際的傳輸數據
        case BR_TRANSACTION: {
            struct binder_transaction_data *txn = (struct binder_transaction_data *) ptr;
            //判斷讀出的數據大小是否符合要求
            if ((end - ptr) < sizeof(*txn)) {
                ALOGE("parse: txn too small!\n");
                return -1;
            }
            .........
            if (func) {
                ..........
                //調用svcmgr_handler處理收到的數據
                res = func(bs, txn, &msg, &reply);
                if (txn->flags & TF_ONE_WAY) {
                    binder_free_buffer(bs, txn->data.ptr.buffer);
                } else {
                    //發送回復信息
                    binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
                }
            }
            ptr += sizeof(*txn);
            break;
        }
        ...........
        case BR_DEAD_BINDER: {
            struct binder_death *death = (struct binder_death *)(uintptr_t) *(binder_uintptr_t *)ptr;
            ptr += sizeof(binder_uintptr_t);
            //如果與serviceManager通信的binder死亡,需要調用對應的處理函數
            death->func(bs, death->ptr);
        }
        ...........
        }
    }
}

最後,我們來看看svcmgr_handler函數:

int svcmgr_handler(struct binder_state *bs,
                   struct binder_transaction_data *txn,
                   struct binder_io *msg,
                   struct binder_io *reply) {
    //進行參數有效性檢查等操作
    .............
    //根據收到數據中攜帶的code字段,執行相應的操作
    switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        //從收到數據中讀出需查找服務的名稱
        s = bio_get_string16(msg, &len);
        .......
        //得到服務對應的句柄
        //根據名稱進行匹配,在返回信息前會進行權限檢查
        handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid);
        ......
        //將句柄信息寫入reply
        bio_put_ref(reply, handle);
        return 0;

    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len);
        .......
        handle = bio_get_ref(msg);
        allow_isolated = bio_get_uint32(msg) ? 1 : 0;
        //向servicemanager注冊服務
        //在注冊前會進行權限檢查,然後利用參數中的信息,構建出服務對象,加入到全局變量svclist中
        //同時會調用binder_link_to_death監聽新加入服務進程是否死亡
        if (do_add_service(bs, s, len, handle, txn->sender_euid,
                allow_isolated, txn->sender_pid))
            return -1;
        break;

    case SVC_MGR_LIST_SERVICES: {
        //從收到的數據中,取出需要服務的編號
        uint32_t n = bio_get_uint32(msg);

        //權限檢查
        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
            //log
            ......
            return -1;
        }

        //svclist中記錄了注冊到servicemanager的服務的信息
        si = svclist;
        while ((n-- > 0) && si)
            si = si->next;
        if (si) {
            //得到當前注冊到servicemanager的服務中,第n個服務的名稱
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    .............
}

從svcmgr_handler函數,我們可以看出ServiceManager的主要功能包括:
1. 集中管理系統內的所有服務,無論其它進程增加服務還是查詢服務,ServiceManager均會進行權限檢查。
2. ServiceManager支持通過字符串查找對應的Service。這一點與DNS很像,用戶將域名發送給DNS,DNS返回實際的IP地址給用戶。
3. ServiceManager監控服務是否正常。由於各種原因的影響,Android中的服務進程可能異常終止。如果讓每個Client都去進行檢測,那麼開銷太大。假設同時存在n個Client、n個Service,那麼每個Client為了知道Service的狀態,將進行n2次通信。
ServiceManager來負責統一監控後,ServiceManager來監聽每個Service的狀態,Client只需要通過ServiceManager就能得到服務端的狀態,此時只需要2n次通信即可。

結束語
本篇博客主要目的是分析Binder通信的起源、基本架構,以及ServiceManager的主要作用。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved