• Android12系统源码分析|Native Binder代码变迁


    Android12系统源码分析|Native Binder代码变迁

    注:广义上native binder可理解为包含vnd,hw,rpc等内容,本文所讨论的Native Binder指的仅是servicemanager服务程序及libbinder中相关代码,不做广义的延伸。

    一、前言

    servicemanager程序(以下简称SM)是Android系统binder模块重要的组成部分,扮演着类似C/S架构中的DNS服务器的角色,提供服务增查和权限管理等功能支撑。

    在Android11之前的版本里,SM是面向binder驱动编程,直接使用open、mmap、ioctl等api与binder驱动交互。而从Android11开始,SM放弃使用这些较底层的接口,转向libbinder库和AIDL。标志性的提交如下,该提交奠定了新的SM架构基础,此后多次提交对此进行完善填充。

    frameworks/native

    servicemanager: use libbinder
    
    Bug: 135768100
    Test: boot
    Test: servicemanager_test
    
    Change-Id: I9d657b6c0d0be0f763b6d54e0e6c6bc1c1e3fc7a
    (cherry picked from commit 3e092daa14c63831d76d3ad6e56b2919a0523536)
    
    smoreland@google.com(作者)
    提交日期2019-07-09 AM 9:54
    

    本文代码基于Android12,以SM为主视角,从架构和情景流程上带大家认识新的Native Binder。

    二、软件架构

    2.1、架构概述

    图1:切换到aidl和libbinder后的ServiceManager类关系图

    图注:

    为了画图方便,将namespace写成了下划线形式。

    android_os_BpServiceManager和android_os_BnServiceManager、android_os_IServiceManager类均在android os 的namespace中,其他无下划线的类名,处于android namespace中。

    一图胜千言,11之前的SM是写在c文件里,没有类的概念,现在基于aidl和libbinder,使用cpp语言,用uml就可以很形象地展示类关系了。就着这幅图我们大致描述新的软件架构。

    • 红色线段大概地将服务端与客户端类相分隔,服务端在右下角。

    一些libbinder的用于继承的公共类请读者自行剥离,而不是将其归入某一端。例如IBinder,我们知道他是BBinder和BpBinder的父类,是公共的接口约束。

    • libbinder中客户端的入口变为:IServiceManager.cpp#ServiceManagerShim

    之前无该辅助类,而是直接操作BpServiceManager,这个辅助类封装了aidl自动生成的BpServiceManager,所以现在的客户端代码流就变成如下三步:

    1.用户代码 
    2.libbinder代码 binder/IServiceManager.cpp#ServiceManagerShim
    3.aidl代码      android/os/IServiceManager.cpp#BpServiceManager接口
    

    所以libbinder中的ServiceManagerShim起到了一个中转的作用,把请求转给out下aidl自动生成的BpServiceManager。

    • BpServiceManager的实现挪到out

    原来是在libbinder#IServiceManager.cpp中手写实现,现在是aidl帮你实现。

    当然,该文件中同样自动实现了BnServiceManager类

    代码路径

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm64_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

    • 服务端的核心实现在ServiceManager.cpp

    原来是没有Bn的,而是一个binder_loop方法沟通驱动,现在则是ServiceManager继承了BnServiceManager来获得代码流。

    • waitForService的改动:IServiceCallback.aidl

    Waiter类。新增了binder匿名服务用来向sm注册跨进程的回调,当sm检测到有服务注册时,会返回通知。

    • 服务的客户端数量监听:IServiceCallback.aidl

    IServiceCallback.aidl这个匿名binder服务就是用于该目的,可以监听某个服务的客户端数量。

    2.2、文件路径

    • AIDL

    AIDL是一种方便的接口定义语言,用于Binder-IPC编程。详细介绍与使用可参考:AIDL Overview

    我们关注三个aidl,分别是IServiceManager.aidl、IServiceCallback.aidl、IClientCallback.aidl,对应的编译后生成的文件路径为:

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/

    IClientCallback.cpp

    IServiceCallback.cpp

    IServiceManager.cpp

    • libbinder中的代码路径

    frameworks/native/libs/binder/IServiceManager.cpp

    • SM服务端代码路径

    frameworks/native/cmds/servicemanager/

    main.cpp

    Access.cpp

    ServiceManager.cpp

    本小节仅展示涉及变迁的文件路径。简洁起见只写了cpp文件,对应的h头文件可以附近查找。

    另外需要特别区分的是,有两个IServiceManager。

    一个在libbinder中,是android的name space,直接被用户#include<binder/IServiceManager>使用。

    另一个是aidl自动生成的android os 的name space,被上面的libbinder所使#include<android/os/IServiceManager>

    2.3、小结

    第二章节从全局的角度展示了SM切换到aidl和libbinder的软件架构,结合图来看还是非常清楚易于理解的。

    接下来跟踪几个情景流程,展示新架构中的细节。

    三、servicemanager启动流程分析

    图2:servicemanager启动时序图

    如上图,启动流程的变动主要在进入循环的方式,android11之前是通过binder_loop方法,而现在是通过looper。下面展示细节。

    frameworks/native/cmds/servicemanager/main.cpp

    int main(int argc, char** argv) {
        if (argc > 2) {
            LOG(FATAL) << "usage: " << argv[0] << " [binder driver]";
        }
    
        const char* driver = argc == 2 ? argv[1] : "/dev/binder";
    	//沟通binder驱动,open,mmap
        sp<ProcessState> ps = ProcessState::initWithDriver(driver);
        ps->setThreadPoolMaxThreadCount(0);
        //oneway限制,sm发起的binder调用必须是单向,否则打印堆栈日志提示
        ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY);
        //实例化ServiceManager,传入Access类用于鉴权
        sp<ServiceManager> manager = sp<ServiceManager>::make(std::make_unique<Access>());
        if (!manager->addService("manager", manager, false /*allowIsolated*/, IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT).isOk()) {
            LOG(ERROR) << "Could not self register servicemanager";
        }
        //设置全局变量给IPCThreadState
        IPCThreadState::self()->setTheContextObject(manager);
        //注册到驱动,成为binder管理员,handle是0
        ps->becomeContextManager();
        //准备looper
        sp<Looper> looper = Looper::prepare(false /*allowNonCallbacks*/);
        //通知驱动BC_ENTER_LOOPER,监听驱动fd,有消息时回调到handleEvent处理binder调用
        BinderCallback::setupTo(looper);
        //服务的注册监听相关
        ClientCallbackCallback::setupTo(looper, manager);
        //无限循环等消息
        while(true) {
            looper->pollAll(-1);
        }
    
        // should not be reached
        return EXIT_FAILURE;
    }
    

    和原来的servicemanager服务相比较,使用了libbinder后,代码更规范化,和其他native的服务风格一致了。

    • 之前是直接open、mmap现在是借助libbinder

    • 之前是binder_loop死循环接收驱动的消息,现在是通过looper监听fd来handleEvent

    • 之前的鉴权现在被独立到单独文件Access.cpp

    突然想起一个题目,servicemanager映射的虚拟内存有多大?现在的答案是和普通应用一样大:1M-2页。

    frameworks/native/libs/binder/ProcessState.cpp

    #define BINDER_VM_SIZE ((1 * 1024 * 1024) - sysconf(_SC_PAGE_SIZE) * 2)
    

    启动流程比较清晰不多赘述,下一小节看addService的流程。

    四、addService流程分析

    图3:defaultServiceManager流程

    图4:addService客户端流程

    图5:addService服务端流程

    先上图,总览native的代码流程,客户端是libbinder里的IServiceManager.cpp,服务端是我们的ServiceManager.cpp

    4.1、ServiceManagerShim::addService

    frameworks/native/libs/binder/IServiceManager.cpp

    status_t ServiceManagerShim::addService(const String16& name, const sp<IBinder>& service,
                                            bool allowIsolated, int dumpsysPriority)
    {
        Status status = mTheRealServiceManager->addService(
            String8(name).c_str(), service, allowIsolated, dumpsysPriority);
        return status.exceptionCode();
    }
    

    直接使用的mTheRealServiceManager,澄清疑问,mTheRealServiceManager是谁?

    4.1.1、mTheRealServiceManager是谁?

    frameworks/native/libs/binder/IServiceManager.cpp

    #include <android/os/IServiceManager.h>
    using AidlServiceManager = android::os::IServiceManager;
    class ServiceManagerShim : public IServiceManager
    {
    protected:
        sp<AidlServiceManager> mTheRealServiceManager;
    ......
    ServiceManagerShim::ServiceManagerShim(const sp<AidlServiceManager>& impl)
     : mTheRealServiceManager(impl)
    {}
    

    可以看到,mTheRealServiceManager就是一个android::os::IServiceManager类型的实例,并且在ServiceManagerShim实例化时赋值。

    那么ServiceManagerShim何时实例化呢?答案是defaultServiceManager()中

    frameworks/native/libs/binder/IServiceManager.cpp

    sp<IServiceManager> defaultServiceManager()
    {
        std::call_once(gSmOnce, []() {
            sp<AidlServiceManager> sm = nullptr;
            while (sm == nullptr) {
                //1、拿到AidlServiceManager类型的BpServiceManager(new BpBinder(0))实例
                sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr));
                if (sm == nullptr) {
                    ALOGE("Waiting 1s on context object on %s.", ProcessState::self()->getDriverName().c_str());
                    sleep(1);
                }
            }
            //2、new ServiceManagerShim
            gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
        });
    
        return gDefaultServiceManager;
    }
    

    如注释1、2,mTheRealServiceManager就是在这样流程中赋值的。他的真是面目是BpServiceManager(new BpBinder(0))

    由图1可知,我们拿到了操作binder驱动的入口,BpServiceManager-->BpBinder-->IPCThreadState-->ioctl

    关于一部分旧知识会贴拓展链接本文不做展开。interface_cast的实现可参考:浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路

    好现在返回上节,直接走入BpServiceManager#addService方法

    4.2、BpServiceManager::addService

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

    namespace android {
    namespace os {
    
    BpServiceManager::BpServiceManager(const ::android::sp<::android::IBinder>& _aidl_impl)
        : BpInterface<IServiceManager>(_aidl_impl){//_aidl_impl就是BpBinder(0)实例
    }
    --------------------------------------------------
        ::android::binder::Status BpServiceManager::addService(const ::std::string& name, const ::android::sp<::android::IBinder>& service, bool allowIsolated, int32_t dumpPriority) {
      ::android::Parcel _aidl_data;
      _aidl_data.markForBinder(remoteStrong());//0、和rpc binder有关
      ::android::Parcel _aidl_reply;
      ::android::status_t _aidl_ret_status = ::android::OK;
      ::android::binder::Status _aidl_status;
      //1、写interface
      _aidl_ret_status = _aidl_data.writeInterfaceToken(getInterfaceDescriptor());
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      //2、写name
      _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      //3、写binder对象
      _aidl_ret_status = _aidl_data.writeStrongBinder(service);
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      //4、写allowIsolated
      _aidl_ret_status = _aidl_data.writeBool(allowIsolated);
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      //5、写dumpPriority
      _aidl_ret_status = _aidl_data.writeInt32(dumpPriority);
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      //6、借助BpBinder(0)-transact来发起binder通信
      _aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_addService, _aidl_data, &_aidl_reply, 0);
      if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
         return IServiceManager::getDefaultImpl()->addService(name, service, allowIsolated, dumpPriority);
      }
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      //7、如果有返回值就从这个parcel包里读
      _aidl_ret_status = _aidl_status.readFromParcel(_aidl_reply);
      if (((_aidl_ret_status) != (::android::OK))) {
        goto _aidl_error;
      }
      if (!_aidl_status.isOk()) {
        return _aidl_status;
      }
      _aidl_error:
      _aidl_status.setFromStatusT(_aidl_ret_status);
      return _aidl_status;
    }
    

    把android10的贴上来,我们对比看看

    frameworks/native/libs/binder/IServiceManager.cpp

        virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                    bool allowIsolated, int dumpsysPriority) {
            Parcel data, reply;
            data.writeInterfaceToken(IServiceManager::getInterfaceDescriptor());
            data.writeString16(name);
            data.writeStrongBinder(service);
            data.writeInt32(allowIsolated ? 1 : 0);
            data.writeInt32(dumpsysPriority);
            status_t err = remote()->transact(ADD_SERVICE_TRANSACTION, data, &reply);
            return err == NO_ERROR ? reply.readExceptionCode() : err;
        }
    

    和11之前手写的BpServiceManager相比,本质是没变的,就是多了些花里胡哨的规范性代码。

    到这里,客户端的代码就大致展示完了,transact再往后就是旧有的流程,可参考:浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路

    之后走到binder驱动,驱动又根据handle == 0找到对端,我们的servicemanager进程,唤醒他开始处理请求。

    4.3、BinderCallback::handleEvent

    如图4:addService服务端流程,现在开始服务端的流程展示。

    frameworks/native/cmds/servicemanager/main.cpp

    class BinderCallback : public LooperCallback {
    public:
    ......
            int handleEvent(int /* fd */, int /* events */, void* /* data */) override {
            IPCThreadState::self()->handlePolledCommands();
            return 1;  // Continue receiving callbacks.
        }
    };
    

    之后走到BR_TRANSACTION

    frameworks/native/libs/binder/IPCThreadState.cpp

    status_t IPCThreadState::executeCommand(int32_t cmd)
    {
    	switch ((uint32_t)cmd) {
    		case BR_TRANSACTION:
            {
            	if (tr.target.ptr) {
            	//因为目的端sm所以是tr.target.ptr是0
            	}else {//开始业务分发
            	    error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            	}
    

    the_context_object是SM启动的时候设置好的

    sp<BBinder> the_context_object;
    
    void IPCThreadState::setTheContextObject(const sp<BBinder>& obj)
    {
        the_context_object = obj;
    }
    

    是ServiceManager类实例,所以也是一个BBinder对象,所以就有了transact()-->onTransact()的处理能力。

    所以现在the_context_object->transact()调用就走到BBinder的transact又走到BnServiceManager的onTransact()方法,回到了这个aidl自动生成的IServiceManager.cpp文件里。

    兜兜转转还是在这个文件。

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceManager.cpp

    ::android::status_t BnServiceManager::onTransact(uint32_t _aidl_code, const ::android::Parcel& _aidl_data, ::android::Parcel* _aidl_reply, uint32_t _aidl_flags) {
      ::android::status_t _aidl_ret_status = ::android::OK;
      switch (_aidl_code) {
      case BnServiceManager::TRANSACTION_addService:
      {
        ::std::string in_name;
        ::android::sp<::android::IBinder> in_service;
        bool in_allowIsolated;
        int32_t in_dumpPriority;
        //检查interface
        if (!(_aidl_data.checkInterface(this))) {
          _aidl_ret_status = ::android::BAD_TYPE;
          break;
        }
        //读name
        _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
        if (((_aidl_ret_status) != (::android::OK))) {
          break;
        }
        //读binder
        _aidl_ret_status = _aidl_data.readStrongBinder(&in_service);
        if (((_aidl_ret_status) != (::android::OK))) {
          break;
        }
        //读in_allowIsolated
        _aidl_ret_status = _aidl_data.readBool(&in_allowIsolated);
        if (((_aidl_ret_status) != (::android::OK))) {
          break;
        }
        //读in_dumpPriority
        _aidl_ret_status = _aidl_data.readInt32(&in_dumpPriority);
        if (((_aidl_ret_status) != (::android::OK))) {
          break;
        }
        //调用真正的ServiceManager.cpp中的实现
        ::android::binder::Status _aidl_status(addService(in_name, in_service, in_allowIsolated, in_dumpPriority));
        //如果有返回写返回到_aidl_reply
        _aidl_ret_status = _aidl_status.writeToParcel(_aidl_reply);
        if (((_aidl_ret_status) != (::android::OK))) {
          break;
        }
        if (!_aidl_status.isOk()) {
          break;
        }
      }
    

    和Bp端是对称的操作,下一步走到ServiceManager.cpp::addService方法

    4.4、ServiceManager::addService

    frameworks/native/cmds/servicemanager/ServiceManager.cpp

    Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
        auto ctx = mAccess->getCallingContext();
    
        // uid鉴权
        if (multiuser_get_app_id(ctx.uid) >= AID_APP) {
            return Status::fromExceptionCode(Status::EX_SECURITY);
        }
        //selinux鉴权
        if (!mAccess->canAdd(ctx, name)) {
            return Status::fromExceptionCode(Status::EX_SECURITY);
        }
    
        if (binder == nullptr) {
            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
        }
        //检查name命名
        if (!isValidServiceName(name)) {
            LOG(ERROR) << "Invalid service name: " << name;
            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
        }
        //如果vndservicemanager则检查VINTF manifest
    #ifndef VENDORSERVICEMANAGER
        if (!meetsDeclarationRequirements(binder, name)) {
            // already logged
            return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT);
        }
    #endif  // !VENDORSERVICEMANAGER
        //和rpc有关,死亡监听
        // implicitly unlinked when the binder is removed
        if (binder->remoteBinder() != nullptr &&
            binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) {
            LOG(ERROR) << "Could not linkToDeath when adding " << name;
            return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE);
        }
        //新增一个结构体到map中
        // Overwrite the old service if it exists
        mNameToService[name] = Service {
            .binder = binder,
            .allowIsolated = allowIsolated,
            .dumpPriority = dumpPriority,
            .debugPid = ctx.debugPid,
        };
        //架构中提到的waiteForService的跨进程
        auto it = mNameToRegistrationCallback.find(name);
        if (it != mNameToRegistrationCallback.end()) {
            for (const sp<IServiceCallback>& cb : it->second) {
                mNameToService[name].guaranteeClient = true;
                // permission checked in registerForNotifications
                cb->onRegistration(name, binder);
            }
        }
    
        return Status::ok();
    }
    

    五、其他值得关注的细节

    前两节是全局总览、经典情景的视角看代码,现在我们换一个视角,展示一些边边角角的内容为上面的主干填充细节。

    5.1、servicemanager的能力变化

    11之前仅有4个接口暴露给应用

    frameworks/native/libs/binder/include/binder/IServiceManager.h

        enum {
            GET_SERVICE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
            CHECK_SERVICE_TRANSACTION,
            ADD_SERVICE_TRANSACTION,
            LIST_SERVICES_TRANSACTION,
        };
    

    而Android11增加到9个,Android12又增加到13个

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/BnServiceManager.h

    class BnServiceManager : public ::android::BnInterface<IServiceManager> {
    public:
      static constexpr uint32_t TRANSACTION_getService = ::android::IBinder::FIRST_CALL_TRANSACTION + 0;
      static constexpr uint32_t TRANSACTION_checkService = ::android::IBinder::FIRST_CALL_TRANSACTION + 1;
      static constexpr uint32_t TRANSACTION_addService = ::android::IBinder::FIRST_CALL_TRANSACTION + 2;
      static constexpr uint32_t TRANSACTION_listServices = ::android::IBinder::FIRST_CALL_TRANSACTION + 3;
      static constexpr uint32_t TRANSACTION_registerForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 4;
      static constexpr uint32_t TRANSACTION_unregisterForNotifications = ::android::IBinder::FIRST_CALL_TRANSACTION + 5;
      static constexpr uint32_t TRANSACTION_isDeclared = ::android::IBinder::FIRST_CALL_TRANSACTION + 6;
      static constexpr uint32_t TRANSACTION_getDeclaredInstances = ::android::IBinder::FIRST_CALL_TRANSACTION + 7;
      static constexpr uint32_t TRANSACTION_updatableViaApex = ::android::IBinder::FIRST_CALL_TRANSACTION + 8;
      static constexpr uint32_t TRANSACTION_getConnectionInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 9;
      static constexpr uint32_t TRANSACTION_registerClientCallback = ::android::IBinder::FIRST_CALL_TRANSACTION + 10;
      static constexpr uint32_t TRANSACTION_tryUnregisterService = ::android::IBinder::FIRST_CALL_TRANSACTION + 11;
      static constexpr uint32_t TRANSACTION_getServiceDebugInfo = ::android::IBinder::FIRST_CALL_TRANSACTION + 12;
    

    从这些接口的变动我们也可以很清晰地把握住servicemanager的前进方向

    5.2、DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE

    frameworks/native/libs/binder/include/binder/IInterface.h

    #define IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \
        static_assert(internal::allowedManualInterface(NAME),               \
                      "b/64223827: Manually written binder interfaces are " \
                      "considered error prone and frequently have bugs. "   \
                      "The preferred way to add interfaces is to define "   \
                      "an .aidl file to auto-generate the interface. If "   \
                      "an interface must be manually written, add its "     \
                      "name to the whitelist.");                            \
        DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)    \
    -----------------------------
    constexpr const char* const kManualInterfaces[] = {
      "android.app.IActivityManager",
      "android.app.IUidObserver",
      "android.drm.IDrm",
      "android.dvr.IVsyncCallback",
      "android.dvr.IVsyncService",
      "android.gfx.tests.ICallback",
      "android.gfx.tests.IIPCTest",
      ......
    

    以后手写的native服务需要关注下这个宏,做了限制。谷歌建议是现在的native服务都用aidl,别手写。

    5.3、String16、String8与name

    aidl改造之前,都是一路String16从客户端传到服务端,而现在需要绕一些路了。还是以addService为例

    status_t ServiceManagerShim::addService(const String16& name,){
        Status status = mTheRealServiceManager->addService(
            String8(name).c_str(), );
    在这里转一次,16转成8
    ------------------------------------------
    _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
    在BpServiceManager里又转了一次,8转16
    ------------------------------------------
    _aidl_ret_status = _aidl_data.readUtf8FromUtf16(&in_name);
    现在来到BnServiceManager继续转,16转8
    

    转来转去快晕了。总结就是,SM服务端都是操作的utf8,而libbinder客户端都是utf16。有修改的话需要注意下编码问题。

    也可能是由于这个转换问题,在服务端加了个服务名检查

    bool isValidServiceName(const std::string& name) {
        if (name.size() == 0) return false;
        if (name.size() > 127) return false;
    
        for (char c : name) {
            if (c == '_' || c == '-' || c == '.' || c == '/') continue;
            if (c >= 'a' && c <= 'z') continue;
            if (c >= 'A' && c <= 'Z') continue;
            if (c >= '0' && c <= '9') continue;
            return false;
        }
    
        return true;
    }
    

    5.4、服务保存的数据结构

    SM需要保存服务及其对应的信息,11前用的链表svc_list,成员是svc_info结构体;11后用的map,成员也是结构体

    frameworks/native/cmds/servicemanager/ServiceManager.h

        struct Service {
            sp<IBinder> binder; // not null
            bool allowIsolated;
            int32_t dumpPriority;
            bool hasClients = false; // notifications sent on true -> false.
            bool guaranteeClient = false; // forces the client check to true
            pid_t debugPid = 0; // the process in which this service runs
    
            // the number of clients of the service, including servicemanager itself
            ssize_t getNodeStrongRefCount();
        };
        using ServiceMap = std::map<std::string, Service>;
        ServiceMap mNameToService;
    

    这个Service结构体有了更多的信息和能力,getNodeStrongRefCount()方法可以获取该服务有多少个客户端。

    5.5、listServices返回值

    11之前的实现是客户端循环checkService,11之后是直接返回的是std::vector

    • 客户端

    frameworks/native/libs/binder/IServiceManager.cpp

    Vector<String16> ServiceManagerShim::listServices(int dumpsysPriority)
    {
        std::vector<std::string> ret;
        if (!mTheRealServiceManager->listServices(dumpsysPriority, &ret).isOk()) {
            return {};
        }
    
        Vector<String16> res;
        res.setCapacity(ret.size());
        for (const std::string& name : ret) {
            res.push(String16(name.c_str()));
        }
        return res;
    }
    
    • 服务端

    frameworks/native/cmds/servicemanager/ServiceManager.cpp

    Status ServiceManager::listServices(int32_t dumpPriority, std::vector<std::string>* outList) {
        size_t toReserve = 0;
        for (auto const& [name, service] : mNameToService) {
            (void) name;
    
            if (service.dumpPriority & dumpPriority) ++toReserve;
        }
    
        outList->reserve(toReserve);
        for (auto const& [name, service] : mNameToService) {
            (void) service;
    
            if (service.dumpPriority & dumpPriority) {
                outList->push_back(name);
            }
        }
    

    这里也可以看到字符编码的问题,客户端用的是utf16,而服务端用的是utf8

    • 顺便提一嘴dumpsys的画蛇添足的修改

    frameworks/native/cmds/dumpsys/dumpsys.cpp

         if (services.empty() || showListOnly) {
             services = listServices(priorityFlags, asProto);                                                                         
    ......
         if (N > 1) {
             for (size_t i=0; i<N; i++) {
                 sp<IBinder> service = sm_->checkService(services[i]);
    

    获取到服务列表后为什么再循环check一遍呢?我感觉是没有必要的。

    5.6、waitForService与IServiceCallback.aidl

    利用了匿名binder来传递回调,有兴趣可以自己看看。

    • 回调注册

    frameworks/native/libs/binder/IServiceManager.cpp

    sp<IBinder> ServiceManagerShim::waitForService(const String16& name16)
    {
    	 class Waiter : public android::os::BnServiceCallback {
            Status onRegistration(const std::string& /*name*/,
                                  const sp<IBinder>& binder) override {
    ......
         sp<Waiter> waiter = sp<Waiter>::make();
         if (Status status = mTheRealServiceManager->registerForNotifications(name, waiter);
    
    • 回调响应

    frameworks/native/cmds/servicemanager/ServiceManager.cpp

    Status ServiceManager::addService(const std::string& name, const sp<IBinder>& binder, bool allowIsolated, int32_t dumpPriority) {
    	auto it = mNameToRegistrationCallback.find(name);
        if (it != mNameToRegistrationCallback.end()) {
            for (const sp<IServiceCallback>& cb : it->second) {
                mNameToService[name].guaranteeClient = true;
                // permission checked in registerForNotifications
                cb->onRegistration(name, binder);
            }
        }
    
    • aidl及其生成的代码位置

    frameworks/native/libs/binder/aidl/android/os/IServiceCallback.aidl

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IServiceCallback.cpp

    5.7、IClientCallback.aidl

    IServiceManager.aidl中定义的接口,都是在#include <binder/IServiceManager.h>吗?答案为否。IClientCallback就是这样一个例子。

    想用registerClientCallback方法注册回调,需要直接使用#include <android/os/IServiceManager.h>拿到BpServiceManager实例,来通信。

    这个接口没有暴露在libbinder的IServiceManager中。

    这个回调用于监听某个服务有client,和IServiceCallback.aidl一样是匿名binder服务,一个例子LazyServiceRegistrar.cpp,可自行了解。

    代码路径

    frameworks/native/libs/binder/aidl/android/os/IClientCallback.aidl

    frameworks/native/libs/binder/LazyServiceRegistrar.cpp

    out/soong/.intermediates/frameworks/native/libs/binder/libbinder/android_arm_armv8-a_shared/gen/aidl/android/os/IClientCallback.cpp

    frameworks/native/cmds/servicemanager/ServiceManager.cpp

    5.8、RPC-Binder

    https://cs.android.com/android/_/android/platform/frameworks/native/+/5553ac45e0cb23102016858789603d6e12ab456b

    Minimal-ish change for basic binder RPC.
    
    This enables binder to work over sockets. The main change to core code
    is in 'Parcel' and 'BpBinder'. The Parcel format is now associated with
    the binder that it is either for or a reply from (we no longer have
    binder 'objects' for the kernel). BpBinder is extended to support
    talking over sockets (ideally, this would be a subclass, but
    IBinder::localBinder/remoteBinder mean there is a lot of code which
    presupposes what type of binder we have).
    
    In addition, we have a few new objects:
    - RpcServer - set this up to serve a connection
    - RpcConnection - symmetrical object handling dispatch to a known
        server/client
    - RpcAddress - (this will definitely change) randomly generated
        addresses - this might include things like host VM context, ip
        address, or similar in the future. In that case, the address
        generation should be cryptographically secure.
    - RpcState - this keeps track of known binders, their refcounts, and
        async transactions, and it understand the binder socket wire
        protocol
    
    The connection itself looks like N socket accepts to a server (the
    server might have M socket accepts back to the client for symmetrical
    connections, that is connections which need more than nested
    transactions). The number of these socket connections controls how many
    synchronous transactions can be made. Wherever possible, the behavior
    here seeks to mimick the binder driver, and some differences are
    documented in the code.
    
    After this CL merges, the future work I intend on completing includes:
    - support to work over vsock
    - performance benchmarking
    - optimization of the socket code here (may include delaying refcounts)
    - support to pass 'transitive' binders (pass a binder from one service
      to a different service, to let it setup a new connection). This task
      may be excluded from my efforts as a security hedge if I can manage.
    - fuzzer for this wire format
    - support for linkToDeath
    - support for transaction encryption
    - support for promoting from a weak pointer
    - handling SIGPIPE for dead connections
    - and many more! :)
    
    Bug: 167966510
    Test: binderRpcTest
    
    Change-Id: I276c6e312f584b57f4e7a14389ea4a1d63cfa2f4
    
    smoreland@google.com(作者)
    提交日期 3月24日 AM9:53
    

    可能是受了苹果和鸿蒙的刺激,谷歌也咔咔弄上了万物互联、分布式。这个提交大意是将binder通信拓展支持跨设备,后面有机会再研究。

    六、总结和参考资料

    SM经过aidl和libbinder改造后,对于开发者来说,修改会更加规范和省心

    新引入的特性展示了SM功能更多的可能性,可为特定需求提供思路,native aidl和匿名binder回调值得学习。

    关于aidl的使用可以参照官方文档:

    AIDL Overview

    android11之前的Native Binder可以参考老罗的书或者博客:

    Android进程间通信(IPC)机制Binder简要介绍和学习计划

    浅谈Service Manager成为Android进程间通信(IPC)机制Binder守护进程之路

    浅谈Android系统进程间通信(IPC)机制Binder中的Server和Client获得Service Manager接口之路

    Android系统进程间通信(IPC)机制Binder中的Server启动过程源代码分析

    Android系统进程间通信(IPC)机制Binder中的Client获得Server远程接口过程源代码分析

    本文来自博客园,作者:秋城,转载请注明原文链接:https://www.cnblogs.com/wanghongzhu/p/15551978.html

  • 相关阅读:
    BFC——块级格式化上下文
    深入浅出——float
    NodeJS 学习记录
    JavaScript高级程序设计 第六章 面向对象程序设计
    软件项目管理课感想
    第八周PSP 新折线图和饼图 个人时间管理
    第七周PSP 新折线图和饼图 个人时间管理
    Alpha、伪Beta 发布个人感想与体会
    ”单元测试“理解与感悟
    编程
  • 原文地址:https://www.cnblogs.com/wanghongzhu/p/15551978.html
Copyright © 2020-2023  润新知