Android 10 啟動(dòng)之servicemanager源碼解析
正文
上一篇文章:
Android 10 啟動(dòng)分析之Init篇 (一)
在前文提到,init進(jìn)程會(huì)在在Trigger 為init的Action中,啟動(dòng)servicemanager服務(wù),這篇文章我們就來具體分析一下servicemanager服務(wù),它到底做了哪些事情。
servicemanager服務(wù)的源碼位于/frameworks/native/cmds/servicemanager/service_manager.c,我們將從這個(gè)類的入口開始看起。
int main(int argc, char** argv)
{
struct binder_state *bs;
union selinux_callback cb;
char *driver;
if (argc > 1) {
driver = argv[1];
} else {
//啟動(dòng)時(shí)默認(rèn)無參數(shù),走這個(gè)分支
driver = "/dev/binder";
}
//打開binder驅(qū)動(dòng),并設(shè)置mmap的內(nèi)存大小為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函數(shù)中可以看出,它主要做了三件事情:
- 打開/dev/binder設(shè)備,并在內(nèi)存中映射128K的空間。
- 通知Binder設(shè)備,把自己變成context_manager,其他用戶進(jìn)程都通過0號(hào)句柄訪問ServiceManager。
- 進(jìn)入循環(huán),不停的去讀Binder設(shè)備,看是否有對(duì)service的請(qǐng)求,如果有的話,就去調(diào)用svcmgr_handler函數(shù)回調(diào)處理請(qǐng)求。
我們?cè)賮砜纯磗vcmgr_handler函數(shù)的實(shí)現(xiàn):
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 DENIED\n",
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 %d\n", txn->code);
return -1;
}
bio_put_uint32(reply, 0);
return 0;
}
我們先來認(rèn)識(shí)一下binder的數(shù)據(jù)傳輸載體binder_transaction_data:
struct binder_transaction_data {
union {
/* 當(dāng)binder_transaction_data是由用戶空間的進(jìn)程發(fā)送給Binder驅(qū)動(dòng)時(shí),
handle是該事務(wù)的發(fā)送目標(biāo)在Binder驅(qū)動(dòng)中的信息,即該事務(wù)會(huì)交給handle來處理;
handle的值是目標(biāo)在Binder驅(qū)動(dòng)中的Binder引用。*/
__u32 handle;
/* 當(dāng)binder_transaction_data是有Binder驅(qū)動(dòng)反饋給用戶空間進(jìn)程時(shí),
ptr是該事務(wù)的發(fā)送目標(biāo)在用戶空間中的信息,即該事務(wù)會(huì)交給ptr對(duì)應(yīng)的服務(wù)來處理;
ptr是處理該事務(wù)的服務(wù)的服務(wù)在用戶空間的本地Binder對(duì)象。*/
binder_uintptr_t ptr;
} target; // 該事務(wù)的目標(biāo)對(duì)象(即,該事務(wù)數(shù)據(jù)包是給該target來處理的)
// 只有當(dāng)事務(wù)是由Binder驅(qū)動(dòng)傳遞給用戶空間時(shí),cookie才有意思,它的值是處理該事務(wù)的ServerC++層的本地Binder對(duì)象
binder_uintptr_t cookie;
// 事務(wù)編碼。如果是請(qǐng)求,則以BC_開頭;如果是回復(fù),則以BR_開頭。
__u32 code;
/* General information about the transaction. */
__u32 flags;
//表示事務(wù)發(fā)起者的pid和uid。
pid_t sender_pid;
uid_t sender_euid;
// 數(shù)據(jù)大小
binder_size_t data_size;
//數(shù)據(jù)偏移量
binder_size_t offsets_size;
//data是一個(gè)共用體,當(dāng)通訊數(shù)據(jù)很小的時(shí),可以直接使用buf[8]來保存數(shù)據(jù)。當(dāng)夠大時(shí),只能用指針buffer來描述一個(gè)申請(qǐng)的數(shù)據(jù)緩沖區(qū)。
union {
struct {
/* transaction data */
binder_uintptr_t buffer;
binder_uintptr_t offsets;
} ptr;
__u8 buf[8];
} data;
};
可以看到,svcmgr_handler函數(shù)中對(duì)binder data的事務(wù)編碼進(jìn)行了判斷,并分別對(duì)SVC_MGR_GET_SERVICE(SVC_MGR_CHECK_SERVICE)、SVC_MGR_ADD_SERVICE、SVC_MGR_LIST_SERVICES三種類型的事務(wù)編碼做了業(yè)務(wù)處理。
獲取服務(wù)
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函數(shù)中主要執(zhí)行service的查找,并把找到的服務(wù)句柄寫入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;
}
我們繼續(xù)看find_svc函數(shù):
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 是一個(gè)單向鏈表,儲(chǔ)存了所有向servicemanager注冊(cè)的服務(wù)信息。find_svc遍歷svclist鏈表,通過服務(wù)名稱作為索引條件,最終找到符合條件的服務(wù)。
注冊(cè)服務(wù)
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;
我們繼續(xù)看do_add_service函數(shù)中做了哪些事情。
在該函數(shù)中,首先會(huì)去檢查客戶端是否有權(quán)限注冊(cè)service,如果沒有權(quán)限就直接返回,不能注冊(cè)。
if (!svc_can_register(s, len, spid, sid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
}
然后會(huì)去檢查該service是否已經(jīng)注冊(cè)過了,如果已經(jīng)注冊(cè)過,那么就不能再注冊(cè)了。
si = find_svc(s, len);
if (si) {
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
}
再判斷內(nèi)存是否足夠。
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
str8(s, len), handle, uid);
return -1;
}
如果都沒什么問題,會(huì)注冊(cè)該service,并加入到svcList鏈表中。
綜上所述,servicemanager主要負(fù)責(zé)查詢和注冊(cè)其他的系統(tǒng)服務(wù),是系統(tǒng)服務(wù)的管理者。
文章的最后,留給大家一個(gè)問題進(jìn)行思考:
為什么Android需要設(shè)計(jì)servicemanager做中轉(zhuǎn)來添加和獲取系統(tǒng)服務(wù),而不直接讓客戶端去獲取服務(wù)端句柄?
更多關(guān)于Android 10 啟動(dòng)之servicemanager的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Android?Service啟動(dòng)綁定流程詳解
- Android布局控件View?ViewRootImpl?WindowManagerService關(guān)系
- android?微信搶紅包工具AccessibilityService實(shí)現(xiàn)詳解
- Android?O對(duì)后臺(tái)Service限制詳解
- Android?NotificationListenerService通知監(jiān)聽服務(wù)使用
- Android?NotificationListenerService?通知服務(wù)原理解析
- Android開發(fā)InputManagerService創(chuàng)建與啟動(dòng)流程
- Android 開機(jī)自啟動(dòng)Service實(shí)現(xiàn)詳解
相關(guān)文章
詳解基于Android的Appium+Python自動(dòng)化腳本編寫
這篇文章主要介紹了詳解基于Android的Appium+Python自動(dòng)化腳本編寫,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08
Android通過ksoap2傳遞復(fù)雜數(shù)據(jù)類型及CXF發(fā)布的webservice詳細(xì)介紹
這篇文章主要介紹了 Android通過ksoap2傳遞復(fù)雜數(shù)據(jù)類型詳細(xì)介紹的相關(guān)資料,需要的朋友可以參考下2017-02-02
Kotlin封裝RecyclerView Adapter實(shí)例教程
這篇文章主要給大家介紹了關(guān)于Kotlin封裝RecyclerView Adapter的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2018-08-08
Android Lock鎖實(shí)現(xiàn)原理詳細(xì)分析
這篇文章主要介紹了Android Lock鎖實(shí)現(xiàn)原理,Lock接口的實(shí)現(xiàn)類提供了比使用synchronized關(guān)鍵字更加靈活和廣泛的鎖定對(duì)象操作,而且是以面向?qū)ο蟮姆绞竭M(jìn)行對(duì)象加鎖2023-02-02
詳解Android使用Gradle統(tǒng)一配置依賴管理
本篇文章主要介紹了詳解Android 使用 Gradle 統(tǒng)一配置依賴管理,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-01-01
Android互聯(lián)網(wǎng)訪問圖片并在客戶端顯示的方法
這篇文章主要介紹了Android互聯(lián)網(wǎng)訪問圖片并在客戶端顯示的方法,結(jié)合實(shí)例分析了Android處理圖片的技巧,并附帶了Android的URL封裝類,網(wǎng)絡(luò)連接封裝類與輸出流封裝類,需要的朋友可以參考下2015-12-12

