码迷,mamicode.com
首页 > 移动开发 > 详细

Android Binder进程间通信---Service代理对象的获取过程

时间:2014-05-21 08:36:38      阅读:536      评论:0      收藏:0      [点我收藏+]

标签:des   android   style   blog   class   c   

本文参考《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<IBinder> binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
	if(binder == NULL) {
		LOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
		return -1;
	}

	sp<IFregService> 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<IServiceManager>
{
public:
    .........
    virtual sp<IBinder> getService(const String16& name) const
    {
        unsigned n;
        for (n = 0; n < 5; n++){
            sp<IBinder> 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<IServiceManager>
{
public:
    ........
    virtual sp<IBinder> 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<IServiceManager>
{
public:
    ........
    virtual sp<IBinder> 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<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);//来获得这个flat_binder_object结构体
    return val;
}
     调用unflatten_binder函数,实现如下:

status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* 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<BpBinder*>(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<IBinder> binder = defaultServiceManager()->getService(String16(FREG_SERVICE));
	if(binder == NULL) {
		LOGE("Failed to get freg service: %s.\n", FREG_SERVICE);
		return -1;
	}

	sp<IFregService> 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> IFregService::asInterface(const android::sp<android::IBinder>& obj)                                              
{                                                                                     
	android::sp<IFregService> intr;                                                    
	
	if (obj != NULL) {                                                                     
		intr = static_cast<IFregService*>(                                                  
                    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发送进程间通信请求了,即可以使用它提供的服务了。

Android Binder进程间通信---Service代理对象的获取过程,布布扣,bubuko.com

Android Binder进程间通信---Service代理对象的获取过程

标签:des   android   style   blog   class   c   

原文地址:http://blog.csdn.net/jltxgcy/article/details/26370733

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!