您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
创建一个BpFregService类型的代理对象
 
作者 jltxgcy的博客,火龙果软件    发布于 2014-07-24
   次浏览      
 

一、测试代码:

~/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

二、源码分析

1、FregClient进程,获取ServiceManager代理对象。参考FregServer进程,获取ServiceManager代理对象

~/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类型的代理对象。

2、FregClient进程,封装进程间通信数据。参考FregServer进程,封装进程间通信数据http://blog.csdn.net/jltxgcy/article/details/26059215。

我们首先分析下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();
}
.........
};

3、 FregClient进程,发送BC_TRANSACTION,睡觉等待。参考FregServer进程,发送BC_TRANSACTION,睡眠等待http://blog.csdn.net/jltxgcy/article/details/26076149。

函数以后的执行流程,和以下两篇文章相类似,只是一个是ADD_SERVICE_TRANSACTION,一个是CHECK_SERVICE_TRANSACTION。

4、Service Manager进程,处理BC_TRANSACTION,返回BR_TRANSACTION。参考Service Manager进程,处理BC_TRANSACTION,返回BR_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进程的引用对象(引用了FregServer进程的实体对象)的句柄值
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驱动程序。

5、Service Manager进程,发送BC_REPLY,睡眠等待。参考Service Manager进程,发送BC_REPLY,睡眠等待http://blog.csdn.net/jltxgcy/article/details/26216521。

随着执行的深入,binder_transaction方法,出现了不同的执行过程。实现如下:

<!DOCTYPE HTML>

----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); //Service Manager进程的引用对象(引用了FregServer进程的实体对象)
.......
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进程的引用对象(引用了FregServer进程的实体对象)
.........
fp->handle = new_ref->desc;//FregClient进程的引用对象句柄赋值给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;
}

要传递的binder_transaction结构体,传递的flat_binder_object的各个成员如下:

flags为0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS,type为BINDER_TYPE_HANDLE,handle为FregClient进程的引用对象(引用了FregServer进程的实体对象)句柄值,cookie为0。

6、FregClient进程,处理BC_REPLY,返回BR_REPLY。参考FregServer进程,处理BC_REPLY,返回BR_REPLYhttp://blog.csdn.net/jltxgcy/article/details/26339313。

7、FregClient进程,返回到checkService中,创建FregClient进程的代理对象,最后创建一个BpFregService类型的代理对象。参考Android Binder进程间通信---FregServer进程,启动Binder线程池http://blog.csdn.net/jltxgcy/article/details/26354311。

实现如下:

~/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();//FregClient进程的代理对象
}
.........
};

返回后调用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 BAD_TYPE;
}

调用getStrongProxyForHandle实现如下:

sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
{
sp<IBinder> result;
AutoMutex _l(mLock);
handle_entry* e = lookupHandleLocked(handle); //检查成员变量mHandleToObject是否已经存在一个与句柄值handle对应的handle_entry结构体
if (e != NULL) {
// We need to create a new BpBinder if there isn't currently one, OR we
// are unable to acquire a weak reference on this current one. See comment
// in getWeakProxyForHandle() for more info about this.
IBinder* b = e->binder;
if (b == NULL || !e->refs->attemptIncWeak(this)) { //如果进程尚未为句柄值handle创建过Binder代理对象,或者创建了Binder代理对象但已经销毁了
b = new BpBinder(handle); //Binder代理对象,handle为1
e->binder = b;//保存再e的成员变量binder中
if (b) e->refs = b->getWeakRefs();//将弱引用计数对象保存在e的成员变量refs中
result = b;//返回结果
} else {//如果进程已经创建了Binder代理对象,并且没有销毁,那么直接返回
// This little bit of nastyness is to allow us to add a primary
// reference to the remote proxy when this team doesn't have one
// but another team is sending the handle to us.
result.force_set(b);//设置返回结果result
e->refs->decWeak(this);//减少弱引用计数,因为attemptIncWeak增加了弱引用计数
}
}
return result;
}

创建FregClient进程的代理对象。

执行完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 BpFregService(obj); //创建了BpFregService类型的代理对象
}

return intr;
}

参数obj指向的是前面获得的一个Binder代理对象,即一个BpBinder对象。然后将这个Binder代理对象封装成一个BpFregService类型的代理对象,并且将它的IFregService接口返回给调用者。

三、目前存在的各种对象

Service Manager进程的本地对象;

Service Manager进程的实体对象;

FregServer进程的引用对象(引用了Service Manager进程的实体对象);

FregServer进程的代理对象。

FregServer进程的本地对象;

FregServer进程的实体对象;

Service Manager进程的引用对象(引用了FregServer进程的实体对象);

FregClient进程的引用对象(引用了FregServer进程的实体对象);

FregClient进程的代理对象;

BpFregService类型的代理对象(成员函数remote()可以获取FregClient进程的代理对象);

   
次浏览       
 
相关文章

手机软件测试用例设计实践
手机客户端UI测试分析
iPhone消息推送机制实现与探讨
Android手机开发(一)
 
相关文档

Android_UI官方设计教程
手机开发平台介绍
android拍照及上传功能
Android讲义智能手机开发
相关课程

Android高级移动应用程序
Android系统开发
Android应用开发
手机软件测试
最新活动计划
软件架构设计方法、案例与实践 8-23[特惠]
Linux内核编程及设备驱动 8-15[北京]
Python、数据分析与机器学习 8-23[特惠]
嵌入式软件架构设计 8-22[线上]
QT应用开发 9-5[北京]

android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...