<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
上一篇文章:
在前文提到,init程序會在在Trigger 為init的Action中,啟動servicemanager服務,這篇文章我們就來具體分析一下servicemanager服務,它到底做了哪些事情。
servicemanager服務的原始碼位於/frameworks/native/cmds/servicemanager/service_manager.c
,我們將從這個類的入口開始看起。
int main(int argc, char** argv) { struct binder_state *bs; union selinux_callback cb; char *driver; if (argc > 1) { driver = argv[1]; } else { //啟動時預設無引數,走這個分支 driver = "/dev/binder"; } //開啟binder驅動,並設定mmap的記憶體大小為128k bs = binder_open(driver, 128*1024); ... if (binder_become_context_manager(bs)) { ALOGE("cannot become context manager (%s)n", strerror(errno)); return -1; } cb.func_audit = audit_callback; selinux_set_callback(SELINUX_CB_AUDIT, cb); #ifdef VENDORSERVICEMANAGER cb.func_log = selinux_vendor_log_callback; #else cb.func_log = selinux_log_callback; #endif selinux_set_callback(SELINUX_CB_LOG, cb); #ifdef VENDORSERVICEMANAGER sehandle = selinux_android_vendor_service_context_handle(); #else sehandle = selinux_android_service_context_handle(); #endif selinux_status_open(true); if (sehandle == NULL) { ALOGE("SELinux: Failed to acquire sehandle. Aborting.n"); abort(); } if (getcon(&service_manager_context) != 0) { ALOGE("SELinux: Failed to acquire service_manager context. Aborting.n"); abort(); } /* binder_loop已封裝如下步驟: while (1) { /* read data */ /* parse data, and process */ /* reply */ } */ binder_loop(bs, svcmgr_handler); return 0; }
從main函數中可以看出,它主要做了三件事情:
我們再來看看svcmgr_handler函數的實現:
int svcmgr_handler(struct binder_state *bs, struct binder_transaction_data_secctx *txn_secctx, struct binder_io *msg, struct binder_io *reply) { struct svcinfo *si; uint16_t *s; size_t len; uint32_t handle; uint32_t strict_policy; int allow_isolated; uint32_t dumpsys_priority; struct binder_transaction_data *txn = &txn_secctx->transaction_data; if (txn->target.ptr != BINDER_SERVICE_MANAGER) return -1; if (txn->code == PING_TRANSACTION) return 0; ... switch(txn->code) { case SVC_MGR_GET_SERVICE: case SVC_MGR_CHECK_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid, (const char*) txn_secctx->secctx); if (!handle) break; bio_put_ref(reply, handle); return 0; case SVC_MGR_ADD_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 : 0; dumpsys_priority = bio_get_uint32(msg); if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid, (const char*) txn_secctx->secctx)) return -1; break; case SVC_MGR_LIST_SERVICES: { uint32_t n = bio_get_uint32(msg); uint32_t req_dumpsys_priority = bio_get_uint32(msg); if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) { ALOGE("list_service() uid=%d - PERMISSION DENIEDn", txn->sender_euid); return -1; } si = svclist; // walk through the list of services n times skipping services that // do not support the requested priority while (si) { if (si->dumpsys_priority & req_dumpsys_priority) { if (n == 0) break; n--; } si = si->next; } if (si) { bio_put_string16(reply, si->name); return 0; } return -1; } default: ALOGE("unknown code %dn", txn->code); return -1; } bio_put_uint32(reply, 0); return 0; }
我們先來認識一下binder的資料傳輸載體binder_transaction_data
:
struct binder_transaction_data { union { /* 當binder_transaction_data是由使用者空間的程序傳送給Binder驅動時, handle是該事務的傳送目標在Binder驅動中的資訊,即該事務會交給handle來處理; handle的值是目標在Binder驅動中的Binder參照。*/ __u32 handle; /* 當binder_transaction_data是有Binder驅動反饋給使用者空間程序時, ptr是該事務的傳送目標在使用者空間中的資訊,即該事務會交給ptr對應的服務來處理; ptr是處理該事務的服務的服務在使用者空間的本地Binder物件。*/ binder_uintptr_t ptr; } target; // 該事務的目標物件(即,該事務封包是給該target來處理的) // 只有當事務是由Binder驅動傳遞給使用者空間時,cookie才有意思,它的值是處理該事務的ServerC++層的本地Binder物件 binder_uintptr_t cookie; // 事務編碼。如果是請求,則以BC_開頭;如果是回覆,則以BR_開頭。 __u32 code; /* General information about the transaction. */ __u32 flags; //表示事務發起者的pid和uid。 pid_t sender_pid; uid_t sender_euid; // 資料大小 binder_size_t data_size; //資料偏移量 binder_size_t offsets_size; //data是一個共用體,當通訊資料很小的時,可以直接使用buf[8]來儲存資料。當夠大時,只能用指標buffer來描述一個申請的資料緩衝區。 union { struct { /* transaction data */ binder_uintptr_t buffer; binder_uintptr_t offsets; } ptr; __u8 buf[8]; } data; };
可以看到,svcmgr_handler函數中對binder data的事務編碼進行了判斷,並分別對SVC_MGR_GET_SERVICE(SVC_MGR_CHECK_SERVICE)
、SVC_MGR_ADD_SERVICE
、SVC_MGR_LIST_SERVICES
三種型別的事務編碼做了業務處理。
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,返回給使用者端。
uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid) { struct svcinfo *si = find_svc(s, len); ... return si->handle; }
我們繼續看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 是一個單向連結串列,儲存了所有向servicemanager註冊的服務資訊。find_svc遍歷svclist連結串列,通過服務名稱作為索引條件,最終找到符合條件的服務。
case SVC_MGR_ADD_SERVICE: s = bio_get_string16(msg, &len); if (s == NULL) { return -1; } handle = bio_get_ref(msg); allow_isolated = bio_get_uint32(msg) ? 1 : 0; dumpsys_priority = bio_get_uint32(msg); if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority, txn->sender_pid, (const char*) txn_secctx->secctx)) return -1;
我們繼續看do_add_service函數中做了哪些事情。
在該函數中,首先會去檢查使用者端是否有許可權註冊service,如果沒有許可權就直接返回,不能註冊。
if (!svc_can_register(s, len, spid, sid, uid)) { ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIEDn", str8(s, len), handle, uid); return -1; }
然後會去檢查該service是否已經註冊過了,如果已經註冊過,那麼就不能再註冊了。
si = find_svc(s, len); if (si) { if (si->handle) { ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDEn", str8(s, len), handle, uid); svcinfo_death(bs, si); } si->handle = handle; }
再判斷記憶體是否足夠。
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t)); if (!si) { ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORYn", str8(s, len), handle, uid); return -1; }
如果都沒什麼問題,會註冊該service,並加入到svcList連結串列中。
綜上所述,servicemanager主要負責查詢和註冊其他的系統服務,是系統服務的管理者。
文章的最後,留給大家一個問題進行思考:
為什麼Android需要設計servicemanager做中轉來新增和獲取系統服務,而不直接讓使用者端去獲取伺服器端控制程式碼?
更多關於Android 10 啟動之servicemanager的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45