Binder - 4、获取Service的过程

441 阅读5分钟

一、前言

我们在前文讨论了Service是怎么添加到ServiceManager的,说完了添加,我们来看下获取的过程,由于过程中很多东西都是一样的,所以获取的分析过程就稍显容易。

针对Service的获取,我们还是从Native层入手,对象还是SurfaceFlinger

二、源码分析

2.1 Surface系统中的getService

我们找一下SurfaceFlinger在native层中的使用,找到这样一段逻辑:

frameworks\native\libs\gui\SurfaceComposerClient.cpp

bool ComposerService::connectLocked() {
    const String16 name("SurfaceFlinger");
    mComposerService = waitForService<ISurfaceComposer>(name);
    if (mComposerService == nullptr) {
        return false; // fatal error or permission problem
    }
    return true;
}

template<typename INTERFACE>
sp<INTERFACE> waitForService(const String16& name) {
    const sp<IServiceManager> sm = defaultServiceManager();
    return interface_cast<INTERFACE>(sm->waitForService(name));
}

我们在之前的分析中已经知道,defaultServiceManager最终返回的是ServiceManagerShim,最终起作用的是BpServiceManager,而waitForService实质上是getService实现的。接下来,我们还是进入BpServiceManager看下后续的逻辑:

2.2 BpServiceManagergetService

BpServiceManager是由aidl生成的,其checkService方法为:

::android::binder::Status BpServiceManager::getService(const ::std::string &name,::android::sp<::android::IBinder> *_aidl_return)
{
    ::android::Parcel _aidl_data;
    _aidl_data.markForBinder(remoteStrong());
    ::android::Parcel _aidl_reply;
    ::android::status_t _aidl_ret_status = ::android::OK;
    ::android::binder::Status _aidl_status;
    _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
    _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
    _aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_getService, _aidl_data, &_aidl_reply, 0);
    _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
    _aidl_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
    if (((_aidl_ret_status) != (::android::OK)))
    {
        goto _aidl_error;
    }
    return _aidl_status;
}

这里remote()代表的是BpBinder(0),然后直接进行transact,我们知道这会经过IPCThreadState,然后进入内核层,与addService一致,然后进入ServiceManager进程,最后由BnServiceManager来处理事务。

中间通信过程基本同addService,我们来看BnServiceManager的逻辑:

2.3 BnServiceManageronTransact

case BnServiceManager::TRANSACTION_getService:
{
    ::std::string in_name;
    //读取name
    ::android::sp<::android::IBinder> _aidl_return;
    _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
    //调用真正实现
    ::android::binder::Status _aidl_status(getService(in_name, &_aidl_return));
    _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
    //将获取到的IBinder对象写入reply
    _aidl_ret_status = _aidl_reply->writeStrongBinder(_aidl_return);
}
  • 1、首先获取Servicename
  • 2、调用ServiceManagergetService真正实现
  • 3、写入reply

我们来看下真正的getService实现:

frameworks\native\cmds\servicemanager\ServiceManager.cpp

Status ServiceManager::getService(const std::string& name, sp<IBinder>* outBinder) {
    *outBinder = tryGetService(name, true);
    // returns ok regardless of result for legacy reasons
    return Status::ok();
}

sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfNotFound) {
    auto ctx = mAccess->getCallingContext();
    sp<IBinder> out;
    Service* service = nullptr;
    if (auto it = mNameToService.find(name); it != mNameToService.end()) {
        service = &(it->second);
        if (!service->allowIsolated) {
            //...
        }
        out = service->binder;
    }
    return out;
}

还记得我们之前存储的Map吗?这里我们从Map中通过Name取出了我们需要的IBinder对象,也就是BpBinder对象,这个对象中含有handle值。

拿到BpBinder之后,我们需要返回给对端,回到刚才的writeStrongBinder方法,这次内部的分支要发生变化了:

2.3.1 BpBinderwriteStrongBinder

我们看下Parcel中的实现:

status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
    if (isForRpc()) {
        //...
    }
    flat_binder_object obj;
    obj.flags = FLAT_BINDER_FLAG_ACCEPTS_FDS;
    if (binder != nullptr) {
        BBinder *local = binder->localBinder();
        if (!local) {
            BpBinder *proxy = binder->remoteBinder();
            const int32_t handle = proxy ? proxy->getPrivateAccessorForId().binderHandle() : 0;
            obj.hdr.type = BINDER_TYPE_HANDLE;
            obj.binder = 0; /* Don't pass uninitialized stack data to a remote process */
            obj.handle = handle;
            obj.cookie = 0;
        } else {
            //...
        }
    } else {
        //...
    }
    obj.flags |= schedBits;
    status_t status = writeObject(obj, false);
    if (status != OK) return status;
    return finishFlattenBinder(binder);
}

这次我们的local为空,然后给flat_binder_object赋值,此时类型为BINDER_TYPE_HANDLEhandle值为我们设置进去的那个,既然flat_binder_object有所调整,Binder驱动中的逻辑也会有所调整,首先是binder_transaction

2.3.2 binder_transaction的变化

此时binder_transaction中的type发生变化,对应的case有所调整:

case BINDER_TYPE_HANDLE:
case BINDER_TYPE_WEAK_HANDLE: {
    struct flat_binder_object *fp
    fp = to_flat_binder_object(hdr);
    //调用binder_translate_handle
    ret = binder_translate_handle(fp, t, thread);
    if (ret < 0 ||
        binder_alloc_copy_to_buffer(&target_proc->alloc,
                    t->buffer,
                    object_offset,
                    fp, sizeof(*fp))) {
        //...
    }
} break;

其对flat_binder_object的使用变成了binder_translate_handle:

static int binder_translate_handle(struct flat_binder_object *fp,
                   struct binder_transaction *t,
                   struct binder_thread *thread)
{
    struct binder_proc *proc = thread->proc;
    struct binder_proc *target_proc = t->to_proc;
    struct binder_node *node;
    struct binder_ref_data src_rdata;
    int ret = 0;
    //获取Binder节点
    node = binder_get_node_from_ref(proc, fp->handle,
            fp->hdr.type == BINDER_TYPE_HANDLE, &src_rdata);
    if (node->proc == target_proc) {
        //如果调用和目标是同个进程
        //我们这里不是同个进程
        //...
    } else {
        struct binder_ref_data dest_rdata;
        //增加引用计数,更新handle值
        ret = binder_inc_ref_for_node(target_proc, node,
                fp->hdr.type == BINDER_TYPE_HANDLE,
                NULL, &dest_rdata);
        fp->binder = 0;
        fp->handle = dest_rdata.desc;
        fp->cookie = 0;
    }
done:
    binder_put_node(node);
    return ret;
}
  • 1、首先获取handle对应的Binder节点
  • 2、如果调用和目标不是同个进程,对Binder节点引用计数+1
  • 3、更新返回handle值

ServiceManager中保存着Service的引用,也就是handle,通过这个handle,Binder驱动找到了其对应的Binder节点,然后修改对该节点的引用,因为调用getService之后,代表有一个新的地方引用了该对象,在修改完引用之后,将handle更新,最后将flat_binder_object再写入到客户端进程中。

2.4 回到BpServiceManager

我们回头再看下,回到getService中,我们想要的是_aidl_return,我们已经知道readNullableStrongBinder就是根据handle创建BpBinder,最后,我们拿到了Service的代理,那就是BpBinder

2.5 接口的实现

拿到BpBinder之后,用户进程是不能直接使用的,因为没有用户进程想要的接口,这时interface_cast就起作用了,经过interface_cast之后,BpBinder就变成了BpSurfaceComposer

三、总结

通过ServiceManager获取Service的过程,也是一个IPC过程,其中,ServiceManager持有Service的句柄handle,在经过Binder通信之后,handle被更新,对应Binder节点的引用计数增加,然后返回给用户进程,用户进程拿到handle之后,将其初始化为BpBinder,然后将BpBinder转换为实现了接口的Bp类,从此用户进程就可以通过此Bp类进行快乐的IPC通信了~

由于getService本身也是IPC通信,所以我们能看到很多地方会做缓存,只需要获取一次就够了。