Binder - 4、获取Service的过程

一、前言

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

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

二、源码分析

2.1 Surface系统中的getService

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

frameworks\native\libs\gui\SurfaceComposerClient.cpp

c++ 复制代码
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方法为:

c++ 复制代码
::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

c++ 复制代码
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

c++ 复制代码
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中的实现:

c++ 复制代码
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有所调整:

c++ 复制代码
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:

c++ 复制代码
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通信,所以我们能看到很多地方会做缓存,只需要获取一次就够了。

相关推荐
无极程序员1 小时前
PHP常量
android·ide·android studio
萌面小侠Plus2 小时前
Android笔记(三十三):封装设备性能级别判断工具——低端机还是高端机
android·性能优化·kotlin·工具类·低端机
慢慢成长的码农2 小时前
Android Profiler 内存分析
android
大风起兮云飞扬丶3 小时前
Android——多线程、线程通信、handler机制
android
L72563 小时前
Android的Handler
android
清风徐来辽3 小时前
Android HandlerThread 基础
android
HerayChen4 小时前
HbuildderX运行到手机或模拟器的Android App基座识别不到设备 mac
android·macos·智能手机
顾北川_野4 小时前
Android 手机设备的OEM-unlock解锁 和 adb push文件
android·java
hairenjing11234 小时前
在 Android 手机上从SD 卡恢复数据的 6 个有效应用程序
android·人工智能·windows·macos·智能手机
小黄人软件4 小时前
android浏览器源码 可输入地址或关键词搜索 android studio 2024 可开发可改地址
android·ide·android studio