Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1495750
  • 博文数量: 267
  • 博客积分: 3010
  • 博客等级: 少校
  • 技术积分: 3089
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-05 17:09
个人简介

尊天命,尽人事

文章分类

全部博文(267)

文章存档

2017年(6)

2015年(4)

2014年(27)

2013年(52)

2012年(59)

2011年(120)

分类: Android平台

2013-05-03 11:11:44

匿名binder就是没有向servicemanager提交注册的binder。

对于已经建立好Binder通信的Client和server,server可以将一个Binder的引用传递给client,client可以通过这个引用来访问server。


那么这种匿名的访问是怎么建立起来的?在server被唤醒后为什么可以通过target-ptr找到bbinder呢?

答案就在第一次返回这个Binder的引用的时候,binder驱动保存了这个Binder实体的各种数据,创建了节点。

以surfaceflinger调用createConnection返回IsurfaceComposerClient为例:

  1. status_t BnSurfaceComposer::onTransact(  
  2.     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)  
  3. {  
  4.     switch(code) {  
  5.         case CREATE_CONNECTION: {  
  6.             CHECK_INTERFACE(ISurfaceComposer, data, reply);  
  7.             sp b = createConnection()->asBinder();  
  8.             reply->writeStrongBinder(b);//关键  
  9.   
  10. //...  
  11. }  
实际就是往reply中存入了一个BBinder实体。

我们进一步看下,parcel.cpp:

  1. status_t Parcel::writeStrongBinder(const sp& val)  
  2. {  
  3.     return flatten_binder(ProcessState::self(), val, this);  
  4. }  
也就是:

  1. status_t flatten_binder(const sp& proc,  
  2.     const sp& binder, Parcel* out)  
  3. {  
  4.     flat_binder_object obj;  
  5.       
  6.     obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;  
  7.     if (binder != NULL) {  
  8.         IBinder *local = binder->localBinder();//这里我们是由Client强转得到的,所以这里不是空,返回BBinder  
  9.         if (!local) {  
  10.             BpBinder *proxy = binder->remoteBinder();  
  11.             if (proxy == NULL) {  
  12.                 LOGE("null proxy");  
  13.             }  
  14.             const int32_t handle = proxy ? proxy->handle() : 0;  
  15.             obj.type = BINDER_TYPE_HANDLE;  
  16.             obj.handle = handle;  
  17.             obj.cookie = NULL;  
  18.         } else {  
  19.             obj.type = BINDER_TYPE_BINDER;//关键,表示当前传入的类型,并将对象本身作为cookie传入。  
  20.             obj.binder = local->getWeakRefs();  
  21.             obj.cookie = local;  
  22.         }  
  23.     } else {  
  24.         obj.type = BINDER_TYPE_BINDER;  
  25.         obj.binder = NULL;  
  26.         obj.cookie = NULL;  
  27.     }  
  28.       
  29.     return finish_flatten_binder(binder, obj, out);  
  30. }  
接下来,回到IPCThreadState::executeCommand中,会sendreply,将刚刚返回的数据传回给binder驱动。


通过talkwithdriver----ioctrl---进入内核空间---也就是binder_ioctl中。

流程大略是binder_ioctl-----binder_thread_write------binder_transaction


在binder_transaction中会对传入的binder_transaction_data进行解析,打包成binder_transaction

  1. static void binder_transaction(struct binder_proc *proc,  
  2.                    struct binder_thread *thread,  
  3.                    struct binder_transaction_data *tr, int reply)  
  4. {  
  5.   
  6. //....  
  7.   
  8.         fp = (struct flat_binder_object *)(t->buffer->data + *offp);  
  9.         switch (fp->type) {//这里会对我们刚刚在reply里写入的数据进行解析  
  10.         case BINDER_TYPE_BINDER:  
  11.         case BINDER_TYPE_WEAK_BINDER: {//如果是传入了BBinder的实体  
  12.             struct binder_ref *ref;  
  13.             struct binder_node *node = binder_get_node(proc, fp->binder);//会进行查找,如果当前进程里没有节点,则会创建一个,node里保存了binder的实体地址和cookie,相当于是实名登记。  
  14.             if (node == NULL) {  
  15.                 node = binder_new_node(proc, fp->binder, fp->cookie);  
  16.                 if (node == NULL) {  
  17.                     return_error = BR_FAILED_REPLY;  
  18.                     goto err_binder_new_node_failed;  
  19.                 }  
  20.                 node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;  
  21.                 node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);  
  22.             }  
  23.             if (fp->cookie != node->cookie) {  
  24.                 binder_user_error("binder: %d:%d sending u%p "  
  25.                     "node %d, cookie mismatch %p != %p\n",  
  26.                     proc->pid, thread->pid,  
  27.                     fp->binder, node->debug_id,  
  28.                     fp->cookie, node->cookie);  
  29.                 goto err_binder_get_ref_for_node_failed;  
  30.             }  
  31.             ref = binder_get_ref_for_node(target_proc, node);//获取目标(client)进程对于node的引用    
  32.             if (ref == NULL) {  
  33.                 return_error = BR_FAILED_REPLY;  
  34.                 goto err_binder_get_ref_for_node_failed;  
  35.             }  
  36.             if (fp->type == BINDER_TYPE_BINDER)  
  37.                 fp->type = BINDER_TYPE_HANDLE; //修改type为handle,等待client进程去读取,创建Bpbinder。  
  38.             else  
  39.                 fp->type = BINDER_TYPE_WEAK_HANDLE;  
  40.             fp->handle = ref->desc;//传入handle值  
  41.             binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,  
  42.                        &thread->todo);  
  43.   
  44.             binder_debug(BINDER_DEBUG_TRANSACTION,  
  45.                      "        node %d u%p -> ref %d desc %d\n",  
  46.                      node->debug_id, node->ptr, ref->debug_id,  
  47.                      ref->desc);  
  48.         } break;  
  49. //....  
  50.   
  51.   
  52. }  

在上述函数中,如果是第一次调用这个,binder驱动做的事里,最关键的是,在目标创建了这个BBinder的实体节点。

总的来说,在建立好Binder通信的连接(基于实名注册的Binder)后,server可以传递Binder对象的引用给client,大致的过程是:

server将Binder对象写入parcel,接着通过ioctrl和binder驱动通信,bidner驱动会对传入的对象进行检查,如果发 现传入的type是binder,则会在当前进程(server对应的proc)查找是否有这个节点,如果没有就用传入的Binder实体在user空间 指针和cookie(通常是BBinder本身)构造一个新的node,接着得到Binder实体的引用,存放在transaction_data中等待 client去获取。

client拿到Binder的引用后,就可以通过这个BpBinder和server的BBinder进行通信了,和实名注册的Binder是一样的,不再赘述。

阅读(1228) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~