android Binder详解(4)


3.4 getService()分析

clinet中获取service接口的调用如下:

    sp<ISampleService> sampleSrv;
    if(getService(String16("SampleService"), &sampleSrv) != NO_ERROR){
        ALOGE("get SampleService fail");
        return 0;
    }
getService()实现如下:

template<typename INTERFACE>
status_t getService(const String16& name, sp<INTERFACE>* outService)
{
    const sp<IServiceManager> sm = defaultServiceManager();
    if (sm != NULL) {
        *outService = interface_cast<INTERFACE>(sm->getService(name));
        if ((*outService) != NULL) return NO_ERROR;
    }
    return NAME_NOT_FOUND;
}
这其中获取ServiceManager接口的动作,前面已经分析过了。之后有两个动作:
1,sm->getService(name)获取到一个sp<IBinder>对象。
2,从获取的BpBinder指针中构造出BpSampleService对象。

第二步是很清楚的,就是调用了BpSampleService::interface_cast<ISampleService>(sp<IBinder>)。我们主要需要研究一下第一步的细节。


3.4.1 BpServiceManager::getService()

BpServiceManager::getService()是调用了checkService()函数

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;
            ALOGI("Waiting for service %s...\n", String8(name).string());
            sleep(1);
        }
        return NULL;
    }
virtual sp<IBinder> checkService( const String16& name) const
    {
        Parcel data, reply;
        data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
        data.writeString16(name);
        remote()->transact(CHECK_SERVICE_TRANSACTION, data, &reply);
        return reply.readStrongBinder();
    }
checkService()中之写入了InterfaceToken和servicename,然后就开始了transact()了。
这边的transact因为没有写入object,流程和PING_TRANSACTION的基本一样了。我们直接到ServiceManager端看看具体的处理。

3.4.2 ServiceManager处理CHECK_SERVICE_TRANSACTION

command和ADD_SERVICE一样在svcmgr_handler()中处理

    case SVC_MGR_GET_SERVICE:
    case SVC_MGR_CHECK_SERVICE:
       //获取service name。
        s = bio_get_string16(msg, &len);
       //查找对应的service。
        ptr = do_find_service(bs, s, len, txn->sender_euid);
        if (!ptr)
            break;
        bio_put_ref(reply, ptr);
        return 0;
主要看下do_find_service()

void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len, unsigned uid)
{
    //根据service name找到对应的svcinfo结点。
    struct svcinfo *si;
    si = find_svc(s, len);
    
//    ALOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
    if (si && si->ptr) {
        if (!si->allow_isolated) {
            // If this service doesn't allow access from isolated processes,
            // then check the uid to see if it is isolated.
            unsigned appid = uid % AID_USER;
            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
                return 0;
            }
        }
    //返回结点中的ptr,这个ptr是binder中对应的binder_ref.desc。
        return si->ptr;
    } else {
        return 0;
    }
}
我们看到了最终返回的是SampleService在ServiceManager这边对应的binder_ref的desc信息,之后这个信息被写入到write buffer中:
void bio_put_ref(struct binder_io *bio, void *ptr)
{ 
    //构造了一个binder_object,也就是一个flat_binder_object。
    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;
    obj->cookie = 0;
}
之后进入binder_send_reply(),在这里,我们write了BC_FREE_BUFFER,还有一组BC_REPLY信息,BC_REPLY信息中,是在bio_put_ref()中构造的binder_object。
带着这些信息,我们进入到binder中,首先在binder_thread_write()中处理BC_FREE_BUFFER,这边的处理和之前的PING_TRANSACTION基本一致,没有object,释放掉binder_buffer就可以了。
然后处理BC_REPLY,主要在binder_transaction()函数中,这里和addService处理差异在于reply信息是一个object,而不是一个数据,我们看下组织binder_transaction的部分:

        //remote binder object, means BpBinder。
        case BINDER_TYPE_HANDLE:
        case BINDER_TYPE_WEAK_HANDLE: {
            struct binder_ref *ref = binder_get_ref(proc, fp->handle);
            if (ref == NULL) {
                binder_user_error("%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 (security_binder_transfer_binder(proc->tsk, target_proc->tsk)) {
                return_error = BR_FAILED_REPLY;
                goto err_binder_get_ref_failed;
            }
            //如果传给service所在的进程,转换为BINDER_TYPE_BINDER类型的object。
            if (ref->node->proc == target_proc) {
                if (fp->type == BINDER_TYPE_HANDLE)
                    fp->type = BINDER_TYPE_BINDER;
                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);
                trace_binder_transaction_ref_to_node(t, ref);
                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 {//传入到其他client进程,为目标进程建立新的binder_ref,并传回这个新的binder_ref的信息。
                struct binder_ref *new_ref;
                new_ref = binder_get_ref_for_node(target_proc, ref->node);//第一次会建立一个新的binder_ref。
                if (new_ref == NULL) {
                    return_error = BR_FAILED_REPLY;
                    goto err_binder_get_ref_for_node_failed;
                }
                fp->handle = new_ref->desc;//用目标进程desc替换。
                binder_inc_ref(new_ref, fp->type == BINDER_TYPE_HANDLE, NULL);
                trace_binder_transaction_ref_to_ref(t, ref,
                                    new_ref);
                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;
在这里,binder会为client进程建立一个新的binder_ref出来,他会在当前进程中得到一个唯一的desc也就是handle值,注意desc值0是保留给了ServiceManager,最终我们把这个handle回填到data中。

3.4.3 client端处理返回信息
client在IPCThreadState::waitForResponse()处理BR_REPLY,数据传递给Parcel reply中,最终调用得到了sp<IBinder>对象。

reply.readStrongBinder();
我们看看readStrongBinder()里面做了什么:
sp<IBinder> Parcel::readStrongBinder() const
{
    sp<IBinder> val;
    unflatten_binder(ProcessState::self(), *this, &val);
    return val;
}
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:
                //查找对应的BpBinder对象。
                *out = proc->getStrongProxyForHandle(flat->handle);
                return finish_unflatten_binder(
                    static_cast<BpBinder*>(out->get()), *flat, in);
        }        
    }
    return BAD_TYPE;
}
最终还是调用了getStrongproxyForHandle()来获取了sp<IBinder>,参数的handle就是在binder中的binder_ref.desc。
getStrongproxyForHandle()中创建BpBinder的动作,我们就不在看了,我们看一下如果不是首次调用的情况下的处理:
} else {
            // 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.
           //force_set()函数和直接赋值的差异在于它会强制调用RefBase.onFirstRef(),对这里来说
           //也就是会出发BpBinder.onFirstRef()。
            result.force_set(b);
            e->refs->decWeak(this);
        }
这段代码中主要注意一下result.fore_set(b)这行代码,这里又强制触发了一次RefBase.onFirstRef(),调用的目的是对binder中的binder_ref增加了一次引用。
但是这里有个问题:
force_set对于binder_ref又增加了一次reference,但是因为他们用的都是同意BpBinder,最终只会调用一次onLastStrongRef()去decrease strong reference,这样会导致ref的增减不同步,可能是会有问题的。(加了debug信息确认,的确是会出现这样的问题的。)


至此,getService()部分分析完毕,我们看到了service的传递主要是依赖binder对于binder_ref的管理,binder_ref.desc决定了在user层的handle,user层又使用handle去建立了一个BpBinder,所有的service访问结构都是使用这个BpBinder构造出BpXXX对象来操作service接口。


3.5 sayHello()调用分析
这部分我们分析下client端调用SampleService的sayHello()接口的流程,看看client端是如何把信息投递到service进程中去的。

3.5.1 sayHello() client调用

virtual int sayHello(const String8& clientName){
        Parcel data,reply;
        data.writeInterfaceToken(ISampleService::getInterfaceDescriptor());
       
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值