Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android Binder進程間通信---Service代理對象的獲取過程

Android Binder進程間通信---Service代理對象的獲取過程

編輯:關於Android編程

本文參考《Android系統源代碼情景分析》,作者羅升陽

一、測試代碼:

~/Android/external/binder/server

----FregServer.cpp

~/Android/external/binder/common

----IFregService.cpp

----IFregService.h

~/Android/external/binder/client

----FregClient.cpp


Binder庫(libbinder)代碼:

~/Android/frameworks/base/libs/binder

----BpBinder.cpp

----Parcel.cpp

----ProcessState.cpp

----Binder.cpp

----IInterface.cpp

----IPCThreadState.cpp

----IServiceManager.cpp

----Static.cpp

~/Android/frameworks/base/include/binder

----Binder.h

----BpBinder.h

----IInterface.h

----IPCThreadState.h

----IServiceManager.h

----IBinder.h

----Parcel.h

----ProcessState.h


驅動層代碼:

~/Android//kernel/goldfish/drivers/staging/android

----binder.c

----binder.h

Service Manager代碼:

~/Android/frameworks/base/cmd/servicemanager ----binder.c ----service_manager.c ----binder.h


二、源碼分析

~/Android/external/binder/client

----FregClient.cpp

int main()
{
	sp binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
	if(binder == NULL) {
		LOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
		return -1;
	}

	sp service = IFregService::asInterface(binder);
	if(service == NULL) {
		LOGE("Failed to get freg service interface.\n");
		return -2;
	}
        ............
}
首先調用Binder庫提供的函數defaultServiceManager在FregClient進程中獲得一個Service Manager代理對象,接著再調用它的成員函數getService來獲得一個名稱為FREG_SERVICE的Service組件的代理對象,類型為BpBinder。然後再需要通過IFregService類的靜態成員函數asInterface將它封裝成一個BpFregService類型的代理對象。

我們首先分析下Service Manager代理對象的成員函數getService實現如下:

~/Android/external/binder/client

----IServiceManager.cpp

class BpServiceManager : public BpInterface
{
public:
    .........
    virtual sp getService(const String16& name) const
    {
        unsigned n;
        for (n = 0; n < 5; n++){
            sp svc = checkService(name);
            if (svc != NULL) return svc;
            LOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }
    ...........
};
這個函數最多會嘗試5次來獲得一個名稱為name的Service組件的代理對象。如果上一次獲得失敗,那麼就調用sleep使得當前線程睡眠1毫秒,然後再重新去獲取,否則就直接將獲得的Service組件的代理對象返回給調用者。

調用checkService來獲得一個名稱為name的Service組件的代理對象。實現如下:

~/Android/external/binder/client

----IServiceManager.cpp

class BpServiceManager : public BpInterface
{
public:
    ........
    virtual sp checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//android.os.IServiceManager
        data.writeString16(name);//shy.luo.FregService
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);//remote為BpBinder對象
        return reply.readStrongBinder();
    }
    .........
};

函數以後的執行流程,和以下兩篇文章相類似,只是一個是ADD_SERVICE_TRANSACTION,一個是CHECK_SERVICE_TRANSACTION。

首先是Android Binder進程間通信---注冊Service組件---Client發送BC_TRANSACTIONhttp://blog.csdn.net/jltxgcy/article/details/26076149。

然後Android Binder進程間通信---注冊Service組件---Server處理BC_TRANSACTIONhttp://blog.csdn.net/jltxgcy/article/details/26151113。

隨著執行的深入,執行到第二篇文章的svcmgr_handler方法,出現了不同的執行過程。實現如下:

~/Android/frameworks/base/cmd/servicemanager ----service_manager.c
int svcmgr_handler(struct binder_state *bs,
                   struct binder_txn *txn,
                   struct binder_io *msg,
                   struct binder_io *reply)
{
    struct svcinfo *si;
    uint16_t *s;
    unsigned len;
    void *ptr;
    uint32_t strict_policy;

    ..........

    if (txn->target != svcmgr_handle)
        return -1;

    .........
    strict_policy = bio_get_uint32(msg);//strict_policy為STRICT_MODE_PENALTY_GATHER
    s = bio_get_string16(msg, &len);//s為android.os.IServiceManager
    if ((len != (sizeof(svcmgr_id) / 2)) ||
        memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {//比較是否一致,如果不一致,直接返回出錯
        fprintf(stderr,"invalid id %s\n", str8(s));
        return -1;
    }

    switch(txn->code) {//CHECK_SERVICE_TRANSACTION,即SVC_MGR_CHECK_SERVICE
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);//s為shy.luo.FregService,len為它的長度
        ptr = do_find_service(bs, s, len);//一個引用了注冊到Service Manager中Service組件的Binder引用對象的句柄值
        if (!ptr)
            break;
        bio_put_ref(reply, ptr);//將前面獲得的一個句柄值封裝成一個binder_object結構體,並且寫入到binder_io結構體reply中
        return 0;
    .........
    }
    .........
}
調用do_find_service在已注冊Service組件列表svclist中查找與它對應的一個svcinfo結構體,實現如下:

~/Android/frameworks/base/cmd/servicemanager ----service_manager.c
void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
{
    struct svcinfo *si;
    si = find_svc(s, len);//s為shy.luo.FregService,len為它的長度

//    LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
    if (si && si->ptr) {
        return si->ptr;//返回一個引用了注冊到Service Manager中Service組件的Binder引用對象的句柄值
    } else {
        return 0;
    }
}
首先調用find_svc來查找與字符串s對應的一個svcinfo結構體si。我們已經分析過函數find_svc的實現了,它通過遍歷已注冊Service組件列表svclist來查找與字符串s對應的一個svcinfo結構體。如果找到了與字符串對應的svcinfo結構體si,並且它的成員變量ptr的值不為0,那麼就將它的成員變量ptr的值返回給調用者。

結構體svcinfo的成員變量ptr保存的一個引用了注冊到Service Manager中Service組件的Binder引用對象的句柄值。當Service Manager將這個句柄值返回給Binder驅動程序時,Binder驅動程序就可以根據它找到相應的Binder引用對象,接著找到該Binder引用對象所引用Binder實體對象。

返回svcmgr_handler,繼續執行bio_put_ref函數,將前面獲得的一個句柄值封裝成一個binder_object結構體,並且寫入到binder_io結構體reply中,實現如下:

~/Android/frameworks/base/cmd/servicemanager

----binder.c

void bio_put_ref(struct binder_io *bio, void *ptr)//bio為reply,ptr為句柄值
{
    struct binder_object *obj;

    if (ptr)//不為NULL
        obj = bio_alloc_obj(bio);//分配了binder_object結構體,而不是binder_io,binder_io以前已經分配過了
    else
        obj = bio_alloc(bio, sizeof(*obj));

    if (!obj)
        return;

    obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    obj->type = BINDER_TYPE_HANDLE;
    obj->pointer = ptr;
    obj->cookie = 0;
}
由於傳進來的參數ptr的值不等於0,因此調用bio_alloc_obj在binder_io結構體bio的數據緩沖區中分配一個binder_object結構體obj。實現如下:

~/Android/frameworks/base/cmd/servicemanager

----binder.c

static struct binder_object *bio_alloc_obj(struct binder_io *bio)//bio為reply
{
    struct binder_object *obj;

    obj = bio_alloc(bio, sizeof(*obj));//在binder_io結構體bio的數據緩沖區中分配一個binder_object結構體obj
    
    if (obj && bio->offs_avail) {
        bio->offs_avail--;//偏移數組大小減1
        *bio->offs++ = ((char*) obj) - ((char*) bio->data0);//偏移數組內容指向剛才的binder_object結構體obj
        return obj;
    }

    bio->flags |= BIO_F_OVERFLOW;
    return 0;
}

~/Android/frameworks/base/cmd/servicemanager

----binder.c

static void *bio_alloc(struct binder_io *bio, uint32_t size)
{
    size = (size + 3) & (~3);
    if (size > bio->data_avail) {
        bio->flags |= BIO_F_OVERFLOW;
        return 0;
    } else {
        void *ptr = bio->data;//開始位置
        bio->data += size;//分配完binder_object後的位置
        bio->data_avail -= size;//可用數據要減少size
        return ptr;
    }
}
回到svcmgr_handler中,現在要返回給Binder驅動程序的進程間通信結果數據保存在binder_io結構體reply中了。接著又返回函數binder_parse中,最後調用函數binder_send_reply將binder_io結構體reply的內容返回給Binder驅動程序。

在這篇Android Binder進程間通信---注冊Service組件---發送和處理BC_REPLY命令協議http://blog.csdn.net/jltxgcy/article/details/26216521文章中,我們已經分析了binder_send_reply函數,省去了 很多步驟,執行到binder_transaction函數。

~/Android//kernel/goldfish/drivers/staging/android

----binder.c

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;
	......
	struct binder_proc *target_proc;
	struct binder_thread *target_thread = NULL;
	struct binder_node *target_node = NULL;
	struct list_head *target_list;
	wait_queue_head_t *target_wait;
	struct binder_transaction *in_reply_to = NULL;
	........
	uint32_t return_error;

	........

	if (reply) {
		in_reply_to = thread->transaction_stack;//首先從線程thread的事務堆棧中將該binder_transaction結構體取出來,並且保存在變量in_reply_to中
		if (in_reply_to == NULL) {
			......
			return_error = BR_FAILED_REPLY;
			goto err_empty_call_stack;
		}
		binder_set_nice(in_reply_to->saved_priority);
		if (in_reply_to->to_thread != thread) {
			........
			return_error = BR_FAILED_REPLY;
			in_reply_to = NULL;
			goto err_bad_call_stack;
		}
		thread->transaction_stack = in_reply_to->to_parent;
		target_thread = in_reply_to->from;//目標線程
		if (target_thread == NULL) {
			return_error = BR_DEAD_REPLY;
			goto err_dead_binder;
		}
		if (target_thread->transaction_stack != in_reply_to) {
			.........
			return_error = BR_FAILED_REPLY;
			in_reply_to = NULL;
			target_thread = NULL;
			goto err_dead_binder;
		}
		target_proc = target_thread->proc;//找到了目標進程
	} else {
		........
	}
	if (target_thread) {
		.........
		target_list = &target_thread->todo;//分別將它的todo隊列和wait等待隊列作為目標todo隊列target_list和目標wait等待隊列target_wait
		target_wait = &target_thread->wait;//分別將它的todo隊列和wait等待隊列作為目標todo隊列target_list和目標wait等待隊列target_wait
	} else {
		.........
	}
	.........

	/* TODO: reuse incoming transaction for reply */
	t = kzalloc(sizeof(*t), GFP_KERNEL);//分配了binder_transaction結構體
	........

	tcomplete = kzalloc(sizeof(*tcomplete), GFP_KERNEL);//分配了binder_work結構體
	if (tcomplete == NULL) {
		return_error = BR_FAILED_REPLY;
		goto err_alloc_tcomplete_failed;
	}
	.......

	if (!reply && !(tr->flags & TF_ONE_WAY))
		t->from = thread;//service_manager的主線程
	else
		t->from = NULL;
	t->sender_euid = proc->tsk->cred->euid;//service_manager進程號
	t->to_proc = target_proc;//目標進程
	t->to_thread = target_thread;//目標線程
	t->code = tr->code;//0
	t->flags = tr->flags;//0
	t->priority = task_nice(current);
	t->buffer = binder_alloc_buf(target_proc, tr->data_size,
		tr->offsets_size, !reply && (t->flags & TF_ONE_WAY));//分配了binder_buffer結構體
	if (t->buffer == NULL) {
		return_error = BR_FAILED_REPLY;
		goto err_binder_alloc_buf_failed;
	}
	t->buffer->allow_user_free = 0;//不允許釋放
	.......
	t->buffer->transaction = t;
	t->buffer->target_node = target_node;//NULL
	if (target_node)
		binder_inc_node(target_node, 1, 0, NULL);//增加目標Binder實體對象的強引用計數

	offp = (size_t *)(t->buffer->data + ALIGN(tr->data_size, sizeof(void *)));//偏移數組在data中起始位置,位於數據緩沖區之後

	if (copy_from_user(t->buffer->data, tr->data.ptr.buffer, tr->data_size)) {//數據緩沖區拷貝到data中
		binder_user_error("binder: %d:%d got transaction with invalid "
			"data ptr\n", proc->pid, thread->pid);
		return_error = BR_FAILED_REPLY;
		goto err_copy_data_failed;
	}
	if (copy_from_user(offp, tr->data.ptr.offsets, tr->offsets_size)) {//偏移數組拷貝到data中,偏移數組位於數據緩沖區之後
		binder_user_error("binder: %d:%d got transaction with invalid "
			"offsets ptr\n", proc->pid, thread->pid);
		return_error = BR_FAILED_REPLY;
		goto err_copy_data_failed;
	}
	...........
	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);
		switch (fp->type) {
		......
		case BINDER_TYPE_HANDLE:
		case BINDER_TYPE_WEAK_HANDLE: {
			struct binder_ref *ref = binder_get_ref(proc, fp->handle);
			.......
			if (ref->node->proc == target_proc) {//FregService進程和FregClient進程不相等
				.......
			} else {
				struct binder_ref *new_ref;
				new_ref = binder_get_ref_for_node(target_proc, ref->node);//為FregClient進程創建一個引用了Service組件FregService的Binder引用對象
				.........
				fp->handle = new_ref->desc;//新的引用對象的句柄賦值給handle
				binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
				........
			}
		} break;
                .......
	}
	if (reply) {
		BUG_ON(t->buffer->async_transaction != 0);
		binder_pop_transaction(target_thread, in_reply_to);//TODO
	} else if (!(t->flags & TF_ONE_WAY)) {
		.........
	} else {
		.........
	}
	t->work.type = BINDER_WORK_TRANSACTION;
	list_add_tail(&t->work.entry, target_list);//加入到目標線程的todo
	tcomplete->type = BINDER_WORK_TRANSACTION_COMPLETE;
	list_add_tail(&tcomplete->entry, &thread->todo);//加入到本線程的todo
	if (target_wait)
		wake_up_interruptible(target_wait);//喚醒目標線程
	return;
}
我們只分析for循環裡面的內容,因為其他內容在Android Binder進程間通信---注冊Service組件---發送和處理BC_REPLY命令協議http://blog.csdn.net/jltxgcy/article/details/26216521一文中,已經介紹過了。

binder_get_ref函數根據flat_binder_object結構體fp的句柄值在當前進程中找到了對應的Binder引用對象ref。由於FregService進程和FregClient進程不相等,執行else部分代碼。調用函數binder_get_ref_for_node在FregClient進程中查找是否已經存在一個Binder引用計數,它引用了Binder實體對象ref->node,即引用了Service組件FregService。如果不存在,那麼函數binder_get_ref_for_node就會為FregClient進程創建一個引用了Service組件FregService的Binder引用對象,並且返回給調用者。

我們假設首先執行的還是本線程,參考Android Binder進程間通信---注冊Service組件---發送和處理BC_REPLY命令協議http://blog.csdn.net/jltxgcy/article/details/26216521,Service Manger進程又一次睡眠等待直到其所屬的進程有新的未處理項為止,停留在下面的代碼:

wait_event_interruptible_exclusive(proc->wait, binder_has_proc_work(proc, thread));//睡眠等待直到其所屬的進程有新的未處理項為止

然後我們喚醒目標線程,即Android Binder進程間通信---注冊Service組件---Client發送BC_TRANSACTIONhttp://blog.csdn.net/jltxgcy/article/details/26076149一文中最後睡眠等待的線程(我們就借用FregService的用了,因為FregClient和FregService在流程上是一致的) , 當這個目標線程target_thread被喚醒之後,它就會繼續執行Binder驅動程序中的函數binder_thread_read,參考Android Binder進程間通信---注冊Service組件---發送和處理BC_REPLY返回協議http://blog.csdn.net/jltxgcy/article/details/26339313和Android Binder進程間通信---注冊Service組件---啟動Binder線程池http://blog.csdn.net/jltxgcy/article/details/26354311,我們最後返回到Service Manager代理對象的成員函數checkService中。

實現如下:

~/Android/external/binder/client

----IServiceManager.cpp

class BpServiceManager : public BpInterface
{
public:
    ........
    virtual sp checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());//android.os.IServiceManager
        data.writeString16(name);//shy.luo.FregService
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);//remote為BpBinder對象
        return reply.readStrongBinder();//來獲得一個Binder代理對象
    }
    .........
};
返回後調用Parcel對象reply的成員函數readStrongBinder來獲得一個Binder代理對象。實現如下:

~/Android/frameworks/base/libs/binder

----Parcel.cpp

sp Parcel::readStrongBinder() const
{
    sp val;
    unflatten_binder(ProcessState::self(), *this, &val);//來獲得這個flat_binder_object結構體
    return val;
}
調用unflatten_binder函數,實現如下:

status_t unflatten_binder(const sp& proc,
    const Parcel& in, sp* out)
{
    const flat_binder_object* flat = in.readObject(false);//in就是reply
    
    if (flat) {
        switch (flat->type) {
            .........
            case BINDER_TYPE_HANDLE:
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}
從前面的調用過程可以知道,Parcel對象reply內部的數據緩沖區保存了Binder驅動程序返回給當前線程的進程間通信結果數據,即它裡面包含了一個類型為BINDER_TYPE_HANDLE的flat_binder_object結構體,因此我們調用函數unflatten_binder來獲得這個flat_binder_object結構體。
從Parcel對象in獲得的flat_binder_object結構體flat的類型為BINDER_TYPE_HANDLE,因此調用當前進程的ProcessState對象proc的成員函數getStrongProxyForHandle來查找一個與它的句柄值相對應的Binder代理對象,即一個BpBinder對象。由於flat_binder_object結構體flat的句柄值handle是一個引用了Service組件FregService的Binder引用對象句柄值,因此getStrongProxyForHandle返回來的Binder代理對象也是引用了Service組件FregService的。

執行完checkSevice,返回main函數。實現如下:

~/Android/external/binder/client

----FregClient.cpp

int main()
{
	sp binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
	if(binder == NULL) {
		LOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
		return -1;
	}

	sp service = IFregService::asInterface(binder);
	if(service == NULL) {
		LOGE("Failed to get freg service interface.\n");
		return -2;
	}
        ............
}
IFregService類的靜態成員函數asInterface是通過宏IMPLEMENT_META_INTERFACE來定義的,它的實現如下:

android::sp IFregService::asInterface(const android::sp& obj)                                              
{                                                                                     
	android::sp intr;                                                    
	
	if (obj != NULL) {                                                                     
		intr = static_cast(                                                  
                    obj->queryLocalInterface(IFregService::descriptor).get());//返回NULL
		
		if (intr == NULL) {                
			intr = new BpServiceManager(obj);  //創建了Service Manager代理對象                                      
		}                                          
	}
	return intr;                                  
}   
參數obj指向的是前面獲得的一個Binder代理對象,即一個BpBinder對象。然後將這個Binder代理對象封裝成一個BpFregService類型的Binder代理對象,並且將它的IFregService接口返回給調用者。

至此,FregClient進程就成功地通過Service Manager獲得一個運行在FregServer進程中的Service組件FregService的代理對象。有了這個代理對象之後,FregClient進程就可以向Service組件FregService發送進程間通信請求了,即可以使用它提供的服務了。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved