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

相关推荐
CYRUS_STUDIO5 小时前
Frida 检测与对抗实战:进程、maps、线程、符号全特征清除
android·逆向
csj506 小时前
安卓基础之《(28)—Service组件》
android
lhbian8 小时前
PHP、C++和C语言对比:哪个更适合你?
android·数据库·spring boot·mysql·kafka
catoop9 小时前
Android 最佳实践、分层架构与全流程解析(2025)
android
ZHANG13HAO9 小时前
Android 13 特权应用(Android Studio 开发)调用 AOSP 隐藏 API 完整教程
android·ide·android studio
田梓燊10 小时前
leetcode 142
android·java·leetcode
angerdream10 小时前
Android手把手编写儿童手机远程监控App之JAVA基础
android
菠萝地亚狂想曲10 小时前
Zephyr_01, environment
android·java·javascript
sTone8737511 小时前
跨端框架通信机制全解析:从 URL Schema 到 JSI 到 Platform Channel
android·前端
sTone8737511 小时前
Java 注解完全指南:从 "这是什么" 到 "自己写一个"
android·前端