binder 进程间通讯关于handle一点疑问?(自己已经弄明白了一点)


疑问的提出:


每个服务通过调用ServiceManger的接口addService会将自己的名字和handle加入到servcemanger进程的svrlist列表里,但是这个handle是怎么来的呢???
我只知道servcemanger是固定死了是0,其他的服务呢?



以CameraService为例

mediaserver启动,创建Camera服务端
CameraService::instantiate();
         --> defaultServiceManager()->addService("media.camera",new CamraService)
                --> IServiceManger::addService
                     {
                             Parcel data
                             data.writeString16("android.os.IServiceManger");
                             data.writeString16(name);
                             data.writeStrongBinder(service);
                                       -->flatten_binder(ProcessState::self(), service, this); //就在这个函数里有点疑问                
                              IPCThreadState::transact(data);
                   }

flatten_binder函数源码:
status_t flatten_binder(const sp<ProcessState>& proc,
    const sp<IBinder>& binder, Parcel* out)
{
    flat_binder_object obj;
   
    obj.flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != NULL) { //执行这个分支
        IBinder *local = binder->localBinder(); //由于CameraService是继承于BBinder,所以local返回对象实列,local是不空的
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            if (proxy == NULL) {
                LOGE("null proxy");
            }
            const int32_t handle = proxy ? proxy->handle() : 0;
            obj.type = BINDER_TYPE_HANDLE;
            obj.handle = handle;
            obj.cookie = NULL;
        } else { //执行这个分支
            obj.type = BINDER_TYPE_BINDER;
            obj.binder = local->getWeakRefs();
            obj.cookie = local;

        }
    } else {
        obj.type = BINDER_TYPE_BINDER;
        obj.binder = NULL;
        obj.cookie = NULL;
    }
   
    return finish_flatten_binder(binder, obj, out);
}
将这个 flat_binder_object写入到Parcel类中,再调用 IPCThreadState::transact将Parcel数据填充binder_transaction_data数据结构,将此数据结构写入内 核,在内核具体作了什么不是很清楚,没看过代码。

ServiceManger服务进程
Service_manger.c main()

从内核读到数据后会一层层的分析,会调用到svcmgr_handler函数,其中涉及到addService的代码:

svcmgr_handler(){

   switch(txn->code) {
    case SVC_MGR_ADD_SERVICE:
        s = bio_get_string16(msg, &len); //这个是取出字符串,就是“media.camera”
        ptr = bio_get_ref(msg); //这个就是取出handle,但是是0,后面会分析这个函数
        if (do_add_service(bs, s, len, ptr, txn->sender_euid)) //这个函数因为ptr是0,直接返回并没于把(name,handle)加到svrlist全局列表里,这明显分析 的是不对的,困惑呀????
            return -1;
        break;

      }

}


bio_get_ref
{
    struct binder_object *obj;
    obj = _bio_get_obj(bio); //这个取出在flatten_binder函 数设置的flat_binder_object变量值(binder_object与flat_binder_object结构体一样)
    if (!obj)
        return 0;

    if (obj->type == BINDER_TYPE_HANDLE) //这个分支 不满足,因为之前设置的是BINDER_TYPE_BINDER
        return obj->pointer;

    return 0; //函数返回0
}

疑问解决:

今天粗略的看了一下内核知道一点原因了
将把flat_binder_object写入内核时,会调用
ioctl(BINDER_WRITE_READ)

   内核

    -->binder_ioctl-->binder_thread_write->binder_transaction

binder_transaction{
    fp = (struct flat_binder_object *)(t->buffer->data + *offp);
        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) {
                node = binder_new_node(proc, fp->binder, fp->cookie);
                if (node == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_new_node_failed;
                }
                node->min_priority = fp->flags & FLAT_BINDER_FLAG_PRIORITY_MASK;
                node->accept_fds = !!(fp->flags & FLAT_BINDER_FLAG_ACCEPTS_FDS);
            }
            if (fp->cookie != node->cookie) {
                binder_user_error("binder: %d:%d sending u%p "
                    "node %d, cookie mismatch %p != %p\n",
                    proc->pid, thread->pid,
                    fp->binder, node->debug_id,
                    fp->cookie, node->cookie);
                goto err_binder_get_ref_for_node_failed;
            }
            ref = binder_get_ref_for_node(target_proc, node);
            if (ref == NULL) {
                return_error = BR_FAILED_REPLY;
                goto err_binder_get_ref_for_node_failed;
            }
            if (fp->type == BINDER_TYPE_BINDER) //在这里类型变了
                fp->type = BINDER_TYPE_HANDLE;
            else
                fp->type = BINDER_TYPE_WEAK_HANDLE;
            fp->handle = ref->desc; //handle就是在这里设置的,后面再简单说明一下 ref->desc是怎么来的,就在前面的binder_get_ref_for_node的函数里设置的
            binder_inc_ref(ref, fp->type == BINDER_TYPE_HANDLE,
                       &thread->todo);

            binder_debug(BINDER_DEBUG_TRANSACTION,
                     "        node %d u%p -> ref %d desc %d\n",
                     node->debug_id, node->ptr, ref->debug_id,
                     ref->desc);
        } break;
}
将fp设置后等待对应的进程读
binder_thread_read
{
        tr.data_size = t->buffer->data_size;
        tr.offsets_size = t->buffer->offsets_size;
        tr.data.ptr.buffer = (void *)t->buffer->data +
                    proc->user_buffer_offset;
        tr.data.ptr.offsets = tr.data.ptr.buffer +
                    ALIGN(t->buffer->data_size,
                        sizeof(void *));
        返回tr给用户空间
}
再来以前提出的函数
bio_get_ref
{
    struct binder_object *obj;
    obj = _bio_get_obj(bio);
    if (!obj)
        return 0;
    if (obj->type == BINDER_TYPE_HANDLE)//第一次分析错误,其实走这个分支
        return obj->pointer; //pointer就是fp->handle
    return 0;
}
这样分析就对了,将name和handle加到了svrlist列表里,上面就是addService的过程,再简单所一下相对应的getService过程,用户空间的我就简单的提一下
defaultServiceManager()->getService("media.camera")
                --> IServiceManger::checkService
                     {
                             Parcel data
                             data.writeString16("android.os.IServiceManger");
                             data.writeString16(name);
                             IPCThreadState::transact(data,replay);
                                      -->ioctrl(BINDER_WRITE_READ)
                             replay.readStrongBinder();                                     
                                      -->unflatten_binder(ProcessState::self(), this,&val);              
                    }
将字符串传给servicemanger,servicemanger会在svrlist列表里根据name查找handle,在将handle填充flat_binder_object写入内核
int svcmgr_handler(){
   switch(txn->code) {
    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
        s = bio_get_string16(msg, &len);
        ptr = do_find_service(bs, s, len);
        if (!ptr)
            break;
        bio_put_ref(reply, ptr);
        return 0;
    }
}

void bio_put_ref(struct binder_io *bio, void *ptr)
{
    struct binder_object *obj;
    if (ptr)
        obj = bio_alloc_obj(bio);
    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; //pointer指向handle
    obj->cookie = 0;
}

内核代码
binder_transaction{
    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); //根据handle查找binder_ref节点,每个handle对应于一个
            if (ref == NULL) {
                binder_user_error("binder: %d:%d got "
                    "transaction with invalid "
                    "handle, %ld\n", proc->pid,
                    thread->pid, fp->handle);
                return_error = BR_FAILED_REPLY;
                goto err_binder_get_ref_failed;
            }
            if (ref->node->proc == target_proc) { //要接受数据的进程与handle所标识的服务进程是同一个
                if (fp->type == BINDER_TYPE_HANDLE)
                    fp->type = BINDER_TYPE_BINDER; //返回给用户前,类型又变了,告诉接受进程“你可以直接使用fp->cookie保存的对象引用,因为你跟对象在一个进程里”
                else
                    fp->type = BINDER_TYPE_WEAK_BINDER;
                fp->binder = ref->node->ptr;
                fp->cookie = ref->node->cookie; //这个指向服务进程内的服务对象的实例
                binder_inc_node(ref->node, fp->type == BINDER_TYPE_BINDER, 0, NULL);
                binder_debug(BINDER_DEBUG_TRANSACTION,
                         "        ref %d desc %d -> node %d u%p\n",
                         ref->debug_id, ref->desc, ref->node->debug_id,
                         ref->node->ptr);
            } else {//要接受数据的进程与handle所标识的服务进程不是同一个
                struct binder_ref *new_ref;
                new_ref = binder_get_ref_for_node(target_proc, ref->node);
                if (new_ref == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }
                fp->handle = new_ref->desc; //赋值服务对象的handle,这里很重要,是我一直想要弄明白的地方,在这里真相大白,不过还有一点点不懂,那就不管了
                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                binder_debug(BINDER_DEBUG_TRANSACTION,
                         "        ref %d desc %d -> ref %d desc %d (node %d)\n",
                         ref->debug_id, ref->desc, new_ref->debug_id,
                         new_ref->desc, ref->node->debug_id);
            }
        } break;
}
将这个fp返回给用户空间
用户空间
status_t unflatten_binder(const sp<ProcessState>& proc,
    const Parcel& in, sp<IBinder>* out)
{
    const flat_binder_object* flat = in.readObject(false);
   
    if (flat) {
        switch (flat->type) {
            case BINDER_TYPE_BINDER:
                *out = static_cast<IBinder*>(flat->cookie);
                return finish_unflatten_binder(NULL, *flat, in);
            case BINDER_TYPE_HANDLE: //不在同一个进程的话执行这个分支
                *out = proc->getStrongProxyForHandle(flat->handle);//根据handle创建BpBinder,分析到这里就可以结束了,通过getService调用返回相应服务对象的handle并根据handle创建BpBinder
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }       
    }
    return BAD_TYPE;
}

你可能感兴趣的:(数据结构,struct,object,service,null,通讯)