1. 程式人生 > >Android 8.0 啟動ServiceManager

Android 8.0 啟動ServiceManager

一、簡述

framework/native/cmds/servicemanager/
  - service_manager.c
  - binder.c
  
kernel/drivers/ (不同Linux分支路徑略有不同)
  - staging/android/binder.c
  - android/binder.c 

ServiceManager是Binder IPC通訊過程中的守護程序,本身也是一個Binder服務,但並沒有採用libbinder中的多執行緒模型來與Binder驅動通訊,而是自行編寫了binder.c直接和Binder驅動來通訊,並且只有一個迴圈binder_loop來進行讀取和處理事務,這樣的好處是簡單而高效。

ServiceManager本身工作相對簡單,其功能:查詢和註冊服務。 對於Binder IPC通訊過程中,其實更多的情形是BpBinder和BBinder之間的通訊,比如ActivityManagerProxy和ActivityManagerService之間的通訊等。

流程

啟動過程

ServiceManager是由init程序通過解析init.rc檔案而建立的,其所對應的可執行程式/system/bin/servicemanager,所對應的原始檔是service_manager.c,程序名為/system/bin/servicemanager。

service servicemanager /system
/bin/servicemanager class core user system group system critical onrestart restart healthd onrestart restart zygote onrestart restart media onrestart restart surfaceflinger onrestart restart drm

啟動Service Manager的入口函式是service_manager.c中的main()方法,程式碼如下:

main

[ -> service_manager.c]

int main(int argc, char **argv)
{
    struct binder_state *bs;
    //開啟binder驅動,申請128k位元組大小的記憶體空間
    bs = binder_open(128*1024);
    ...

    //成為上下文管理者 【見小節2.3】
    if (binder_become_context_manager(bs)) {
        return -1;
    }

    selinux_enabled = is_selinux_enabled(); //selinux許可權是否使能
    sehandle = selinux_android_service_context_handle();
    selinux_status_open(true);

    if (selinux_enabled > 0) {
        if (sehandle == NULL) {  
            abort(); //無法獲取sehandle
        }
        if (getcon(&service_manager_context) != 0) {
            abort(); //無法獲取service_manager上下文
        }
    }
    ...

    //進入無限迴圈,處理client端發來的請求
    binder_loop(bs, svcmgr_handler);
    return 0;
}

二、核心工作

servicemanager的核心工作就是註冊服務和查詢服務

2.1 do_find_service

[-> service_manager.c]

uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
    //查詢相應的服務
    struct svcinfo *si = find_svc(s, len);

    if (!si || !si->handle) {
        return 0;
    }

    if (!si->allow_isolated) {
        uid_t appid = uid % AID_USER;
        //檢查該服務是否允許孤立於程序而單獨存在
        if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
            return 0;
        }
    }

    //服務是否滿足查詢條件
    if (!svc_can_find(s, len, spid)) {
        return 0;
    }
    return si->handle;
}

查詢到目標服務,並返回該服務所對應的handle

2.1.1 find_svc

struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
    struct svcinfo *si;

    for (si = svclist; si; si = si->next) {
        //當名字完全一致,則返回查詢到的結果
        if ((len == si->len) &&
            !memcmp(s16, si->name, len * sizeof(uint16_t))) {
            return si;
        }
    }
    return NULL;
}

從svclist服務列表中,根據服務名遍歷查詢是否已經註冊。當服務已存在svclist,則返回相應的服務名,否則返回NULL。

當找到服務的handle, 則呼叫bio_put_ref(reply, handle),將handle封裝到reply.

2.2 do_add_service

[-> service_manager.c]

int do_add_service(struct binder_state *bs,
                   const uint16_t *s, size_t len,
                   uint32_t handle, uid_t uid, int allow_isolated,
                   pid_t spid)
{
    struct svcinfo *si;

    if (!handle || (len == 0) || (len > 127))
        return -1;

    //許可權檢查,>=AID_APP
    if (!svc_can_register(s, len, spid)) {
        return -1;
    }

    //服務檢索
    si = find_svc(s, len);
    if (si) {
        if (si->handle) {
            svcinfo_death(bs, si); //服務已註冊時,釋放相應的服務
        }
        si->handle = handle;
    } else {
        si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
        if (!si) {  //記憶體不足,無法分配足夠記憶體
            return -1;
        }
        si->handle = handle;
        si->len = len;
        memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); //記憶體拷貝服務資訊
        si->name[len] = '\0';
        si->death.func = (void*) svcinfo_death;
        si->death.ptr = si;
        si->allow_isolated = allow_isolated;
        si->next = svclist; // svclist儲存所有已註冊的服務
        svclist = si;
    }

    //以BC_ACQUIRE命令,handle為目標的資訊,通過ioctl傳送給binder驅動
    binder_acquire(bs, handle);
    //以BC_REQUEST_DEATH_NOTIFICATION命令的資訊,通過ioctl傳送給binder驅動,主要用於清理記憶體等收尾工作
    binder_link_to_death(bs, handle, &si->death);
    return 0;
}

static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
    const char *perm = "add";

    if (multiuser_get_app_id(uid) >= AID_APP) {
        return 0; /* Don't allow apps to register services */
    }

    return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
} 

註冊服務的分以下3部分工作:

  • svc_can_register:檢查許可權,檢查selinux許可權是否滿足;
  • find_svc:服務檢索,根據服務名來查詢匹配的服務;
  • svcinfo_death:釋放服務,當查詢到已存在同名的服務,則先清理該服務資訊,再將當前的服務加入到服務列表svclist;

三. 總結

ServiceManger集中管理系統內的所有服務,通過許可權控制程序是否有權註冊服務,通過字串名稱來查詢對應的Service;由於ServiceManger程序建立跟所有向其註冊服務的死亡通知, 那麼當服務所在程序死亡後, 會只需告知ServiceManager.每個Client通過查詢ServiceManager可獲取Server程序的情況,降低所有Client程序直接檢測會導致負載過重。

ServiceManager啟動流程:

  1. 開啟binder驅動,並呼叫mmap()方法分配128k的記憶體對映空間:binder_open();
  2. 通知binder驅動使其成為守護程序:binder_become_context_manager();
  3. 驗證selinux許可權,判斷程序是否有權註冊或檢視指定服務;
  4. 進入迴圈狀態,等待Client端的請求:binder_loop()。
  5. 註冊服務的過程,根據服務名稱,但同一個服務已註冊,重新註冊前會先移除之前的註冊資訊;
  6. 死亡通知: 當binder所在程序死亡後,會呼叫binder_release方法,然後呼叫binder_node_release.這個過程便會發出死亡通知的回撥.

ServiceManager最核心的兩個功能為查詢和註冊服務:

  • 註冊服務:記錄服務名和handle資訊,儲存到svclist列表;
  • 查詢服務:根據服務名查詢相應的的handle資訊。

四. 原始碼目錄

從上之下, 整個Binder架構所涉及的總共有以下5個目錄:

/framework/base/core/java/               (Java)
/framework/base/core/jni/                (JNI)
/framework/native/libs/binder            (Native)
/framework/native/cmds/servicemanager/   (Native)
/kernel/drivers/staging/android          (Driver)

4.1 Java framework

/framework/base/core/java/android/os/  
    - IInterface.java
    - IBinder.java
    - Parcel.java
    - IServiceManager.java
    - ServiceManager.java
    - ServiceManagerNative.java
    - Binder.java  


/framework/base/core/jni/    
    - android_os_Parcel.cpp
    - AndroidRuntime.cpp
    - android_util_Binder.cpp (核心類)

4.2 Native framework

/framework/native/libs/binder         
    - IServiceManager.cpp
    - BpBinder.cpp
    - Binder.cpp
    - IPCThreadState.cpp (核心類)
    - ProcessState.cpp  (核心類)

/framework/native/include/binder/
    - IServiceManager.h
    - IInterface.h

/framework/native/cmds/servicemanager/
    - service_manager.c
    - binder.c

4.3 Kernel

/kernel/drivers/staging/android/
    - binder.c
    - uapi/binder.h

參考網址:

http://gityuan.com/2015/11/07/binder-start-sm/