跟著《Android藝術(shù)開發(fā)探索》一書學(xué)習(xí)了android中的進(jìn)程間通信,剛好和最近學(xué)習(xí)操作系統(tǒng)的進(jìn)程間通信做了比較。
android的IPC主要就是基于Binder,Messenger、ContentProvider的底層都是基于Binder。所以這篇文章主要分析一下Binder的底層實現(xiàn)。
Binder
Linux下的進(jìn)程間通信
Linux跨進(jìn)程通信涉及到一些基本概念:
- 進(jìn)程間隔離
進(jìn)程與進(jìn)程間內(nèi)存是不共享的。兩個進(jìn)程就像兩個平行的世界,A進(jìn)程無法訪問B進(jìn)程的數(shù)據(jù),B也無法訪問A。兩個進(jìn)程間要進(jìn)行數(shù)據(jù)交互需采用特殊的通信機制:進(jìn)程間通信(IPC)。
- 進(jìn)程空間劃分:用戶空間(User Space)/內(nèi)核空間(Kernel Space)
現(xiàn)在的操作系統(tǒng)采用的都是虛擬存儲技術(shù)。對32位系統(tǒng)而言,它的虛擬存儲空間是2^32,就是4GB。操作系統(tǒng)的核心是內(nèi)核,獨立于普通的應(yīng)用程序,可以訪問受保護(hù)的內(nèi)存空間,也可以訪問底層硬件設(shè)備的權(quán)限。為保護(hù)用戶進(jìn)程不能直接操作內(nèi)核,保證內(nèi)核的安全,操作系統(tǒng)從邏輯上將虛擬空間劃分為用戶空間和內(nèi)核空間。
- 系統(tǒng)調(diào)用:用戶態(tài)/內(nèi)核態(tài)
雖然劃分了用戶空間和內(nèi)核空間,但是用戶在某些情況下需要訪問內(nèi)核資源(文件操作等)。這時候就需要借助系統(tǒng)調(diào)用。
當(dāng)一個進(jìn)程執(zhí)行系統(tǒng)調(diào)用而陷入內(nèi)核代碼中執(zhí)行時,稱此進(jìn)程處于內(nèi)核態(tài);當(dāng)進(jìn)程在執(zhí)行用戶自己的代碼的時候,稱進(jìn)程處于用戶態(tài)
系統(tǒng)調(diào)用主要下面兩個函數(shù)實現(xiàn):
copy_from_user()//將數(shù)據(jù)從用戶空間拷貝到內(nèi)核空間
copy_to_user()//將數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間
從上圖可以看到傳統(tǒng)的IPC通信存在兩個問題
- 一次數(shù)據(jù)傳遞需要經(jīng)過兩次拷貝:內(nèi)存緩存區(qū)-->內(nèi)核緩存區(qū)-->內(nèi)存緩存區(qū)
- 浪費空間和時間:接收區(qū)的緩存區(qū)由數(shù)據(jù)接收進(jìn)程提供,但接收進(jìn)程并不知道要多大的空間來存放傳遞過來的數(shù)據(jù)。
Binder下的進(jìn)程間通信
Binder通信采用C/S架構(gòu),包含Client、Server、ServiceManager以及Binder驅(qū)動。其中ServiceManager用于管理系統(tǒng)中的各種服務(wù)。架構(gòu)圖如下:
從圖中可以看到注冊服務(wù)和獲取服務(wù)都需要ServiceManager,這里的ServiceManager是Native層的(C++),不是framework層的ServiceManager(java)。SericeManager是Binder機制中的大管家,是android進(jìn)程間通信的守護(hù)進(jìn)程??聪聢D中標(biāo)出的三大步驟:
- 注冊服務(wù)(addService):Server進(jìn)程要先注冊服務(wù)到ServiceManager。該過程:Server是客戶端,ServiceManager是服務(wù)端。
- 獲取服務(wù)(getService):Client進(jìn)程使用某個Service之前,必須向ServiceManager中獲取相應(yīng)的Service。該過程:Client是客戶端,ServiceManager是服務(wù)端。
- 使用服務(wù):Client根據(jù)得到的Service信息建立與Service所在的Server進(jìn)程的通路,之后就可以與Service進(jìn)行交互。該過程:Client是客戶端,Server是服務(wù)端。
- 最重要的一點是,三者的交互都是基于Binder通信的,通過任意兩者的關(guān)系都可以揭示Binder的奧秘。
圖中Client、Server、ServiceManager彼此之間不是直接交互,而是通過Binder驅(qū)動進(jìn)行交互,實現(xiàn)IPC方式。Binder驅(qū)動位于內(nèi)核空間,它們都位于用戶空間。
Binder Driver
注冊服務(wù)和獲取服務(wù)都基于ServiceManager,也就是需要獲取ServiceManager,獲取之前需要啟動ServiceManager,最終會調(diào)用底層Binder驅(qū)動。所以先從Binder的底層驅(qū)動看起。
Binder驅(qū)動底層的驅(qū)動架構(gòu)和Linux驅(qū)動一樣,Binder驅(qū)動在以misc設(shè)備(Linux的一種雜項特殊字符設(shè)備),作為虛擬字符設(shè)備,沒有直接操作硬件,只是對設(shè)備內(nèi)存的處理。Binder驅(qū)動設(shè)備的初始化(binder_init),打開(binder_open),映射(binder_mmap),數(shù)據(jù)操作(binder_ioctl)。
用戶態(tài)程序調(diào)用內(nèi)核層程序需要陷入內(nèi)核態(tài),會進(jìn)行系統(tǒng)調(diào)用(syscall),例如:打開Binder驅(qū)動方法的調(diào)用鏈為open()-->_open()-->binder_open()。open()為用戶態(tài)方法,_open()是系統(tǒng)調(diào)用,通過查找對應(yīng)調(diào)用到內(nèi)核binder驅(qū)動的binder_open()方法。下面從四個方法來看binder驅(qū)動:
binder_init
注冊字符驅(qū)動設(shè)備misc
binder_open
打開binder驅(qū)動設(shè)備。這里會創(chuàng)建binder_proc對象,也就是binder進(jìn)程,為binder初始化一些信息,并把每次都創(chuàng)建的binder_proc對象加入binder_procs鏈表中。
binder_mmap
我覺得這是binder驅(qū)動的核心點,binder之所以優(yōu)于傳統(tǒng)IPC就是因為binder有內(nèi)存映射。
主要功能(分三步):
- 首先在內(nèi)核虛擬地址空間申請一塊和用戶虛擬內(nèi)存大小相同的內(nèi)存;
- 再申請1個page(頁)大小的物理內(nèi)存;
- 再將同一塊物理內(nèi)存分別映射到內(nèi)核虛擬地址空間和用戶虛擬內(nèi)存空間。
這樣就實現(xiàn)了用戶空間的Buffer和內(nèi)核空間的Buffer同步操作的功能。
映射的這個想的很巧妙,這使得Binder通信只需要從用戶空間復(fù)制一次信息到內(nèi)核空間就可以了。但是用戶空間怎么就通過映射讀到了數(shù)據(jù),是向HashMap那樣有一個key對應(yīng)這么,通過下面這張圖可以看到:
虛擬進(jìn)程地址空間和虛擬內(nèi)核地址空間都映射到同一塊物理內(nèi)存。當(dāng)client端向server端發(fā)送數(shù)據(jù)時,client把自己進(jìn)程空間的通信數(shù)據(jù)拷貝(copy_from_user)到內(nèi)核空間,server端和內(nèi)核共享數(shù)據(jù),不需要再拷貝數(shù)據(jù)。通過內(nèi)存地址的偏移量獲得內(nèi)存地址(這里有點像今天剛上課聽的微機原理里的尋址方法,感覺很有意思),只發(fā)生了一次拷貝。
binder_ioctl
從上面的ServiceManager交互的圖中我們可以看到Client和Server實際上是通過ioctl和driver交互的。
binder_ioctl()函數(shù)負(fù)責(zé)在兩個進(jìn)程間收發(fā)IPC數(shù)據(jù)。這就可以對應(yīng)到之前寫過的Binder通信的文件。我們將數(shù)據(jù)放入輸入型Parcel _data,用輸出型Parcel _reply接收服務(wù)端返回的數(shù)據(jù)。執(zhí)行ioctl操作時,read_buffer需要持有binder_main_lock同步鎖,并處于wait_event_freezable過程,等有數(shù)據(jù)到來是則喚醒并嘗試持有同步鎖。
ServiceManager
分析完了驅(qū)動層知道了驅(qū)動層是怎么被初始化 打開 被分配內(nèi)存。就需要再進(jìn)一步了解ServiceManager,ServiceManager作為大管家這里主要分析它的啟動以及注冊、查詢服務(wù),如何和binder驅(qū)動建立聯(lián)系。
ServiceManager自行編寫了binder.c直接和binder驅(qū)動進(jìn)行通信,并且只有一個循環(huán)binder_lopp來進(jìn)行讀取和處理事務(wù)。其本身工作相對簡單,主要功能就是查詢和注冊服務(wù)。Binder IPC通信過程中,其實是BpBinder和BBinder之間的通信,后面會介紹到。
這里有一張別人畫的ServiceManager從創(chuàng)建到實現(xiàn)自己功能的時序圖,我覺得對從整體來把握ServiceManager有一定的幫助和統(tǒng)領(lǐng)的作用。
ServiceManager啟動過程
參照時序圖,啟動過程主要分為以下幾個階段:
- 打開binder驅(qū)動:binder_open;
- 注冊成為binder服務(wù)的大管家:binder_become_context_manager;
- 進(jìn)入無線循環(huán),處理client端發(fā)來的請求:binder_loop。
ServiceManager是由init進(jìn)程通過解析init.rc文件而創(chuàng)建的。啟動ServiceManager的入口函數(shù)是service_manager.c中的main()方法,代碼如下:
main
int main(int argc, char **argv) {
struct binder_state *bs;
//BINDER_SERVICE_MANAGER值為null,用來標(biāo)志文件的格式
void *svcmgr = BINDER_SERVICE_MANAGER;
//打開binder驅(qū)動,申請大小為128KB字節(jié)大小的內(nèi)存空間
bs = binder_open(128*1024);
//成為manager(上下文管理者)
if (binder_become_context_manager(bs)) {
return -1;
}
//進(jìn)入無限循環(huán)狀態(tài),處理client端發(fā)來的請求
binder_loop(bs, svcmgr_handler);
return 0;
}
binder_open
struct binder_state *binder_open(size_t mapsize)
{
struct binder_state *bs;【見小節(jié)2.2.1】
struct binder_version vers;
bs = malloc(sizeof(*bs));
if (!bs) {
errno = ENOMEM;
return NULL;
}
````
bs->mapsize = mapsize;
//通過系統(tǒng)調(diào)用,mmap內(nèi)存映射,mmap必須是page的整數(shù)倍
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
if (bs->mapped == MAP_FAILED) {
goto fail_map; // binder設(shè)備內(nèi)存無法映射
}
return bs;
`````
}
binder_open主要就是打開驅(qū)動設(shè)備,系統(tǒng)調(diào)用mmap內(nèi)存映射。
binder_become_context_manager
int binder_become_context_manager(struct binder_state *bs)
{
//0是設(shè)置的handle,BINDER_SET_CONTEXT_MGR設(shè)置ServiceManager結(jié)點
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
binder_ioctl
static long binder_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) {
binder_lock(__func__);
switch (cmd) {
case BINDER_SET_CONTEXT_MGR:
ret = binder_ioctl_set_ctx_mgr(filp);
break;
}
case :...
}
binder_unlock(__func__);
}
根據(jù)參數(shù)BINDER_SET_CONTEXT_MGR,最終調(diào)用binder_ioctl_set_ctx_mgr()方法,這個過程會持有binder_main_lock。
binder_ioctl_set_ctx_mgr
static int binder_ioctl_set_ctx_mgr(struct file *filp)
{
int ret = 0;
struct binder_proc *proc = filp->private_data;
kuid_t curr_euid = current_euid();
//保證只創(chuàng)建一次mgr_node對象
if (binder_context_mgr_node != NULL) {
ret = -EBUSY;
goto out;
}
if (uid_valid(binder_context_mgr_uid)) {
...
} else {
//設(shè)置當(dāng)前線程euid作為Service Manager的uid
binder_context_mgr_uid = curr_euid;
}
//創(chuàng)建ServiceManager實體
binder_context_mgr_node = binder_new_node(proc, 0, 0);
````
}
在這里創(chuàng)建了ServiceManager實體binder_new_node()方法中創(chuàng)建了binder_node結(jié)構(gòu)體,也就是binder實體。
binder_loop
void binder_loop(struct binder_state *bs, binder_handler func) {
int res;
struct binder_write_read bwr;
uint32_t readbuf[32];
bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER;
//將BC_ENTER_LOOPER命令發(fā)送給binder驅(qū)動,讓Service Manager進(jìn)入循環(huán)
//binder_write方法中調(diào)用ioctl方法,將bwr數(shù)據(jù)發(fā)送給binder驅(qū)動,調(diào)用binder_ioctl方法,獲取binder_thread,進(jìn)行binder的讀寫操作。
binder_write(bs, readbuf, sizeof(uint32_t));
for (;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (uintptr_t) readbuf;
res = ioctl(bs->fd, BINDER_WRITE_READ, &bwr); //進(jìn)入循環(huán),不斷地binder讀寫過程
if (res < 0) {
break;
}
// 接收到請求,交給binder_parse處理
res = binder_parse(bs, 0, (uintptr_t) readbuf, bwr.read_consumed, func);
if (res == 0) {
break;
}
if (res < 0) {
break;
}
}
}
binder_parse
int binder_parse(struct binder_state *bs, struct binder_io *bio,
uintptr_t ptr, size_t size, binder_handler func)
{
int r = 1;
uintptr_t end = ptr + (uintptr_t) size;
while(ptr < end){
switch(cmd) {
case BR_NOOP: //無操作,退出循環(huán)
break;
case BR_TRANSACTION_COMPLETE:
break;
case BR_INCREFS:
case BR_ACQUIRE:
case BR_RELEASE:
case BR_DECREFS:
ptr += sizeof(struct binder_ptr_cookie);
break;
case BR_TRANSACTION: {
`````
//初始化reply
bio_init(&reply, rdata, sizeof(rdata), 4);
//從txn解析出binder_io信息
bio_init_from_txn(&msg, txn);
//func指向svcmgr_handler,調(diào)用svcmgr_handler
res = func(bs, txn, &msg, &reply);
binder_send_reply(bs, &reply, txn->data.ptr.buffer, res);
`````
}
break;
case BR_REPLY: {
break;
}
case BR_DEAD_BINDER: {
break;
}
case BR_FAILED_REPLY:
r = -1;
break;
case BR_DEAD_REPLY:
r = -1;
break;
default:
return -1;
}
}
這個方法在binder_loop中,用于接收請求,根據(jù)請求的類別執(zhí)行對應(yīng)的方法。
svcmgr_handler
binder_loop中傳遞的函數(shù)指針是svcmgr_handler
int svcmgr_handler(struct binder_state *bs,
struct binder_transaction_data *txn,
struct binder_io *msg,
struct binder_io *reply)
{
`````
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
//獲取服務(wù)名
s = bio_get_string16(msg, &len);
//根據(jù)名稱查找相應(yīng)服務(wù),返回服務(wù)所對應(yīng)的handle
handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
//將handle封裝到reply
bio_put_ref(reply, handle);
return 0;
case SVC_MGR_ADD_SERVICE:
//獲取服務(wù)名
s = bio_get_string16(msg, &len);
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
//注冊指定服務(wù)(檢查權(quán)限、根據(jù)名稱檢索服務(wù)、查詢到同名的釋放后保存當(dāng)前服務(wù))
if (do_add_service(bs, s, len, handle, txn->sender_euid,allow_isolated, txn->sender_pid))
return -1;
break;
//得到當(dāng)前系統(tǒng)中已經(jīng)注冊的所有的名字
case SVC_MGR_LIST_SERVICES:
`````
}
可以看到這個方法中:查詢服務(wù)、注冊服務(wù),以及列舉所有服務(wù)
總結(jié)
- ServiceManager啟動流程
- 打開binder驅(qū)動(binder_open),調(diào)用mmap()方法分配128KB的內(nèi)存映空間;
- 調(diào)用binder_become_context_manager(),參數(shù)BINDER_SET_CONTEXT_MGR信號傳入ioctl()方法,調(diào)用binder_ioctl創(chuàng)建出ServiceManager實體;
- 調(diào)用binder_loop()方法,循環(huán)接收客戶端傳來的信息,循環(huán)讀寫操作。通過iotcl將數(shù)據(jù)發(fā)送給binder驅(qū)動(binder_loop()-->binder_write()-->iotcl()-->binder_ioctl()-->binder_iotcl_write_read()進(jìn)行數(shù)據(jù)的讀寫和將數(shù)據(jù)拷貝到用戶buf)
- 注冊服務(wù)、查詢服務(wù)。
獲取服務(wù)
在進(jìn)程注冊服務(wù)和獲取服務(wù)的過程之前,都需要先調(diào)用defaultServiceManager()方法來獲取getDefaultServiceManager對象。
defaultServiceManager
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
{
AutoMutex _l(gDefaultServiceManagerLock); //加鎖
while (gDefaultServiceManager == NULL) {
//創(chuàng)建真正的gDefaultServiceManager
gDefaultServiceManager = interface_cast<IServiceManager>(
ProcessState::self()->getContextObject(NULL));
if (gDefaultServiceManager == NULL)
sleep(1);
}
}
return gDefaultServiceManager;
}
獲取ServiceManager對象采用了單例模式。很有意思的一點的事,ggDefaultServiceManager是在一個循環(huán)中被創(chuàng)建的。這是因為當(dāng)獲取ServiceManager時,ServiceManager可能還未準(zhǔn)備就緒,因此通過sleep 1s,通過循環(huán)嘗試直到成功。
getDefaultServiceManager分為下面三個步驟:
- ProcessState::self():用于獲取ProcessState對象;
- getContextObject():用于獲取BpBinder對象;
- interface_cast<IServiceManager>:用于獲取BpServiceManager對象。
獨一無二的ProcessState
每個進(jìn)程只有一個ProcessState。
ProcessState::self
sp<ProcessState> ProcessState::self()
{
Mutex::Autolock _l(gProcessMutex);
if (gProcess != NULL) {
return gProcess;
}
//實例化ProcessState
gProcess = new ProcessState;
return gProcess;
}
獲取ProcessState對象也采用單例模式,保證了每個進(jìn)程只有一個ProcessState對象。其中g(shù)Process和gProcessMuted保存在static.c類的全局變量。
構(gòu)造ProcessState
ProcessState::ProcessState()
: mDriverFD(open_driver())//打開binder驅(qū)動
, mVMStart(MAP_FAILED)//映射內(nèi)存的起始地址
, mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
, mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
, mExecutingThreadsCount(0)
, mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
, mManagesContexts(false)
, mBinderContextCheckFunc(NULL)
, mBinderContextUserData(NULL)
, mThreadPoolStarted(false)
, mThreadPoolSeq(1)
{
//mDriverFD記錄binder驅(qū)動的fd,用于訪問binder設(shè)備
if (mDriverFD >= 0) {
//采用內(nèi)存映射函數(shù)mmap,給binder分配一塊虛擬地址空間,用來接收事務(wù)
mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
if (mVMStart == MAP_FAILED) {
close(mDriverFD); //沒有足夠空間分配給/dev/binder,則關(guān)閉驅(qū)動
mDriverFD = -1;
}
}
}
- 因為ProcessState單例模式的唯一性,一個進(jìn)程只能打開一個binder設(shè)備。
- BINDER_VM_SIZE:(102410241)-(4096*2) = 1M-8K 。
- DEFAULT_ MAX_BINDER_THREADS:binder默認(rèn)的最大可并發(fā)訪問線程數(shù)。
打開binder設(shè)備
static int open_driver(){
int fd = open("/dev/binder",O_RDWR);
if(fd > 0){
`````
size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
// 通過ioctl設(shè)置binder驅(qū)動,能支持的最大線程數(shù)
result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
}
}
從這里可以從binder驅(qū)動層打開binder驅(qū)動的方式聯(lián)系起來open_driver()-->open-->binder_open()。
Process::self函數(shù)功能:
- 打開dev/binder設(shè)備,相當(dāng)于和內(nèi)核的Binder驅(qū)動有了交互。
- 對返回的fd使用mmap,這樣Binder驅(qū)動會分配一塊內(nèi)訓(xùn)來接收數(shù)據(jù)。
- ProcessState具有唯一性,因此一個進(jìn)程只打開設(shè)備一次。
獲取BpBinder對象
getContextObject
繼續(xù)defaultServiceManager()中的方法
sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& caller){
if(supportProcess()){
return getStrongProxyForHandle(0);
}else{
return getContextObject(String16("default"),caller);
}
}
- 該方法返回IBinder對象。
- supportProcess():根據(jù)open_driver()函數(shù)是否可以打開來判斷設(shè)備是否支持進(jìn)程,真實設(shè)備肯定支持process,所以調(diào)用getStrongProxyForHandle函數(shù)。
- getStrongProxyForHandle(0):它傳入的參數(shù)名叫handle,是對資源的一種標(biāo)識。也就是一個資源項放在了一個資源數(shù)組中,handle的值是該資源項在數(shù)組中的索引。
getStrongProxyForHandle
sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
//查找handle對應(yīng)的資源項【見小節(jié)3.3】
handle_entry* e = lookupHandleLocked(handle);
if (e != NULL) {
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) {
if (handle == 0) {
Parcel data;
//通過ping操作測試binder是否準(zhǔn)備就緒
status_t status = IPCThreadState::self()->transact(
0, IBinder::PING_TRANSACTION, data, NULL, 0);
if (status == DEAD_OBJECT)
return NULL;
}
//當(dāng)handle值所對應(yīng)的IBinder不存在或弱引用無效時,則創(chuàng)建BpBinder對象【見小節(jié)3.4】
b = new BpBinder(handle);
e->binder = b;
if (b) e->refs = b->getWeakRefs();
result = b;
} else {
result.force_set(b);
e->refs->decWeak(this);
}
}
return result;
}
這個方法主要創(chuàng)建BpBinder對象。
- lookipHandleLocked(handle):根據(jù)索引查找對應(yīng)的資源項。如果沒有,會創(chuàng)建新的資源項。
- 對于新的資源項,其binder為空(b==null),創(chuàng)建一個BpBinder。
看到這里就會好奇到底BpBinder是干什么的。BpBinder和BBinder都是android中和Binder通信相關(guān)的代表,它們都從IBinder類中派生而來。和ServieManager交互獲取服務(wù)和注冊服務(wù)的其實是這兩個類,不是我們俗稱的客戶端和服務(wù)端。
從上面的圖可以看到;
- BpBinder是客戶端用來和Server交互的代理類。
- BBinder則是和proxy相對應(yīng)的,它是和proxy交互的對端。可以說proxy代表客戶端,BBinder代表服務(wù)端
- BpBinder和BBinder必須是一一對應(yīng)的。Binder系統(tǒng)通過handle值來標(biāo)識對應(yīng)BBinder。在new BpBinder(handle)時傳入了0,0代表的就是ServiceManager所對應(yīng)的BBinder。
創(chuàng)建BpBinder
BpBinder::BpBinder(int32_t handle)
: mHandle(handle)
, mAlive(1)
, mObitsSent(0)
, mObituaries(NULL)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
IPCThreadState::self()->incWeakHandle(handle);
}
通過源碼,BpBinder、BBinder這兩個類并沒有對ProcessState打開的/dev/binder設(shè)備進(jìn)行操作,也就是他們之間沒有交互。
BpServiceManager
通過下面來看到底BpBinder為什么與通信相關(guān)。
interface_cast
依舊從defaultServiceManager方法中入手:
template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
return INTERFACE::asInterface(obj);
}
這是一個模板函數(shù),等價于:
inline sp<IServiceManager> interface_cast(const sp<IBinder>& obj)
{
return IServiceManager::asInterface(obj);
}
這里又轉(zhuǎn)移到了IServiceManager中
IServiceManager
class IServiceManager : public IInterface{
public:
//很重要的宏定義
DECLARE_META_INTERFACE(ServiceManager);
``````
//這里是ServiceManager提供的業(yè)務(wù)函數(shù)
virtual sp<IBinder> getService();
virtual sp<IBinder> checkService();
virtual status_t addService();
virtual Vector<String16> listServices() = 0;
``````
}
IServiceManager定義了ServiceManager所提供的服務(wù),這是如何和IBinder通信家族聯(lián)系在一起的。就需要宏定義。宏定義將業(yè)務(wù)和通信掛鉤,展開后的代碼如下:
const android::String16 IServiceManager::descriptor(“android.os.IServiceManager”);
//實現(xiàn)了getInterfaceDescriptor函數(shù)
const android::String16& IServiceManager::getInterfaceDescriptor() const
{
//返回android.os.IServiceManager
return IServiceManager::descriptor;
}
android::sp<IServiceManager> IServiceManager::asInterface(const android::sp<android::IBinder>& obj)
{
android::sp<IServiceManager> intr;
if(obj != NULL) {
intr = static_cast<IServiceManager *>(
obj->queryLocalInterface(IServiceManager::descriptor).get());
if (intr == NULL) {
intr = new BpServiceManager(obj);
}
}
return intr;
}
IServiceManager::IServiceManager () { }
IServiceManager::~ IServiceManager() { }
- 實現(xiàn)了asInterface():new BpServiceManager(obj),obj是剛才創(chuàng)建出的BpBinder(0)。追溯回去,發(fā)現(xiàn)interface_cast利用BpBinder對象為參數(shù)新建了BpServiceManager對象。
gDefaultServiceManager = interface_cast<IServiceManager>(new BpBinder(0));
BpServiceManager實例化
創(chuàng)建BpServiceManager對象的過程,會先初始化父類對象
BpServiceManager初始化
//impl是IBinder類型
BpServiceManager(const sp<IBinder>& impl)
: BpInterface<IServiceManager>(impl)
{ }
BpInterface初始化
inline BpInterface<INTERFACE>::BpInterface(const sp<IBinder>& remote)
:BpRefBase(remote)
{ }
BpRefBase初始化
BpRefBase::BpRefBase(const sp<IBinder>& o)
: mRemote(o.get()), mRefs(NULL), mState(0)
{
extendObjectLifetime(OBJECT_LIFETIME_WEAK);
if (mRemote) {
mRemote->incStrong(this);
mRefs = mRemote->createWeak(this);
}
}
- 最終mRemote = new BpBinder(0)
- BpBinder對象的handle值為0,和它對應(yīng)的BBinder建立一一對應(yīng);BpServiceManager對象,它的mRemote值是BpBinder。
BpServiceManager不僅實現(xiàn)了IServiceManager的業(yè)務(wù)函數(shù),還有BpBinder作為通信代表。
總結(jié)
defaultServiceManager等價于new BpServiceManager(new BpBinder(0))
ProcessState::self()主要工作:
- 打開/dev/binder驅(qū)動設(shè)備
- 調(diào)用mmap(),創(chuàng)建大小為1M - 8k的內(nèi)存地址空間
- 設(shè)定當(dāng)前進(jìn)程的最大并發(fā)binder線程個數(shù)為15
ServiceManager可直接與binder驅(qū)動進(jìn)行交互。重要的還有IBinder的通信族。
BpServiceManager將通信層與業(yè)務(wù)層邏輯合為一體:
- 通過繼承IServiceManager接口,實現(xiàn)接口中的業(yè)務(wù)邏輯函數(shù)(添加service等)
- 通過成員變量mRemote = new BpBinder(0)進(jìn)行Binder通信工作
- BpBinder通過handle來指向所對應(yīng)的BBinder
注冊服務(wù)
注冊服務(wù)我們通過MediaService的具體注冊過程來看
media服務(wù)注冊
int main(int argc __unused, char** argv)
{
...
InitializeIcuOrDie();
//獲得ProcessState實例對象
sp<ProcessState> proc(ProcessState::self());
//獲取BpServiceManager對象
sp<IServiceManager> sm = defaultServiceManager();
AudioFlinger::instantiate();
//注冊多媒體服務(wù)
MediaPlayerService::instantiate();
ResourceManagerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
SoundTriggerHwService::instantiate();
RadioService::instantiate();
registerExtensions();
//啟動Binder線程池
ProcessState::self()->startThreadPool();
//當(dāng)前線程加入到線程池
IPCThreadState::self()->joinThreadPool();
}
上面是native層中media服務(wù)注冊的過程。
分別為下面幾個過程:
- 獲取ProcessState對象
- 獲取ServiceManager對象,也就是BpManagerService
- 注冊服務(wù)
- 啟動binder線程池
- 將當(dāng)前線程加入到線程池
獲取取ProcessState對象和ServiceManager對象在上節(jié)已經(jīng)分析過,這里主要看注冊服務(wù)的過程。
業(yè)務(wù)層的工作
instantiate()
void MediaPlayerService::instantiate() {
//注冊服務(wù)
defaultServiceManager()->addService(String16("media.player"), new MediaPlayerService());
}
注冊服務(wù)MediaPlayerService:
- defaultServiceManager返回BpManagerService,同時會創(chuàng)建ProcessState和BpBinder對象
- 等價于調(diào)用BpServiceManager-->addService
BpSM.addService()
virtual status_t addService(const String16& name, const sp<IBinder>& service, bool allowIsolated) {
Parcel data, reply;
//Parcel相當(dāng)于數(shù)據(jù)包,在aidl生成的文件中就出現(xiàn)過
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
data.writeString16(name);
data.writeStrongBinder(service);
data.writeInt32(allowIsolated ? 1 : 0);
//remote返回的就是mRemote,也就是BpBinder對象
status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
return err == NO_ERROR ? reply.readExceptionCode() : err;
}
可以看到,addService作為BpManagerService的業(yè)務(wù)函數(shù),把請求數(shù)據(jù)包打包成data后傳給了BpBinder的transact函數(shù)。也就是把通信的工作交給了BpBinder。
業(yè)務(wù)層的功能就是將請求數(shù)據(jù)打包,交給通信層去處理。
通信層的工作
之前在初始化BpBinder的函數(shù)中我們沒有發(fā)現(xiàn)BpBinder與binder驅(qū)動設(shè)備有任何的交互,但是在binder的體系架構(gòu)圖中客戶端確實是通過ioctl和binder驅(qū)動進(jìn)行了通信。再繼續(xù)往下看:
BpBinder::transact
status_t BpBinder::transact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
if (mAlive) {
//把工作交給了IPCTHreadState
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
return status;
}
return DEAD_OBJECT;
}
BpBinder調(diào)用transact,但是真正執(zhí)行的IPCTHreadState,BpBinder相當(dāng)于一個工具,讓別人去工作,啊哈哈哈。。。
IPCTHreadState::self()
看樣子是個通信線程?
IPCThreadState* IPCThreadState::self()
{
//第一次進(jìn)來為false
if (gHaveTLS) {
restart:
const pthread_key_t k = gTLS;
//獲取TLS空間中的內(nèi)容
IPCThreadState* st = (IPCThreadState*)pthread_getspecific(k);
if (st) return st;
//new一個對象 構(gòu)造函數(shù)中會調(diào)用pthread_serspecific
return new IPCThreadState;
}
if (gShutdown) return NULL;
pthread_mutex_lock(&gTLSMutex);
if (!gHaveTLS) {
//創(chuàng)建線程的TLS
if (pthread_key_create(&gTLS, threadDestructor) != 0) {
pthread_mutex_unlock(&gTLSMutex);
return NULL;
}
gHaveTLS = true;
}
pthread_mutex_unlock(&gTLSMutex);
goto restart;
}
這個方法中:
- gHavaTLS == true:使用pthread_getspecific獲取IPCTHreadState對象,并返回這個對象
- gHaveTLS == false:便會創(chuàng)建線程的TLS
TLS是Thread Local Storge(線程本地存儲空間)的簡稱。學(xué)過操作系統(tǒng)可知,這種空間每個線程都有,而且線程不共享這些空間。通過pthread_setspecific/pthread_getspecific函數(shù)可以設(shè)置/獲取這些空間中的內(nèi)容。**從線程本地存儲空間中獲得保存在其中的IPCTHreadState對象。
之前在操作系統(tǒng)課上還做過創(chuàng)建線程的實驗,pthread_create()感覺很有意思,要好好學(xué)操作系統(tǒng)呀!
IPCTHreadState::IPCTHreadState()
從上面的情況來看,我們是很有必要了解IPCTHreadState的,下面看下它的構(gòu)造函數(shù)
IPCThreadState::IPCThreadState()
: mProcess(ProcessState::self()),
mMyThreadId(gettid()),
mStrictModePolicy(0),
mLastTransactionBinderFlags(0)
{
//在構(gòu)造函數(shù)中,把自己保存到了線程本地存儲中
pthread_setspecific(gTLS, this);
clearCaller();
mIn.setDataCapacity(256);
mOut.setDataCapacity(256);
}
可以看到:
- 成員變量mProcess保存了ProcessState變量(每個進(jìn)程只有一個)
- 每個線程都有一個IPCTHreadState
- 每個IPCTHreadState都有一個mIn,mOut
- mIn:接收來自Binder設(shè)備的數(shù)據(jù)
- mOut:存儲發(fā)往Binder設(shè)備的數(shù)據(jù)
IPCTHreadState::transact
transact這個方法是用來提交事務(wù)的,在學(xué)習(xí)binder通信的時候,學(xué)著寫aidl文件對應(yīng)的binder通信模板代碼中就有,看看它在native層是怎么一會事。
status_t IPCThreadState::transact(int32_t handle,
uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags)
{
status_t err = data.errorCheck(); //數(shù)據(jù)錯誤檢查
flags |= TF_ACCEPT_FDS;
....
if (err == NO_ERROR) { // 傳輸數(shù)據(jù)
err = writeTransactionData(BC_TRANSACTION, flags, handle, code, data, NULL);
}
...
if ((flags & TF_ONE_WAY) == 0) {
if (reply) {
//等待響應(yīng)
err = waitForResponse(reply);
} else {
Parcel fakeReply;
err = waitForResponse(&fakeReply);
}
} else {
//oneway,則不需要等待reply的場景
err = waitForResponse(NULL, NULL);
}
return err;
}
transact事務(wù)處理三大流程:
- errorCheck() 數(shù)據(jù)錯誤檢查
- writeTransactionData() 傳輸數(shù)據(jù)
其中的參數(shù)BC_TRANSACTION,是應(yīng)用程序向binder設(shè)備發(fā)送消息的消息碼。binder設(shè)備向應(yīng)用程序恢復(fù)消息的消息碼以BR_開頭。
- waitForResponse()
IPCTHreadState::writeTransactionData()
作為通信,最重要的就是傳輸數(shù)據(jù)的這一方法
status_t IPCThreadState::writeTransactionData(int32_t cmd, uint32_t binderFlags,
int32_t handle, uint32_t code, const Parcel& data, status_t* statusBuffer)
{
//是和binder設(shè)備通信的數(shù)據(jù)結(jié)構(gòu)
binder_transaction_data tr;
tr.target.ptr = 0;
tr.target.handle = handle; // handle = 0
tr.code = code; // code = ADD_SERVICE_TRANSACTION
tr.flags = binderFlags; // binderFlags = 0
tr.cookie = 0;
tr.sender_pid = 0;
tr.sender_euid = 0;
// data為記錄Media服務(wù)信息的Parcel對象
const status_t err = data.errorCheck();
if (err == NO_ERROR) {
tr.data_size = data.ipcDataSize(); // mDataSize
tr.data.ptr.buffer = data.ipcData(); //mData
tr.offsets_size = data.ipcObjectsCount()*sizeof(binder_size_t); //mObjectsSize
tr.data.ptr.offsets = data.ipcObjects(); //mObjects
} else if (statusBuffer) {
...
} else {
return (mLastError = err);
}
mOut.writeInt32(cmd); //cmd = BC_TRANSACTION
mOut.write(&tr, sizeof(tr)); //寫入binder_transaction_data數(shù)據(jù)
return NO_ERROR;
}
這個方法中主要就是為binder_transaction_data這個數(shù)據(jù)結(jié)構(gòu)中的內(nèi)容賦值,并將BC_TRANSACTIN命令和這個數(shù)據(jù)結(jié)構(gòu)寫入到mOut中。
- handle值用來標(biāo)識目的端,注冊服務(wù)的目的端就是ServiceManager。在創(chuàng)建ServiceManager的方法binder_become_context_manager方法一步步往下調(diào)用的時候,有一個方法binder_ioctl_set_ctx_mgr方法創(chuàng)建了ServiceManager實體。這個實體是binder_context_mgr_node。
- Parcel data中的重要成員變量:
- mDataSize:binder_transaction_data的數(shù)據(jù)大小
- mData:binder_transaction_data數(shù)據(jù)的起始地址
- mObjectsSize:記錄flat_binder_object結(jié)構(gòu)體個數(shù)
- mObjects:記錄flat_binder_object結(jié)構(gòu)體的數(shù)據(jù)偏移量
ICPTHreadState::waitForResponse
上面的方法是把addService的請求信息寫到mOut中,下面是發(fā)送請求的部分實現(xiàn):
status_t IPCThreadState::waitForResponse(Parcel *reply, status_t *acquireResult)
{
int32_t cmd;
int32_t err;
while (1) {
if ((err=talkWithDriver()) < NO_ERROR) break;
...
if (mIn.dataAvail() == 0) continue;
cmd = mIn.readInt32();
switch (cmd) {
case BR_TRANSACTION_COMPLETE: ...
case BR_DEAD_REPLY: ...
case BR_FAILED_REPLY: ...
case BR_ACQUIRE_RESULT: ...
case BR_REPLY: ...
goto finish;
default:
err = executeCommand(cmd); //【見小節(jié)3.x】
if (err != NO_ERROR) goto finish;
break;
}
}
...
return err;
}
這個方法主要就是在發(fā)送請求,可以看到可根據(jù)命令去執(zhí)行相應(yīng)的內(nèi)容。這里的發(fā)送請求有沒有和binder設(shè)備進(jìn)行交互呢?有一個方法talkWithDriver()意面意思就是和driver通信,還有一個方法executeCommand()。下面來看看這個方法。
ICPTHreadState::talkWithDivier
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
...
binder_write_read bwr;
const bool needRead = mIn.dataPosition() >= mIn.dataSize();
const size_t outAvail = (!doReceive || needRead) ? mOut.dataSize() : 0;
bwr.write_size = outAvail;
bwr.write_buffer = (uintptr_t)mOut.data();
if (doReceive && needRead) {
//接收數(shù)據(jù)緩沖區(qū)信息的填充。如果以后收到數(shù)據(jù),就直接填在mIn中了。
bwr.read_size = mIn.dataCapacity();
bwr.read_buffer = (uintptr_t)mIn.data();
} else {
bwr.read_size = 0;
bwr.read_buffer = 0;
}
//當(dāng)讀緩沖和寫緩沖都為空,則直接返回
if ((bwr.write_size == 0) && (bwr.read_size == 0)) return NO_ERROR;
bwr.write_consumed = 0;
bwr.read_consumed = 0;
status_t err;
do {
//通過ioctl不停的讀寫操作,跟Binder Driver進(jìn)行通信
if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
err = NO_ERROR;
...
} while (err == -EINTR); //當(dāng)被中斷,則繼續(xù)執(zhí)行
...
return err;
}
看到這個方法我發(fā)現(xiàn)了三個很重要的信息,能夠幫助我們梳理和divier交互的中間過程:
- binder_write_read
這是用來和binder設(shè)備交換數(shù)據(jù)的結(jié)構(gòu)。這個結(jié)構(gòu)在看binder驅(qū)動底層讀寫數(shù)據(jù)的時候就出現(xiàn)過,當(dāng)時以為這個結(jié)構(gòu)是屬于內(nèi)核空間的。在這里發(fā)現(xiàn)這個數(shù)據(jù)結(jié)構(gòu)中有兩塊區(qū)域,一個是read_buffer,一個是write_buffer。BpBinder將從客戶端拿來的數(shù)據(jù)寫到這里。
- ioctl()
調(diào)用這個方法進(jìn)行讀寫操作,和binder driver通信。
總結(jié)
這里注冊服務(wù)主要分析的MediaService的服務(wù)注冊,主要流程是:
- 首先初始化ProcessState對象和BpServiceManager對象。同時也會獲得通信的BpBinder。
- 初始化MediaServicePlayer對象,并將這個服務(wù)通過BpServiceManager的業(yè)務(wù)層函數(shù)addService將要注冊的服務(wù)加入進(jìn)去。
- 此后BpServiceManager將請求的數(shù)據(jù)交給BpBinder處理。BpBinder調(diào)用transact方法,實則是交給了IPCTHreadState處理,也就是創(chuàng)建出了線程,線程也會創(chuàng)建自己本地存儲空間去完成Parcel數(shù)據(jù)包mOut和mIn的數(shù)據(jù)交換工作。
- IPCTHreadState調(diào)用transact方法處理事務(wù)。將數(shù)據(jù)存入binder_transaction_data結(jié)構(gòu)中,寫入到mOut中。
- 調(diào)用talkWidthDriver()方法,和Binder Driver通信,用binder_write_read結(jié)構(gòu)體和binder設(shè)備交換數(shù)據(jù)。
Binder Driver中的ServiceManager
從上面可以看到talkWithDriver開始和driver開始通信,調(diào)用了ioctl方法。
ioctl-->binder ioctl-->binder_ioctl_write_read
binder_ioctl_write_read
static int binder_ioctl_write_read(struct file *filp,
unsigned int cmd, unsigned long arg,
struct binder_thread *thread)
{
struct binder_proc *proc = filp->private_data;
void __user *ubuf = (void __user *)arg;
struct binder_write_read bwr;
//將用戶空間bwr結(jié)構(gòu)體拷貝到內(nèi)核空間
copy_from_user(&bwr, ubuf, sizeof(bwr));
...
if (bwr.write_size > 0) {
//將數(shù)據(jù)放入目標(biāo)進(jìn)程
ret = binder_thread_write(proc, thread,
bwr.write_buffer,
bwr.write_size,
&bwr.write_consumed);
...
}
if (bwr.read_size > 0) {
//讀取自己隊列的數(shù)據(jù)
ret = binder_thread_read(proc, thread, bwr.read_buffer,
bwr.read_size,
&bwr.read_consumed,
filp->f_flags & O_NONBLOCK);
if (!list_empty(&proc->todo))
wake_up_interruptible(&proc->wait);
...
}
//將內(nèi)核空間bwr結(jié)構(gòu)體拷貝到用戶空間
copy_to_user(ubuf, &bwr, sizeof(bwr));
...
}
這個方法很經(jīng)典,在注釋中已經(jīng)把它分為了三大塊。
- copy_from_user
將binder_write_read結(jié)構(gòu)體拷貝到用戶空間,這里面包含的是用戶地址空間的數(shù)據(jù),在我們最開始分析的時候就可以對接起來了。
- 兩個if
write_size中存在數(shù)據(jù)就寫入目標(biāo)進(jìn)程;read_size存在數(shù)據(jù)就從隊列中讀取進(jìn)程。
- copy_to_user
若處理失敗則需要將數(shù)據(jù)還原,在重新寫回到用戶地址空間。
binder_thread_write
static int binder_thread_write(struct binder_proc *proc,
struct binder_thread *thread,
binder_uintptr_t binder_buffer, size_t size,
binder_size_t *consumed)
{
uint32_t cmd;
void __user *buffer = (void __user *)(uintptr_t)binder_buffer;
void __user *ptr = buffer + *consumed;
void __user *end = buffer + size;
while (ptr < end && thread->return_error == BR_OK) {
//拷貝用戶空間的cmd命令,此時為BC_TRANSACTION
if (get_user(cmd, (uint32_t __user *)ptr)) -EFAULT;
ptr += sizeof(uint32_t);
switch (cmd) {
case BC_TRANSACTION:
case BC_REPLY: {
struct binder_transaction_data tr;
//拷貝用戶空間的binder_transaction_data
if (copy_from_user(&tr, ptr, sizeof(tr))) return -EFAULT;
ptr += sizeof(tr);
binder_transaction(proc, thread, &tr, cmd == BC_REPLY);
break;
}
...
}
*consumed = ptr - buffer;
}
return 0;
}
可以看到BC_TRANSACT命令和BC_REPLY命令執(zhí)行的方法是一樣的。調(diào)用binder_transaction方法。
binder_transaction
static void binder_transaction(struct binder_proc *proc,
struct binder_thread *thread,
struct binder_transaction_data *tr, int reply){
struct binder_transaction *t;
struct binder_work *tcomplete;
...
if (reply) {
...
}else {
if (tr->target.handle) {
...
} else {
// handle=0則找到servicemanager實體
target_node = binder_context_mgr_node;
}
//target_proc為servicemanager進(jìn)程
target_proc = target_node->proc;
}
if (target_thread) {
...
} else {
//找到servicemanager進(jìn)程的todo隊列
target_list = &target_proc->todo;
target_wait = &target_proc->wait;
}
t = kzalloc(sizeof(*t), GFP_KERNEL);
tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);
//非oneway的通信方式,把當(dāng)前thread保存到transaction的from字段
if (!reply && !(tr->flags & TF_ONE_WAY))
t->from = thread;
else
t->from = NULL;
t->sender_euid = task_euid(proc->tsk);
t->to_proc = target_proc; //此次通信目標(biāo)進(jìn)程為servicemanager進(jìn)程
t->to_thread = target_thread;
t->code = tr->code; //此次通信code = ADD_SERVICE_TRANSACTION
t->flags = tr->flags; // 此次通信flags = 0
t->priority = task_nice(current);
//從servicemanager進(jìn)程中分配buffer
t->buffer = binder_alloc_buf(target_proc, tr->data_size,
tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));
t->buffer->allow_user_free = 0;
t->buffer->transaction = t;
t->buffer->target_node = target_node;
if (target_node)
binder_inc_node(target_node, 1, 0, NULL); //引用計數(shù)加1
offp = (binder_size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));
//分別拷貝用戶空間的binder_transaction_data中ptr.buffer和ptr.offsets到內(nèi)核
copy_from_user(t->buffer->data,
(const void __user *)(uintptr_t)tr->data.ptr.buffer, tr->data_size);
copy_from_user(offp,
(const void __user *)(uintptr_t)tr->data.ptr.offsets, tr->offsets_size);
off_end = (void *)offp + tr->offsets_size;
for (; offp < off_end; offp++) {
struct flat_binder_object *fp;
fp = (struct flat_binder_object *)(t->buffer->data + *offp);
off_min = *offp + sizeof(struct flat_binder_object);
switch (fp->type) {
case BINDER_TYPE_BINDER:
case BINDER_TYPE_WEAK_BINDER: {
struct binder_ref *ref;
struct binder_node *node = binder_get_node(proc, fp->binder);
if (node == NULL) {
//服務(wù)所在進(jìn)程 創(chuàng)建binder_node實體【見4.3.2】
node = binder_new_node(proc, fp->binder, fp->cookie);
...
}
//servicemanager進(jìn)程binder_ref
ref = binder_get_ref_for_node(target_proc, node);
...
//調(diào)整type為HANDLE類型
if (fp->type == BINDER_TYPE_BINDER)
fp->type = BINDER_TYPE_HANDLE;
else
fp->type = BINDER_TYPE_WEAK_HANDLE;
fp->binder = 0;
fp->handle = ref->desc; //設(shè)置handle值
fp->cookie = 0;
binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
&thread->todo);
} break;
case :...
}
if (reply) {
..
} else if (!(t->flags & TF_ONE_WAY)) {
//BC_TRANSACTION 且 非oneway,則設(shè)置事務(wù)棧信息
t->need_reply = 1;
t->from_parent = thread->transaction_stack;
thread->transaction_stack = t;
} else {
...
}
//將BINDER_WORK_TRANSACTION添加到目標(biāo)隊列,本次通信的目標(biāo)隊列為target_proc->todo
t->work.type = BINDER_WORK_TRANSACTION;
list_add_tail(&t->work.entry, target_list);
//將BINDER_WORK_TRANSACTION_COMPLETE添加到當(dāng)前線程的todo隊列
tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
list_add_tail(&tcomplete->entry, &thread->todo);
//喚醒等待隊列,本次通信的目標(biāo)隊列為target_proc->wait
if (target_wait)
wake_up_interruptible(target_wait);
return;
}
這個方法主要就是在binder驅(qū)動中執(zhí)行任務(wù)。它有兩個參數(shù)我們應(yīng)該都比較熟悉。
- binder_proc:這是在binder_open的時候創(chuàng)建的binder的一個數(shù)據(jù)類型,里面存放著binder的一些信息
- binder_transaction_data:這個在IPCthreadState的方法中見過,也是一種數(shù)據(jù)類型,存放了客戶端傳來的數(shù)據(jù)信息。
再梳理下這個方法的主要流程:
- target_node = binder_context_mgr_data找到ServiceManager實體
- 設(shè)置ServiceManager進(jìn)程:target_proc
- 找到ServiceManager進(jìn)程的todo隊列和等待隊列
- 為binder_transaction結(jié)構(gòu)賦值:
- t->from = thread(傳進(jìn)來的binder_thread)
- t->to_proc = target_proc(通信目標(biāo)進(jìn)程為ServiceManager進(jìn)程)
- t->buffer = binder_alloc_buf()(ServiceManager進(jìn)程中分配buffer)
- 拷貝用戶空間binder_transaction_data中的buffer和offsets到內(nèi)核
- 在服務(wù)所在進(jìn)程創(chuàng)建binder_node實體,ServiceManager進(jìn)程創(chuàng)建binder_ref
- 向ServiceManager的binder_proc->todo添加BINDER_WORK_TRANSACTION事務(wù)
這是binder底層驅(qū)動執(zhí)行事務(wù)的一系列過程
do_add_service
看完底層servicemanager進(jìn)程是如何與binder driver進(jìn)行通信的,再看看注冊服務(wù)時的方法。這個方法是在分析ServiceManager啟動的時候見過的。binder_loop-->binder_parse-->svcmgr_handler。
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;
//權(quán)限檢查
if (!svc_can_register(s, len, spid)) {
return -1;
}
//服務(wù)檢索
si = find_svc(s, len);
if (si) {
if (si->handle) {
svcinfo_death(bs, si); //服務(wù)已注冊時,釋放相應(yīng)的服務(wù)
}
si->handle = handle;
} else {
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) { //內(nèi)存不足,無法分配足夠內(nèi)存
return -1;
}
si->handle = handle;
si->len = len;
memcpy(si->name, s, (len + 1) * sizeof(uint16_t)); //內(nèi)存拷貝服務(wù)信息
si->name[len] = '\0';
si->death.func = (void*) svcinfo_death;
si->death.ptr = si;
si->allow_isolated = allow_isolated;
si->next = svclist; // svclist保存所有已注冊的服務(wù)
svclist = si;
}
//以BC_ACQUIRE命令,handle為目標(biāo)的信息,通過ioctl發(fā)送給binder驅(qū)動
binder_acquire(bs, handle);
//以BC_REQUEST_DEATH_NOTIFICATION命令的信息,通過ioctl發(fā)送給binder驅(qū)動,主要用于清理內(nèi)存等收尾工作。
binder_link_to_death(bs, handle, &si->death);
return 0;
}
這里先做權(quán)限檢查,再進(jìn)行服務(wù)檢索,如果服務(wù)的名稱有一樣的就釋放源服務(wù)添加新服務(wù)。將服務(wù)保存到svclist中。服務(wù)注冊成功會調(diào)用binder_send_reply方法通過binder_write向binder驅(qū)動通信。
總結(jié)
在看這注冊服務(wù)的時候我有點懵,原因在于native層注冊服務(wù)后又跑到了binder驅(qū)動層。其實這是一個連帶的過程,主要就是要將ServiceManager所在進(jìn)程和binder進(jìn)程聯(lián)系在一起。
這里在梳理下全部流程:
- MediaPlayerService進(jìn)程調(diào)用ioctl向binder發(fā)送數(shù)據(jù)。該過程為一個事務(wù)binder_transaction,執(zhí)行當(dāng)前操作的線程為binder_thread(thread1)。IPC數(shù)據(jù)內(nèi)容包括:
- binder協(xié)議BC_TRANSACTION
- handle為0
- RPC代碼為ADD_SERVICE
- RPC數(shù)據(jù)為”nedia.player“
- binder驅(qū)動收到該請求,生成BR_TRANSACTION命令,選擇目標(biāo)處理該請求的線程,即ServiceManager的binder_thread(thread2)。將整個binder_transaction數(shù)據(jù)插入到目標(biāo)線程的TODO隊列
- thread2線程收到任務(wù)后,將服務(wù)“media player”注冊到服務(wù)目錄中。注冊完成后,生成IPC應(yīng)答數(shù)據(jù)BC_REPLY
- binder驅(qū)動收到該binder應(yīng)答請求,生成BR_REPLY命令。在MediaPlayerService接收到命令后,知道服務(wù)注冊完成就可以正常使用了。
獲取服務(wù)
獲取服務(wù)還是從MediaServicePlayer的獲取服務(wù)方法來看。
getMediaPlayerService
sp<IMediaPlayerService>&
IMediaDeathNotifier::getMediaPlayerService()
{
Mutex::Autolock _l(sServiceLock);
if (sMediaPlayerService == 0) {
sp<IServiceManager> sm = defaultServiceManager(); //獲取ServiceManager
sp<IBinder> binder;
do {
//獲取名為"media.player"的服務(wù)
binder = sm->getService(String16("media.player"));
if (binder != 0) {
break;
}
usleep(500000); // 0.5s
} while (true);
if (sDeathNotifier == NULL) {
sDeathNotifier = new DeathNotifier(); //創(chuàng)建死亡通知對象
}
//將死亡通知連接到binder
binder->linkToDeath(sDeathNotifier);
sMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
return sMediaPlayerService;
}
這里在獲取服務(wù)的過程中,仍采用不斷循環(huán)的方法。
BpSM.getService
virtual sp<IBinder> getService(const String16& name) const
{
unsigned n;
//循環(huán)5次,大概和android ANR時間為5s相關(guān)
for (n = 0; n < 5; n++){
sp<IBinder> svc = checkService(name); //【見2.3】
if (svc != NULL) return svc;
sleep(1);
}
return NULL;
}
BpSM.checkService
virtual sp<IBinder> checkService( const String16& name) const
{
Parcel data, reply;
//寫入RPC頭
data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
//寫入服務(wù)名
data.writeString16(name);
remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
return reply.readStrongBinder();
}
檢索指定服務(wù)是否存在
在這之后又調(diào)用了和請求服務(wù)一樣的程序。
總結(jié)
獲取服務(wù)過程,就是向ServiceManager進(jìn)行查詢指定服務(wù),當(dāng)執(zhí)行binder_transaction()時,會區(qū)分獲取服務(wù)所屬進(jìn)程的情況。