Binder源码分析之ServiceManager(原)
生活随笔
收集整理的這篇文章主要介紹了
Binder源码分析之ServiceManager(原)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
ServiceManager作為Native層Service的管理員,有著極其重要的作用,主要表現兩個方面:
? ? ? ? 1、對于服務端來說,系統所有的服務提供者都需要向ServiceManager注冊。
? ? ? ? 2、對于客戶端來說,所有客戶端如果想要獲得某個系統服務的代理,必須向ServiceManager申請相應的服務端代理。
@Service_manager.c(frameworks/base/cmds/servicemanager)?? int?main(int?argc,?char?**argv)?{?? ????struct?binder_state?*bs;?? ????void?*svcmgr?=?BINDER_SERVICE_MANAGER;?? ????//打開binder設備?? ????bs?=?<span?style="color:#ff0000;">binder_open</span>(128*1024);?? ????//成為Service?manager?? ????if?(<span?style="color:#ff0000;">binder_become_context_manager</span>(bs))?{?? ????????LOGE("cannot?become?context?manager?(%s)\n",?strerror(errno));?? ????????return?-1;?? ????}?? ????svcmgr_handle?=?svcmgr;?? ????//在binder_loop中循環檢測binder中是否有新的請求?? ????<span?style="color:#ff0000;">binder_loop</span>(bs,?svcmgr_handler);?? ????return?0;?? }?? ? ? ? ? main函數主要有三個功能:
? ? ? ? 1、打開Binder設備文件;
? ? ? ? 2、告訴Binder驅動程序自己是Binder上下文管理者;
? ? ? ? 3、進入一個死循環,充當Service的角色,等待Client的請求。
@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;?? }?? ? ? ? ? 上面打開Binder設備的過程其實就是構建一個binder_state結構體對象,然后對其各個成員初始化的過程。我們來看一下binder_state數據結構: [java]?view plaincopy 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設備;
? ? ? ? 同時我們注意到,ServiceManager本身也是一個Service,他需要先向Binder注冊自己,而且要把自己注冊為“管理員”,那么這個注冊過程是怎樣的呢?我們來看源碼: [java]?view plaincopy int?binder_become_context_manager(struct?binder_state?*bs)?? {?? ????//向Binder驅動發送BINDER_SET_CONTEXT_MGR的消息?? ????return?ioctl(bs->fd,?<span?style="color:#ff0000;">BINDER_SET_CONTEXT_MGR</span>,?0);?? }??
? ? ? ? 這一步的入口是binder_loop(): [java]?view plaincopy 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?=?<span?style="color:#ff0000;">ioctl</span>(bs->fd,?BINDER_WRITE_READ,?&bwr);?? ????????//用func解析請求并構建應答返回給客戶端?? ????????res?=?<span?style="color:#ff0000;">binder_parse</span>(bs,?0,?readbuf,?bwr.read_consumed,?<span?style="color:#ff0000;">func</span>);?? ????}?? }?? ? ? ? ? 上面的過程表明了Service_manager進入循環的過程,主要分為三個步驟:
? ? ? ? 1、先通過發送BC_ENTER_LOOPER消息告訴底層,ServiceManager將要進入循環了;
? ? ? ? 2、在死循環中讀取客戶端的請求;
? ? ? ? 3、處理請求;
? ? ? ? 上面的第一步是通過向Binder發送BC_ENTER_LOOPER消息實現的,第二步通過BINDER_WRITE_READ可以讀取Binder中的數據(請求);第三步需要調用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;?? ????????????<span?style="color:#ff0000;">case?BR_TRANSACTION</span>:?{?? ????????????????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()函數返回給客戶端。
binder_loop(bs,?svcmgr_handler);?? ? ? ? ? 因此func()就是svcmgr_handler(): [java]?view plaincopy 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開始: [java]?view plaincopy 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的過程: [java]?view plaincopy 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即可:
[java]?view plaincopy 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就完成了解析數據的過程,下面就需要把相應的數據返回給客戶端。
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()函數完成回應的操作: [java]?view plaincopy 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()。 [java]?view plaincopy 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;?? }??
? ? ? ? 1、對于服務端來說,系統所有的服務提供者都需要向ServiceManager注冊。
? ? ? ? 2、對于客戶端來說,所有客戶端如果想要獲得某個系統服務的代理,必須向ServiceManager申請相應的服務端代理。
? ? ? ? 下面從源碼分析ServiceManager的啟動流程和服務流程。
[java]?view plaincopy? ? ? ? 1、打開Binder設備文件;
? ? ? ? 2、告訴Binder驅動程序自己是Binder上下文管理者;
? ? ? ? 3、進入一個死循環,充當Service的角色,等待Client的請求。
? ? ? ? 下面我們就分別介紹這三個步驟。
一、打開Binder設備
[java]?view plaincopy? ? ? ? 從上面可以看出,打開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注冊自己,而且要把自己注冊為“管理員”,那么這個注冊過程是怎樣的呢?我們來看源碼: [java]?view plaincopy
? ? 我們看到,當ServiceManager向Binder驅動發送BINDER_SET_CONTEXT_MGR的消息時,Binder就會把他注冊為“管理員”。
三、Service_manager服務過程
3.1、Service_manager的執行流程
? ? ? ? 經過前面兩步的操作,我們不僅打開了Binder,而且把當前的ServiceManager注冊成為了管理員,下面要做的就是去承擔管理員的職責,也就是接收各種請求。? ? ? ? 這一步的入口是binder_loop(): [java]?view plaincopy
? ? ? ? 1、先通過發送BC_ENTER_LOOPER消息告訴底層,ServiceManager將要進入循環了;
? ? ? ? 2、在死循環中讀取客戶端的請求;
? ? ? ? 3、處理請求;
? ? ? ? 上面的第一步是通過向Binder發送BC_ENTER_LOOPER消息實現的,第二步通過BINDER_WRITE_READ可以讀取Binder中的數據(請求);第三步需要調用binder_parse去處理客戶端的請求,我們主要看一下這個過程。
3.2、ServiceManager處理請求并回應客戶端的過程
? ? ? ? ServiceManager是通過binder_parse()的函數來處理請求的: [java]?view plaincopy3.2.1、處理請求過程
? ? ? ? 我們先來看一下請求的處理過程,也就是func()的流程,這里的func來自于調用binder_loop()時的參數: [java]?view plaincopy? ? ? ? 1、得到一個Service;
? ? ? ? 2、添加一個Service;
? ? ? ? 3、列出所有的Service;
? ? ? ? 下面我們分別看一下這三個功能的實現方式,我們先從add一個Service開始: [java]?view plaincopy
? ? ? ? 那么我們可以推測,find的過程無非就是去svclist中查找svcinfo的過程: [java]?view plaincopy
? ? ? ? 那么list Service的請求只需要把svclist返回給Client即可:
[java]?view plaincopy
3.2.2、回應客戶端的過程
? ? ? ? 在3.2.1中的三個請求處理過程中,特別是get和list Service的請求,最終都需要給客戶端相應回應的,我們看到在這兩個請求的處理最后,都將相應的回應數據放入了reply的指針中,當從svcmgr_handler()返回后,就把數據帶到了binder_parse()中,我們再來回顧一下這里的代碼: [java]?view plaincopy? ? ? ? 經過以上步驟,就完成了一次完整的請求調用過程。
四、總結
? ? ? ? 我們用兩張圖來總結ServiceManager提供服務的過程。4.1、ServiceManager初始化流程
4.2、ServiceManager處理事務的流程
原文地址:http://blog.csdn.net/u010961631/article/details/19838637
總結
以上是生活随笔為你收集整理的Binder源码分析之ServiceManager(原)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 两种AIDL用法分析(原)
- 下一篇: Binder源码分析之驱动层(原)