Android 之 ServiceManager與服務管理

yangxi_001發表於2013-11-15

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

主函式

從它的主函式程式碼開始:

[java] view plaincopy
  1. int main(int argc, char **argv)  
  2. {  
  3.     struct binder_state *bs;  
  4.     void *svcmgr = BINDER_SERVICE_MANAGER;  
  5.     bs = binder_open(128*1024);  
  6.     if (binder_become_context_manager(bs)) {  
  7.         LOGE("cannot become context manager (%s)\n", strerror(errno));  
  8.         return -1;  
  9.     }  
  10.     svcmgr_handle = svcmgr;  
  11.     binder_loop(bs, svcmgr_handler);  
  12.     return 0;  
  13. }  

從main函式中可以看出,它主要做了三件事情:

開啟/dev/binder裝置,並在記憶體中對映128K的空間。通知Binder裝置,把自己變成context_manager進入迴圈,不停的去讀Binder裝置,看是否有對service的請求,如果有的話,就去呼叫svcmgr_handler函式回撥處理請求。

服務註冊

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

[java] view plaincopy
  1. int svcmgr_handler(struct binder_state *bs,  
  2.                    struct binder_txn *txn,  
  3.                    struct binder_io *msg,  
  4.                    struct binder_io *reply)  
  5. {  
  6.     struct svcinfo *si;  
  7.     uint16_t *s;  
  8.     unsigned len;  
  9.     void *ptr;  
  10.     uint32_t strict_policy;  
  11. //  LOGI("target=%p code=%d pid=%d uid=%d\n",  
  12. //  txn->target, txn->code, txn->sender_pid, txn->sender_euid);  
  13.     if (txn->target != svcmgr_handle)  
  14.         return -1;  
  15.     // Equivalent to Parcel::enforceInterface(), reading the RPC  
  16.     // header with the strict mode policy mask and the interface name.  
  17.     // Note that we ignore the strict_policy and don't propagate it  
  18.     // further (since we do no outbound RPCs anyway).  
  19.     strict_policy = bio_get_uint32(msg);  
  20.     s = bio_get_string16(msg, &len);  
  21.     if ((len != (sizeof(svcmgr_id) / 2)) ||  
  22.         memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {  
  23.         fprintf(stderr,"invalid id %s\n", str8(s));  
  24.         return -1;  
  25.     }  
  26.     switch(txn->code) {  
  27.     case SVC_MGR_GET_SERVICE:  
  28.     case SVC_MGR_CHECK_SERVICE:  
  29.         s = bio_get_string16(msg, &len);  
  30.         ptr = do_find_service(bs, s, len);  
  31.         if (!ptr)  
  32.             break;  
  33.         bio_put_ref(reply, ptr);  
  34.         return 0;  
  35.     case SVC_MGR_ADD_SERVICE:  
  36.         s = bio_get_string16(msg, &len);  
  37.         ptr = bio_get_ref(msg);  
  38.         if (do_add_service(bs, s, len, ptr, txn->sender_euid))  
  39.             return -1;  
  40.         break;  
  41.     case SVC_MGR_LIST_SERVICES: {  
  42.         unsigned n = bio_get_uint32(msg);  
  43.         si = svclist;  
  44.         while ((n-- > 0) && si)  
  45.             si = si->next;  
  46.         if (si) {  
  47.             bio_put_string16(reply, si->name);  
  48.             return 0;  
  49.         }  
  50.         return -1;  
  51.     }  
  52.     default:  
  53.         LOGE("unknown code %d\n", txn->code);  
  54.         return -1;  
  55.     }  
  56.     bio_put_uint32(reply, 0);  
  57.     return 0;  
  58. }  

在該回撥函式中會判斷Service有什麼需要,如果是請求註冊service,那麼久執行:

[java] view plaincopy
  1. case SVC_MGR_ADD_SERVICE:  
  2.         s = bio_get_string16(msg, &len);  
  3.         ptr = bio_get_ref(msg);  
  4.         if (do_add_service(bs, s, len, ptr, txn->sender_euid))  
  5.             return -1;  
  6.         break;  

我們再來看看do_add_service中做了什麼事情:

[java] view plaincopy
  1. int do_add_service(struct binder_state *bs,  
  2.                    uint16_t *s, unsigned len,  
  3.                    void *ptr, unsigned uid)  
  4. {  
  5.     struct svcinfo *si;  
  6. //    LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);  
  7.     if (!ptr || (len == 0) || (len > 127))  
  8.         return -1;  
  9.     if (!svc_can_register(uid, s)) {  
  10.         LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",  
  11.              str8(s), ptr, uid);  
  12.         return -1;  
  13.     }  
  14.     si = find_svc(s, len);  
  15.     if (si) {  
  16.         if (si->ptr) {  
  17.             LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",  
  18.                  str8(s), ptr, uid);  
  19.             return -1;  
  20.         }  
  21.         si->ptr = ptr;  
  22.     } else {  
  23.         si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));  
  24.         if (!si) {  
  25.             LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",  
  26.                  str8(s), ptr, uid);  
  27.             return -1;  
  28.         }  
  29.         si->ptr = ptr;  
  30.         si->len = len;  
  31.         memcpy(si->name, s, (len + 1) * sizeof(uint16_t));  
  32.         si->name[len] = '\0';  
  33.         si->death.func = svcinfo_death;  
  34.         si->death.ptr = si;  
  35.         si->next = svclist;  
  36.         svclist = si;  
  37.     }  
  38.     binder_acquire(bs, ptr);  
  39.     binder_link_to_death(bs, ptr, &si->death);  
  40.     return 0;  
  41. }  

在該函式中,首先會去檢查是否有許可權註冊service,如果沒有許可權就直接返回,不能註冊。

[java] view plaincopy
  1. if (!svc_can_register(uid, s)) {  
  2.         LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",  
  3.              str8(s), ptr, uid);  
  4.         return -1;  
  5.     }  

然後會去檢查該service是否已經註冊過了,如果已經註冊過,那麼就不能再註冊了:

[java] view plaincopy
  1. si = find_svc(s, len);  
  2. if (si) {  
  3.       if (si->ptr) {  
  4.           LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",  
  5.                str8(s), ptr, uid);  
  6.           return -1;  
  7.       }  
  8.       si->ptr = ptr;  
  9.   }  

再判斷記憶體是否足夠:

[java] view plaincopy
  1. si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));  
  2.         if (!si) {  
  3.             LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",  
  4.                  str8(s), ptr, uid);  
  5.             return -1;  
  6.         }  

如果都沒什麼問題,會註冊該service,加入到svcList中來。注意,在ServiceManager中維護service資訊的地方就是svclist。裡面存了service的name和handler。

服務獲取

通過以上幾個步驟,service就算註冊成功了。那麼當要獲得該service的時候又是怎麼去處理的。還是來看下回撥函式中的判斷:

[java] view plaincopy
  1. case SVC_MGR_CHECK_SERVICE:  
  2.         s = bio_get_string16(msg, &len);  
  3.         ptr = do_find_service(bs, s, len);  
  4.         if (!ptr)  
  5.             break;  
  6.         bio_put_ref(reply, ptr);  
  7.         return 0;  

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

do_find_service函式中主要執行service的查詢。

[java] view plaincopy
  1. void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)  
  2. {  
  3.     struct svcinfo *si;  
  4.     si = find_svc(s, len);  
  5. //    LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);  
  6.     if (si && si->ptr) {  
  7.         return si->ptr;  
  8.     } else {  
  9.         return 0;  
  10.     }  
  11. }  

這樣在ServiceManager中就完成了服務的註冊和查詢。來看下ServiceManager的功能圖:

相關文章