Android 之 ServiceManager與服務管理

是android中比較重要的一個進程,它是在init進程啟動之後啟動,從名字上就可以看出來它是用來管理系統中的service。比如:InputMethodService、ActivityManagerService等。在ServiceManager中有兩個比較重要的方法:add_service、check_service。系統的service需要通過add_service把自己的信息註冊到ServiceManager中,當需要使用時,通過check_service檢查該service是否存在。

主函數(anrdroid4.0/frameworks/base/cmds/servicemanager/service_manager.c)

從它的主函數代碼開始:

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;
}
從main函數中可以看出,它主要做瞭三件事情:

打開/dev/binder設備,並在內存中映射128K的空間。
通知Binder設備,把自己變成context_manager
進入循環,不停的去讀Binder設備,看是否有對service的請求,如果有的話,就去調用svcmgr_handler函數回調處理請求。
服務註冊

再來看看ServiceManager中是怎麼樣去註冊服務的。先來看先,當有對service的請求時,調用的回調函數svcmgr_handler: 

int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;
    uint32_t strict_policy;
//  LOGI("target=%p code=%d pid=%d uid=%d\n",
//  txn->target, txn->code, txn->sender_pid, txn->sender_euid);
    if (txn->target != svcmgr_handle)
        return -1;
    // 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);
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
        fprintf(stderr,"invalid id %s\n", str8(s));
        return -1;
    }
    switch(txn->code) {
    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;
    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;
    case SVC_MGR_LIST_SERVICES: {
        unsigned n = bio_get_uint32(msg);
        si = svclist;
        while ((n– > 0) && si)
            si = si->next;
        if (si) {
            bio_put_string16(reply, si->name);
            return 0;
        }
        return -1;
    }
    default:
        LOGE("unknown code %d\n", txn->code);
        return -1;
    }
    bio_put_uint32(reply, 0);
    return 0;
}
在該回調函數中會判斷Service有什麼需要,如果是請求註冊service,那麼久執行:

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;
我們再來看看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,如果沒有權限就直接返回,不能註冊。

if (!svc_can_register(uid, s)) {
        LOGE("add_service('%s',%p) uid=%d – PERMISSION DENIED\n",
             str8(s), ptr, uid);
        return -1;
    }
然後會去檢查該service是否已經註冊過瞭,如果已經註冊過,那麼就不能再註冊瞭:

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;
    }
再判斷內存是否足夠:

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;
        }
如果都沒什麼問題,會註冊該service,加入到svcList中來。註意,在ServiceManager中維護service信息的地方就是svclist。裡面存瞭service的name和handler。

服務獲取

通過以上幾個步驟,service就算註冊成功瞭。那麼當要獲得該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;

如果是獲取service,那麼執行SVC_MGR_CHECK_SERVICE,並把返回的數據寫入reply,返回給客戶端。

do_find_service函數中主要執行service的查找。

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
{
    struct svcinfo *si;
    si = find_svc(s, len);
//    LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
    if (si && si->ptr) {
        return si->ptr;
    } else {
        return 0;
    }
}
這樣在ServiceManager中就完成瞭服務的註冊和查找。來看下ServiceManager的功能圖:

 
 

 

發佈留言