Android 8.0 啟動ServiceManager
一、簡述
framework/native/cmds/servicemanager/
- service_manager.c
- binder.c
kernel/drivers/ (不同Linux分支路徑略有不同)
- staging/android/binder.c
- android/binder.c
ServiceManager是Binder IPC通訊過程中的守護程序,本身也是一個Binder服務,但並沒有採用libbinder中的多執行緒模型來與Binder驅動通訊,而是自行編寫了binder.c直接和Binder驅動來通訊,並且只有一個迴圈binder_loop來進行讀取和處理事務,這樣的好處是簡單而高效。
ServiceManager本身工作相對簡單,其功能:查詢和註冊服務。 對於Binder IPC通訊過程中,其實更多的情形是BpBinder和BBinder之間的通訊,比如ActivityManagerProxy和ActivityManagerService之間的通訊等。
流程
啟動過程
ServiceManager是由init程序通過解析init.rc檔案而建立的,其所對應的可執行程式/system/bin/servicemanager,所對應的原始檔是service_manager.c,程序名為/system/bin/servicemanager。
service servicemanager /system /bin/servicemanager
class core
user system
group system
critical
onrestart restart healthd
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
啟動Service Manager的入口函式是service_manager.c中的main()方法,程式碼如下:
main
[ -> service_manager.c]
int main(int argc, char **argv)
{
struct binder_state *bs;
//開啟binder驅動,申請128k位元組大小的記憶體空間
bs = binder_open(128*1024);
...
//成為上下文管理者 【見小節2.3】
if (binder_become_context_manager(bs)) {
return -1;
}
selinux_enabled = is_selinux_enabled(); //selinux許可權是否使能
sehandle = selinux_android_service_context_handle();
selinux_status_open(true);
if (selinux_enabled > 0) {
if (sehandle == NULL) {
abort(); //無法獲取sehandle
}
if (getcon(&service_manager_context) != 0) {
abort(); //無法獲取service_manager上下文
}
}
...
//進入無限迴圈,處理client端發來的請求
binder_loop(bs, svcmgr_handler);
return 0;
}
二、核心工作
servicemanager的核心工作就是註冊服務和查詢服務
2.1 do_find_service
[-> service_manager.c]
uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
//查詢相應的服務
struct svcinfo *si = find_svc(s, len);
if (!si || !si->handle) {
return 0;
}
if (!si->allow_isolated) {
uid_t appid = uid % AID_USER;
//檢查該服務是否允許孤立於程序而單獨存在
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
return 0;
}
}
//服務是否滿足查詢條件
if (!svc_can_find(s, len, spid)) {
return 0;
}
return si->handle;
}
查詢到目標服務,並返回該服務所對應的handle
2.1.1 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服務列表中,根據服務名遍歷查詢是否已經註冊。當服務已存在svclist
,則返回相應的服務名,否則返回NULL。
當找到服務的handle, 則呼叫bio_put_ref(reply, handle),將handle封裝到reply.
2.2 do_add_service
[-> service_manager.c]
int do_add_service(struct binder_state *bs,
const uint16_t *s, size_t len,
uint32_t handle, uid_t uid, int allow_isolated,
pid_t spid)
{
struct svcinfo *si;
if (!handle || (len == 0) || (len > 127))
return -1;
//許可權檢查,>=AID_APP
if (!svc_can_register(s, len, spid)) {
return -1;
}
//服務檢索
si = find_svc(s, len);
if (si) {
if (si->handle) {
svcinfo_death(bs, si); //服務已註冊時,釋放相應的服務
}
si->handle = handle;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) { //記憶體不足,無法分配足夠記憶體
return -1;
}
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); //記憶體拷貝服務資訊
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist; // svclist儲存所有已註冊的服務
svclist = si;
}
//以BC_ACQUIRE命令,handle為目標的資訊,通過ioctl傳送給binder驅動
binder_acquire(bs, handle);
//以BC_REQUEST_DEATH_NOTIFICATION命令的資訊,通過ioctl傳送給binder驅動,主要用於清理記憶體等收尾工作
binder_link_to_death(bs, handle, &si->death);
return 0;
}
static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
const char *perm = "add";
if (multiuser_get_app_id(uid) >= AID_APP) {
return 0; /* Don't allow apps to register services */
}
return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
}
註冊服務的分以下3部分工作:
- svc_can_register:檢查許可權,檢查selinux許可權是否滿足;
- find_svc:服務檢索,根據服務名來查詢匹配的服務;
- svcinfo_death:釋放服務,當查詢到已存在同名的服務,則先清理該服務資訊,再將當前的服務加入到服務列表svclist;
三. 總結
ServiceManger集中管理系統內的所有服務,通過許可權控制程序是否有權註冊服務,通過字串名稱來查詢對應的Service;由於ServiceManger程序建立跟所有向其註冊服務的死亡通知, 那麼當服務所在程序死亡後, 會只需告知ServiceManager.每個Client通過查詢ServiceManager可獲取Server程序的情況,降低所有Client程序直接檢測會導致負載過重。
ServiceManager啟動流程:
- 開啟binder驅動,並呼叫mmap()方法分配128k的記憶體對映空間:binder_open();
- 通知binder驅動使其成為守護程序:binder_become_context_manager();
- 驗證selinux許可權,判斷程序是否有權註冊或檢視指定服務;
- 進入迴圈狀態,等待Client端的請求:binder_loop()。
- 註冊服務的過程,根據服務名稱,但同一個服務已註冊,重新註冊前會先移除之前的註冊資訊;
- 死亡通知: 當binder所在程序死亡後,會呼叫binder_release方法,然後呼叫binder_node_release.這個過程便會發出死亡通知的回撥.
ServiceManager最核心的兩個功能為查詢和註冊服務:
- 註冊服務:記錄服務名和handle資訊,儲存到svclist列表;
- 查詢服務:根據服務名查詢相應的的handle資訊。
四. 原始碼目錄
從上之下, 整個Binder架構所涉及的總共有以下5個目錄:
/framework/base/core/java/ (Java)
/framework/base/core/jni/ (JNI)
/framework/native/libs/binder (Native)
/framework/native/cmds/servicemanager/ (Native)
/kernel/drivers/staging/android (Driver)
4.1 Java framework
/framework/base/core/java/android/os/
- IInterface.java
- IBinder.java
- Parcel.java
- IServiceManager.java
- ServiceManager.java
- ServiceManagerNative.java
- Binder.java
/framework/base/core/jni/
- android_os_Parcel.cpp
- AndroidRuntime.cpp
- android_util_Binder.cpp (核心類)
4.2 Native framework
/framework/native/libs/binder
- IServiceManager.cpp
- BpBinder.cpp
- Binder.cpp
- IPCThreadState.cpp (核心類)
- ProcessState.cpp (核心類)
/framework/native/include/binder/
- IServiceManager.h
- IInterface.h
/framework/native/cmds/servicemanager/
- service_manager.c
- binder.c
4.3 Kernel
/kernel/drivers/staging/android/
- binder.c
- uapi/binder.h
參考網址:
http://gityuan.com/2015/11/07/binder-start-sm/