Android-ServiceManager

??ServiceManager在init進(jìn)程啟動(dòng)之后啟動(dòng),用來管理系統(tǒng)中的service,那么首先理解一下在init進(jìn)程啟動(dòng)之后啟動(dòng)這句話類:
一般開機(jī)過程分為三個(gè)階段:
1. OS級別,由bootloader載入linux內(nèi)核后,內(nèi)核開始初始化,并載入built-in的驅(qū)動(dòng)程序,內(nèi)核完成開機(jī)后,載入init process,切換至user-space后,結(jié)束內(nèi)核的循序過程,進(jìn)入排成模式。
2. Android-level,由init process開始,讀取init.rc,Mative服務(wù)啟動(dòng),并啟動(dòng)重要的外部程序,例如servicemanager、zygote以及system service。
3. Zygote-Mode,Zygote啟動(dòng)完System Service后,進(jìn)入Zygote Mode,在Socket等候命令,隨后,使用者將看到一個(gè)桌面環(huán)境,桌面環(huán)境由一個(gè)名為Launcher的應(yīng)用程序負(fù)責(zé)提供。


image.png

??在ServiceManager中有兩個(gè)比較重要的方法:add_service和check_service,系統(tǒng)的service需要通過add_service把自己的信息注冊到servicemanager中,當(dāng)需要使用時(shí),通過check_service檢查該service是否存在。看它的main函數(shù)的源碼:
image.png

三件事:
1. 打開Binder設(shè)備,并在內(nèi)存中映射128k的空間
首先看一下struct binder_state這個(gè)結(jié)構(gòu)體
struct binder_state{
    int fd;            //文件描述符,打開/dev/binder設(shè)備
    void* mapped;    //把設(shè)備文件/dev/binder映射到進(jìn)程空間的起始地址
    unsigned mapsize;  //映射內(nèi)存空間的大小
} 

2. 告訴Binder驅(qū)動(dòng)程序,自己是Binder上下文管理者
3.進(jìn)入循環(huán),不停去讀Binder設(shè)備,看是否有對service的請求,如果有的話就去調(diào)用svcmgr_handller函數(shù)回調(diào)處理請求。
??下面就來看一下servicemanager是怎么循環(huán)等待客戶端的請求,并進(jìn)行注冊服務(wù)、服務(wù)獲取這一系列活動(dòng)的。

等待客戶端請求

??ServiceManager進(jìn)程通過binder_loop方法進(jìn)入循環(huán)等待客戶端的請求中,當(dāng)有客戶端請求時(shí),進(jìn)程ServiceManager被喚醒并調(diào)用svcmgr_handler來處理客戶端的請求。
image.png

1. ServiceManager進(jìn)程在進(jìn)入循環(huán)前,調(diào)用binder_write()方法,通過ioctl系統(tǒng)調(diào)用設(shè)置Binder線程的運(yùn)行狀態(tài)為BINDER_LOOPER_STATE_ENTERED,看下binder_write()方法的源碼:
image.png
??首先設(shè)置binder_write_read結(jié)構(gòu)體變量的值,然后通過ioctl傳遞到Binder驅(qū)動(dòng)程序中,此時(shí)控制命令為BINDER_WRITE_READ,binder_ioctl函數(shù)中對BINDER_WRITE_READ命令的處理過程為:
image.png
??在binder_thread_write方法中,對BC_ENTER_LOOPER Binder協(xié)議的處理如下:
image.png

??此處僅僅設(shè)置了binder_thread結(jié)構(gòu)體變量中的線程運(yùn)行狀態(tài)looper為BINDER_LOOPER_STATE_ENTERED,表示當(dāng)前的binder線程進(jìn)入循環(huán)狀態(tài)。
2. 睡眠等待客戶端請求
在沒有客戶端請求時(shí),當(dāng)前進(jìn)程就進(jìn)入休眠狀態(tài),等待請求到來再喚醒。
總結(jié)一哈?
??ServiceManager進(jìn)程的啟動(dòng)首先打開binder驅(qū)動(dòng)并開辟內(nèi)核緩存區(qū),同時(shí)將緩存區(qū)的物理頁面同時(shí)映射到內(nèi)核虛擬地址空間及進(jìn)程虛擬地址空間中,然后在內(nèi)核中創(chuàng)建屬于servicemanager進(jìn)程的binder_node實(shí)體節(jié)點(diǎn),接著設(shè)置處理客戶端請求的binder線程運(yùn)行狀態(tài),由于此時(shí)沒有客戶端的請求,servicemanager進(jìn)程進(jìn)入睡眠等待中,直到客戶端請求的到來時(shí),喚醒servicemanager進(jìn)程,再繼續(xù)往下執(zhí)行。

服務(wù)注冊

直接來看,當(dāng)有service請求時(shí),調(diào)用的回到函數(shù)svcmgr_handler函數(shù)。
image.png
image.png

??如果請求注冊,就執(zhí)行紅色框中的代碼,我們再來看一下具體實(shí)現(xiàn)do_add_service()方法是怎么實(shí)現(xiàn)的:
image.png
image.png
??看代碼中的三個(gè)紅框,首先會(huì)檢查是否有權(quán)限注冊service,如果沒有權(quán)限就直接返回不能注冊;然后去檢查該service是否已經(jīng)注冊過了,如果已經(jīng)注冊過,那就不能再注冊;再判斷內(nèi)存是否夠用。如果都沒有問題,就會(huì)注冊該service,加入到svcList中來,(在servicemanager中維護(hù)service信息的地方就是svcList,里面存了service的name和handler)。通過以上幾步,service就算注冊成功了。

服務(wù)獲取

??如果是服務(wù)獲取,就會(huì)執(zhí)行代碼中的黃色框,并將返回的數(shù)據(jù)寫入reply,返回給客戶端,do_find_service函數(shù)中主要執(zhí)行service的查找,看源碼:

image.png


紀(jì)念我的第一篇MarkDown文章

??寫了這么久的博客,一開始的時(shí)候就對文字輸入表示懷疑,為啥人家輸入代碼的時(shí)候輸入的這么溜,還能復(fù)制,而我只能截圖發(fā)上去,偶然讓我發(fā)現(xiàn)了MarkDown編譯器,感覺當(dāng)時(shí)的自己。。。。好白癡啊。。。。。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容