Binder原始碼分析之ServiceManager(原)
阿新 • • 發佈:2019-02-16
ServiceManager作為Native層Service的管理員,有著極其重要的作用,主要表現兩個方面:
1、對於服務端來說,系統所有的服務提供者都需要向ServiceManager註冊。
2、對於客戶端來說,所有客戶端如果想要獲得某個系統服務的代理,必須向ServiceManager申請相應的服務端代理。
1、開啟Binder裝置檔案;
2、告訴Binder驅動程式自己是Binder上下文管理者;
3、進入一個死迴圈,充當Service的角色,等待Client的請求。
從上面可以看出,開啟Binder的過程的過程分為兩步:
1、開啟Binder裝置;
同時我們注意到,ServiceManager本身也是一個Service,他需要先向Binder註冊自己,而且要把自己註冊為“管理員”,那麼這個註冊過程是怎樣的呢?我們來看原始碼:
這一步的入口是binder_loop():
1、先通過傳送BC_ENTER_LOOPER訊息告訴底層,ServiceManager將要進入迴圈了;
2、在死迴圈中讀取客戶端的請求;
3、處理請求;
上面的第一步是通過向Binder傳送BC_ENTER_LOOPER訊息實現的,第二步通過BINDER_WRITE_READ可以讀取Binder中的資料(請求);第三步需要呼叫binder_parse去處理客戶端的請求,我們主要看一下這個過程。
1、得到一個Service;
2、新增一個Service;
3、列出所有的Service;
下面我們分別看一下這三個功能的實現方式,我們先從add一個Service開始:
那麼我們可以推測,find的過程無非就是去svclist中查詢svcinfo的過程:
那麼list Service的請求只需要把svclist返回給Client即可:
1、對於服務端來說,系統所有的服務提供者都需要向ServiceManager註冊。
2、對於客戶端來說,所有客戶端如果想要獲得某個系統服務的代理,必須向ServiceManager申請相應的服務端代理。
下面從原始碼分析ServiceManager的啟動流程和服務流程。
main函式主要有三個功能:@Service_manager.c(frameworks/base/cmds/servicemanager) int main(int argc, char **argv) { struct binder_state *bs; void *svcmgr = BINDER_SERVICE_MANAGER; //開啟binder裝置 bs = binder_open
(128*1024); //成為Service manager if (binder_become_context_manager(bs)) { LOGE("cannot become context manager (%s)\n", strerror(errno)); return -1; } svcmgr_handle = svcmgr; //在binder_loop中迴圈檢測binder中是否有新的請求 binder_loop(bs, svcmgr_handler); return 0; }
1、開啟Binder裝置檔案;
2、告訴Binder驅動程式自己是Binder上下文管理者;
3、進入一個死迴圈,充當Service的角色,等待Client的請求。
下面我們就分別介紹這三個步驟。
一、開啟Binder裝置
上面開啟Binder裝置的過程其實就是構建一個binder_state結構體物件,然後對其各個成員初始化的過程。我們來看一下binder_state資料結構:@binder.c(\frameworks\base\cmds\servicemanager\) struct binder_state *binder_open(unsigned mapsize) { //建立binder_state結構體並分配記憶體 struct binder_state *bs; bs = malloc(sizeof(*bs)); //開啟binder裝置 bs->fd = open("/dev/binder", O_RDWR); bs->mapsize = mapsize; //將binder物理空間對映為ServiceManager可用的虛擬空間 bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0); //將結構體返回給servicemanager return bs; }
struct binder_state {
//檔案描述符,這裡指的是/dev/binder裝置檔案描述符
int fd;
//把裝置檔案/dev/binder對映到程序空間的起始地址,這裡就是128*1024
void *mapped;
//對映的空間大小
unsigned mapsize;
};
這個結構體只有三個成員變數,其中fd是底層binder裝置的檔案描述符,mapped是ServiceManager得到的虛擬空間地址,這塊虛擬空間映射了底層binder的實體地址,而mapsize是這塊虛擬空間的大小,也就是128*1024。從上面可以看出,開啟Binder的過程的過程分為兩步:
1、開啟Binder裝置;
2、用Binder的實體地址對映為ServiceManager可用的虛擬地址;
二、ServiceManager成為服務管理員的過程
在Android中,每個註冊的Service,Binder都會給他分配一個唯一的int型的控制代碼,Client可以用該控制代碼向ServiceManager請求相應的Service,而負責這個管理任務的正是ServiceManager。也就是說,Service需要先向ServiceManager註冊自己,並得到自己的服務控制代碼,然後Client需要拿這個int型的控制代碼向ServiceManager請求相應的Service,ServiceManager再把相應的Service代理物件傳送給Client使用。同時我們注意到,ServiceManager本身也是一個Service,他需要先向Binder註冊自己,而且要把自己註冊為“管理員”,那麼這個註冊過程是怎樣的呢?我們來看原始碼:
int binder_become_context_manager(struct binder_state *bs)
{
//向Binder驅動傳送BINDER_SET_CONTEXT_MGR的訊息
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
我們看到,當ServiceManager向Binder驅動傳送BINDER_SET_CONTEXT_MGR的訊息時,Binder就會把他註冊為“管理員”。
三、Service_manager服務過程
3.1、Service_manager的執行流程
經過前面兩步的操作,我們不僅打開了Binder,而且把當前的ServiceManager註冊成為了管理員,下面要做的就是去承擔管理員的職責,也就是接收各種請求。這一步的入口是binder_loop():
void binder_loop(struct binder_state *bs, binder_handler func) {
int res;
struct binder_write_read bwr;
unsigned readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
//告訴Binder,ServiceManager將要進入LOOPER狀態了
binder_write(bs, readbuf, sizeof(unsigned));
for (;;) {
//準備要傳送的資料
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned) readbuf;
//與底層Binder通訊,得到客戶端的請求
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
//用func解析請求並構建應答返回給客戶端
res = binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
}
}
上面的過程表明了Service_manager進入迴圈的過程,主要分為三個步驟:1、先通過傳送BC_ENTER_LOOPER訊息告訴底層,ServiceManager將要進入迴圈了;
2、在死迴圈中讀取客戶端的請求;
3、處理請求;
上面的第一步是通過向Binder傳送BC_ENTER_LOOPER訊息實現的,第二步通過BINDER_WRITE_READ可以讀取Binder中的資料(請求);第三步需要呼叫binder_parse去處理客戶端的請求,我們主要看一下這個過程。
3.2、ServiceManager處理請求並回應客戶端的過程
ServiceManager是通過binder_parse()的函式來處理請求的: int binder_parse(struct binder_state *bs,struct binder_io *bio,uint32_t *ptr,uint32_t size,binder_handler func){
while (ptr < end) {
uint32_t cmd = *ptr++;
switch(cmd) {
case BR_NOOP:
case BR_TRANSACTION_COMPLETE:
case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS:
break;
case BR_TRANSACTION: {
struct binder_txn *txn = (void *) ptr;
binder_dump_txn(txn);
if (func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
//呼叫service_manager.c中的svcmgr_handler去處理資料
res = func(bs, txn, &msg, &reply);
//將Service_manager對客戶端的迴應資料(reply)返回給Binder驅動
binder_send_reply(bs, &reply, txn->data, res);
}
ptr += sizeof(*txn) / sizeof(uint32_t);
break;
}
case BR_REPLY:
case BR_DEAD_BINDER:
case BR_FAILED_REPLY:
case BR_DEAD_REPLY:
default:
}
}
return r;
}
這個函式中我們只關心BR_TRANSACTION分支,通過呼叫func去解析拿到的請求,然後把返回值作為迴應通過binder_send_reply()函式返回給客戶端。3.2.1、處理請求過程
我們先來看一下請求的處理過程,也就是func()的流程,這裡的func來自於呼叫binder_loop()時的引數: binder_loop(bs, svcmgr_handler);
因此func()就是svcmgr_handler(): int svcmgr_handler(struct binder_state *bs,struct binder_txn *txn,struct binder_io *msg,struct binder_io *reply){
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
//得到一個Service
s = bio_get_string16(msg, &len);
ptr = do_find_service(bs, s, len, txn->sender_euid);
bio_put_ref(reply, ptr);
return 0;
case SVC_MGR_ADD_SERVICE:
//新增一個Service
s = bio_get_string16(msg, &len);
ptr = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
if (do_add_service(bs, s, len, ptr, txn->sender_euid, allow_isolated))
return -1;
break;
case SVC_MGR_LIST_SERVICES: {
//得到當前所有的Service
unsigned n = bio_get_uint32(msg);
si = svclist;
while ((n-- > 0) && si)
si = si->next;
if (si) {
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
}
return 0;
}
從svcmgr_handler的case分支我們可以看出,作為Service_manager主要完成三個功能:1、得到一個Service;
2、新增一個Service;
3、列出所有的Service;
下面我們分別看一下這三個功能的實現方式,我們先從add一個Service開始:
int do_add_service(struct binder_state *bs,uint16_t *s,unsigned len,void *ptr,unsigned uid,int allow_isolated) {
struct svcinfo *si;
//檢查當前註冊的Service的uid和註冊的服務名稱是否有許可權
if (!svc_can_register(uid, s)) {
return -1;
}
//檢視是否已經add過了
si = find_svc(s, len);
if (si) {
if (si->ptr) {
svcinfo_death(bs, si);
}
si->ptr = ptr;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
si->ptr = ptr;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist;
//把當前需要註冊的Service新增到svclist中,完成註冊過程
svclist = si;
}
}
從add的過程可以看出,所謂向ServiceManager註冊一個服務,其實就是為當前的Service建立svcinfo的結構體,並把該結構體新增到svclist中。那麼我們可以推測,find的過程無非就是去svclist中查詢svcinfo的過程:
void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid) {
struct svcinfo *si;
//從svclist連結串列中得到當前請求的Service資訊
si = find_svc(s, len);
if (si && si->ptr) {
//得到一個Service需要這個Service的許可
if (!si->allow_isolated) {
//還要檢查申請者的uid是否匹配
unsigned appid = uid % AID_USER;
if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
return 0;
}
}
return si->ptr;
} else {
return 0;
}
}
這個過程確實如我們所料,需要通過find_svc()在svclist中尋找需要的Service並把該Service節點發送給請求的Client。那麼list Service的請求只需要把svclist返回給Client即可:
case SVC_MGR_LIST_SERVICES: {
unsigned n = bio_get_uint32(msg);
si = svclist;
while ((n-- > 0) && si)
si = si->next;
if (si) {
//把svclist返回給請求者
bio_put_string16(reply, si->name);
return 0;
}
return -1;
}
經過這些過程,ServiceManager就完成了解析資料的過程,下面就需要把相應的資料返回給客戶端。3.2.2、迴應客戶端的過程
在3.2.1中的三個請求處理過程中,特別是get和list Service的請求,最終都需要給客戶端相應迴應的,我們看到在這兩個請求的處理最後,都將相應的迴應資料放入了reply的指標中,當從svcmgr_handler()返回後,就把資料帶到了binder_parse()中,我們再來回顧一下這裡的程式碼: int binder_parse(struct binder_state *bs,struct binder_io *bio,uint32_t *ptr,uint32_t size,binder_handler func){
while (ptr < end) {
switch(cmd) {
case BR_TRANSACTION: {
struct binder_txn *txn = (void *) ptr;
binder_dump_txn(txn);
if (func) {
//reply就是svcmgr_handler()中得到的迴應
res = func(bs, txn, &msg, &reply);
//將回應資料(reply)返回給Binder驅動
binder_send_reply(bs, &reply, txn->data, res);
}
ptr += sizeof(*txn) / sizeof(uint32_t);
break;
}
}
}
return r;
}
在binder_parse()中又呼叫binder_send_reply()函式完成迴應的操作: void binder_send_reply(struct binder_state *bs, struct binder_io *reply, void *buffer_to_free, int status) {
struct {
uint32_t cmd_free;
void *buffer;
uint32_t cmd_reply;
struct binder_txn txn;
} __attribute__((packed)) data;
data.cmd_free = BC_FREE_BUFFER;
data.buffer = buffer_to_free;
data.cmd_reply = BC_REPLY;
data.txn.target = 0;
data.txn.cookie = 0;
data.txn.code = 0;
if (status) {
data.txn.flags = TF_STATUS_CODE;
data.txn.data_size = sizeof(int);
data.txn.offs_size = 0;
data.txn.data = &status;
data.txn.offs = 0;
} else {
data.txn.flags = 0;
data.txn.data_size = reply->data - reply->data0;
data.txn.offs_size = ((char*) reply->offs) - ((char*) reply->offs0);
data.txn.data = reply->data0;
data.txn.offs = reply->offs0;
}
//向Binder寫回應的資料
binder_write(bs, &data, sizeof(data));
}
在給Binder傳送返回值時,構建了data的資料,並把reply放入其中,並標記了資料的大小,最後通過binder_write()函式將資料寫到Binder中,而且寫的方法仍然是呼叫ioctl()。 int binder_write(struct binder_state *bs, void *data, unsigned len) {
struct binder_write_read bwr;
int res;
bwr.write_size = len;
bwr.write_consumed = 0;
bwr.write_buffer = (unsigned) data;
bwr.read_size = 0;
bwr.read_consumed = 0;
bwr.read_buffer = 0;
//向Binder寫資料
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
if (res < 0) {
fprintf(stderr,"binder_write: ioctl failed (%s)\n", strerror(errno));
}
return res;
}
經過以上步驟,就完成了一次完整的請求呼叫過程。