IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    Android Native服务注册流程概述

    FranzKafka95发表于 2023-09-05 06:20:41
    love 0
    Read Time:9 Minute, 22 Second

    在Android系统中,Java Framework层的诸多服务都通过Binder与Native层的服务进行通信;基于此再对外提供接口给各个Java应用。在这种通信模式下,两端遵守的是C-S架构。一般而言Native服务会作为Server端而存在。

    Native服务作为Server端,是需要注册到serviceManager成为服务之后才能被系统中的各个Client进行获取、连接与使用的。本篇博客将以Android12的源码为基础,简单分析一下Android Native服务的注册流程。

    这里我们先以CameraService为例做一个分析讲解。

    CameraService在Native层主要分为两个部分:一个是以binary形式而存在的cameraserver;另外一个则是以共享库形式而存在的libcameraservice。前者作为CamearService的程序入口,而后者则是具体的逻辑主体实现,且后者是前者的依赖项之一,由前者负责调用。其服务注册的主体部分,位于cameraserver内,总体涉及的到源码路径如下:

    //cameraserver
    frameworks/av/camera/cameraserver
    
    //libcameraservice
    frameworks/av/services/camera/libcameraservice

    我们找到cameraserver启动的源码文件:main_cameraserver.cpp,其源码内容非常精简,具体内容如下所示:

    #define LOG_TAG "cameraserver"
    //#define LOG_NDEBUG 0
    
    #include "CameraService.h"
    #include <hidl/HidlTransportSupport.h>
    
    using namespace android;
    
    int main(int argc __unused, char** argv __unused)
    {
        signal(SIGPIPE, SIG_IGN);
    
        // Set 5 threads for HIDL calls. Now cameraserver will serve HIDL calls in
        // addition to consuming them from the Camera HAL as well.
        hardware::configureRpcThreadpool(5, /*willjoin*/ false);
    
        sp<ProcessState> proc(ProcessState::self());
        sp<IServiceManager> sm = defaultServiceManager();
        ALOGI("ServiceManager: %p", sm.get());
        CameraService::instantiate();
        ALOGI("ServiceManager: %p done instantiate", sm.get());
        ProcessState::self()->startThreadPool();
        IPCThreadState::self()->joinThreadPool();
    }

    在cameraserver的服务启动过程中,就包含了服务注册的部分,主要包含以下几个步骤:

    1.获取ProcessState对象,用于连接底层binder驱动;

    2.获取ServiceManager实例,通过父类instantiate接口发布到Android系统中;

    3.启动binder线程池,该线程池用于处理Binder IPC通信;

    4.线程执行,此时可以处理Binder IPC请求;

    获取ProcessState对象

    这一步的目的其实是为了通过libbinder连接底层binder驱动(/dev/binder),涉及到的源码文件如下:

    frameworks/native/libs/binder/include/binder/ProcessState.h //头文件
    frameworks/native/libs/binder/ProcessState.cpp //源码文件

    ProcessState类在源码中是一个单例实现,部分关键源码如下:

    //frameworks/native/libs/binder/ProcessState.cpp
    
    #ifdef __ANDROID_VNDK__
    const char* kDefaultDriver = "/dev/vndbinder";
    #else
    const char* kDefaultDriver = "/dev/binder";
    #endif
    
    //native 服务使用该接口进行binder初始化,如
    sp<ProcessState> ProcessState::self()
    {
        return init(kDefaultDriver, false /*requireDefault*/);
    }
    //init 函数作为主入口
    sp<ProcessState> ProcessState::init(const char *driver, bool requireDefault)
    {
        [[clang::no_destroy]] static sp<ProcessState> gProcess;
        [[clang::no_destroy]] static std::mutex gProcessMutex;
        if (driver == nullptr) {
            std::lock_guard<std::mutex> l(gProcessMutex);
            return gProcess;
        }
        [[clang::no_destroy]] static std::once_flag gProcessOnce;
        std::call_once(gProcessOnce, [&](){
            if (access(driver, R_OK) == -1) {
                ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
                driver = "/dev/binder";
            }
            std::lock_guard<std::mutex> l(gProcessMutex);
            //use sp<CLASS>::make to construct an sp object
            gProcess = sp<ProcessState>::make(driver);
        });
        if (requireDefault) {
            // Detect if we are trying to initialize with a different driver, and
            // consider that an error. ProcessState will only be initialized once above.
            LOG_ALWAYS_FATAL_IF(gProcess->getDriverName() != driver,
                                "ProcessState was already initialized with %s,"
                                " can't initialize with %s.",
                                gProcess->getDriverName().c_str(), driver);
        }
        return gProcess;
    }
    
    //ProcessState constructor
    ProcessState::ProcessState(const char *driver)
        : mDriverName(String8(driver))
        , mDriverFD(open_driver(driver))
        , mVMStart(MAP_FAILED)
        , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER)
        , mThreadCountDecrement(PTHREAD_COND_INITIALIZER)
        , mExecutingThreadsCount(0)
        , mWaitingForThreads(0)
        , mMaxThreads(DEFAULT_MAX_BINDER_THREADS)
        , mStarvationStartTimeMs(0)
        , mThreadPoolStarted(false)
        , mThreadPoolSeq(1)
        , mCallRestriction(CallRestriction::NONE)
    {
        if (mDriverFD >= 0) {
            // mmap the binder, providing a chunk of virtual address space to receive transactions.
            mVMStart = mmap(nullptr, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
            if (mVMStart == MAP_FAILED) {
                // *sigh*
                ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
                close(mDriverFD);
                mDriverFD = -1;
                mDriverName.clear();
            }
        }
    #ifdef __ANDROID__
        LOG_ALWAYS_FATAL_IF(mDriverFD < 0, "Binder driver '%s' could not be opened.  Terminating.", driver);
    #endif
    }
    //构造函数列表初始化中通过open_driver连接驱动
    static int open_driver(const char *driver)
    {
        int fd = open(driver, O_RDWR | O_CLOEXEC);
        if (fd >= 0) {
            int vers = 0;
            status_t result = ioctl(fd, BINDER_VERSION, &vers);
            if (result == -1) {
                ALOGE("Binder ioctl to obtain version failed: %s", strerror(errno));
                close(fd);
                fd = -1;
            }
            if (result != 0 || vers != BINDER_CURRENT_PROTOCOL_VERSION) {
              ALOGE("Binder driver protocol(%d) does not match user space protocol(%d)! ioctl() return value: %d",
                    vers, BINDER_CURRENT_PROTOCOL_VERSION, result);
                close(fd);
                fd = -1;
            }
            size_t maxThreads = DEFAULT_MAX_BINDER_THREADS;
            result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads);
            if (result == -1) {
                ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno));
            }
            uint32_t enable = DEFAULT_ENABLE_ONEWAY_SPAM_DETECTION;
            result = ioctl(fd, BINDER_ENABLE_ONEWAY_SPAM_DETECTION, &enable);
            if (result == -1) {
                ALOGD("Binder ioctl to enable oneway spam detection failed: %s", strerror(errno));
            }
        } else {
            ALOGW("Opening '%s' failed: %s\n", driver, strerror(errno));
        }
        return fd;
    }

    在Native Service启动时,我们通过ProcessState::self()获取到单例对象,再通过 ProcessState 的拷贝构造函数赋值给proc,从而得到名为proc指向 ProcessState 的智能指针。

    获取ServiceManager实例

    获取IServiceManager实例是为了后续将服务添加到ServiceManager中,这一步涉及到的源码文件如下:

    /frameworks/native/libs/binder/include/binder/IServiceManager.h  //头文件
    /frameworks/native/libs/binder/IServiceManager.cpp  //源文件

    IServiceManager自身也是单例实现,其实现部分的代码如下:

    using AidlServiceManager = android::os::IServiceManager;
    sp<IServiceManager> defaultServiceManager()
    {
    //通过std::call_once确保在多线程并行调用情况下也只会执行一次
        std::call_once(gSmOnce, []() {
            sp<AidlServiceManager> sm = nullptr;
            while (sm == nullptr) {
                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);
                }
            }
            gDefaultServiceManager = sp<ServiceManagerShim>::make(sm);
        });
    
        return gDefaultServiceManager;
    }

    在defaultServiceManager函数实现中,首先通过std::call_once来确保多线程并发调用的情况下函数主体只会调用一次,并且通过while循环来确保在serviceManager进程启动慢时通过sleep休眠来暂缓获取的过程,其中最为关键的接口在于getContextObject函数,其具体内容如下:

    
    sp<IBinder> ProcessState::getContextObject(const sp<IBinder>& /*caller*/)
    {
        sp<IBinder> context = getStrongProxyForHandle(0);
    
        if (context) {
            // The root object is special since we get it directly from the driver, it is never
            // written by Parcell::writeStrongBinder.
            internal::Stability::markCompilationUnit(context.get());
        } else {
            ALOGW("Not able to get context object on %s.", mDriverName.c_str());
        }
        return context;
    }
    
    sp<IBinder> ProcessState::getStrongProxyForHandle(int32_t handle)
    {
        sp<IBinder> result;
    
        AutoMutex _l(mLock);
    
        handle_entry* e = lookupHandleLocked(handle);
      
        if (e != nullptr) {
            IBinder* b = e->binder;
            if (b == nullptr || !e->refs->attemptIncWeak(this)) {
                if (handle == 0) {
                    .....
                    IPCThreadState* ipc = IPCThreadState::self();
                    CallRestriction originalCallRestriction = ipc->getCallRestriction();
                    ipc->setCallRestriction(CallRestriction::NONE);
                    Parcel data;
                    status_t status = ipc->transact(
                            0, IBinder::PING_TRANSACTION, data, nullptr, 0);
                    ipc->setCallRestriction(originalCallRestriction);
                    if (status == DEAD_OBJECT)
                       return nullptr;
                }
                sp<BpBinder> b = BpBinder::create(handle);
                e->binder = b.get();
                if (b) e->refs = b->getWeakRefs();
                result = b;
            } else {
                result.force_set(b);
                e->refs->decWeak(this);
            }
        }
        return result;
    }

    getContextObject中通过getStrongProxyForHandle函数来获取IBinder的sp对象,而其实际上是通过BpBinder::create(handle)来进行获取的,不过在这一步得到的对象是指向BpBinder的sp,我们将上面的代码进行简化,可以得到如下的内容:

    //原始内容
    sp<AidlServiceManager> sm = interface_cast<AidlServiceManager>(ProcessState::self()->getContextObject(nullptr))
    
    //简化内容
    sp<android::os::IServiceManager> sm = interface_cast<android::os::IServiceManager>(BpBinder::create(0))

    这里通过interface_cast将BpBinder::create(0)转换为了android::os::IServiceManager,具体的转换过程可以看看interface_cast的源码实现,其本身属于类模板函数,源码位于frameworks/native/libs/binder/include/binder/IInterface.h内,具体内容如下:

    /**
     * If this is a local object and the descriptor matches, this will return the
     * actual local object which is implementing the interface. Otherwise, this will
     * return a proxy to the interface without checking the interface descriptor.
     * This means that subsequent calls may fail with BAD_TYPE.
     */
    template<typename INTERFACE>
    inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
    {
        return INTERFACE::asInterface(obj);
    }

    我们将其中的INTERFACE模板做相应替换后,可以得到如下内容:

    sp<android::os::IServiceManager> sm = android::os::IServiceManager::asInterface(BpBinder::create(0))

    我们再关注一下IServiceManager类的内部,可以看到如下方法:

    /**
    * Retrieve an existing service, blocking for a few seconds
    * if it doesn't yet exist.
    */
    virtual sp<IBinder>         getService( const String16& name) const = 0;
    
    /**
    * Retrieve an existing service, non-blocking.
    */
    virtual sp<IBinder>         checkService( const String16& name) const = 0;
    
    /**
    * Register a service.
    */
    // NOLINTNEXTLINE(google-default-arguments)
    virtual status_t addService(const String16& name, const sp<IBinder>& service,
                                    bool allowIsolated = false,
                                    int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) = 0;
    
    /**
    * Return list of all existing services.
    */
    // NOLINTNEXTLINE(google-default-arguments)
    virtual Vector<String16> listServices(int dumpsysFlags = DUMP_FLAG_PRIORITY_ALL) = 0;
    
    /**
    * Efficiently wait for a service.
    *
    * Returns nullptr only for permission problem or fatal error.
    */
    virtual sp<IBinder> waitForService(const String16& name) = 0;
    

    这部分方法都是与服务获取、使用相关的,且都属于纯虚函数,具体的实现逻辑在其子类ServiceManagerShim内。

    服务注册

    接下来就是服务注册了,这部分可能也是最让人困惑的。从整个代码调用上来看,服务注册最直观的调用应该属于CameraService::instantiate();这一句,但即使我们翻遍CameraService的源码也是无法找到 instantiate的具体实现的,原因就在于 instantiate 方法其实是来自于父类的public方法,我们在相应的头文件内可以看到:

    //
    class CameraService :
        public BinderService<CameraService>,
        public virtual ::android::hardware::BnCameraService,
        public virtual IBinder::DeathRecipient,
        public virtual CameraProviderManager::StatusListener
    {
      ......
    }

    事实上instantiate方法就是类模板BinderService的公有方法 ,其代码实现如下:

    //frameworks/native/libs/binder/include/binder/BinderService.h
    template<typename SERVICE>
    class BinderService
    {
    public:
        static status_t publish(bool allowIsolated = false,
                                int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
            sp<IServiceManager> sm(defaultServiceManager());
            return sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,dumpFlags);
        }
    
        static void publishAndJoinThreadPool(
                bool allowIsolated = false,
                int dumpFlags = IServiceManager::DUMP_FLAG_PRIORITY_DEFAULT) {
            publish(allowIsolated, dumpFlags);
            joinThreadPool();
        }
    
        static void instantiate() { publish(); }
    
        static status_t shutdown() { return NO_ERROR; }
    
    private:
        static void joinThreadPool() {
            sp<ProcessState> ps(ProcessState::self());
            ps->startThreadPool();
            ps->giveThreadPoolName();
            IPCThreadState::self()->joinThreadPool();
        }
    };
    

    这里 instantiate方法其实就是封装了一下publish方法,在publish方法内,通过IServiceManager的addService方法添加服务,这里有两个小细节是需要注意的:一个是我们实现的服务必须要实现getServiceName方法,且该方法必须为public static方法;另一个是我们实现的服务必须要显式实现默认构造函数,且必须为public可见,新手一般会在这两个地方踩坑。具体原因,我们只需要看sm->addService(String16(SERVICE::getServiceName()), new SERVICE(), allowIsolated,dumpFlags);这一行就知道为什么了。

    启动与加入Binder线程池

    在将服务注册到ServiceManager之后,我们需要启动服务侧的binder线程池,由于是多Client并发请求的,线程池是必须的,

    // 启动binder线程池
    ProcessState::self()->startThreadPool();
    // 加入到Binder线程池
    IPCThreadState::self()->joinThreadPool();

    首先看看startThreadPool内的实现:

    //frameworks/native/libs/binder/ProcessState.cpp
    void ProcessState::startThreadPool()
    {
        AutoMutex _l(mLock);
        if (!mThreadPoolStarted) {
            mThreadPoolStarted = true;
            //通过true设定为主线程
            spawnPooledThread(true);
        }
    }
    
    void ProcessState::spawnPooledThread(bool isMain)
    {
        if (mThreadPoolStarted) {
            String8 name = makeBinderThreadName();
            ALOGV("Spawning new pooled thread, name=%s\n", name.string());
            sp<Thread> t = sp<PoolThread>::make(isMain);
            t->run(name.string());
        }
    }
    
    //PoolThread为内部类,继承自Android自行封装的Thread类
    class PoolThread : public Thread
    {
    public:
        explicit PoolThread(bool isMain)
            : mIsMain(isMain)
        {
        }
    
    protected:
        virtual bool threadLoop()
        {
            IPCThreadState::self()->joinThreadPool(mIsMain);
            return false;
        }
    
        const bool mIsMain;
    };
    

    从其实现我们可以看到,startThreadPool调用就会开启线程执行,并且是作为主线程执行;接着我们看看joinThreadPool的实现:

    //frameworks/native/libs/binder/IPCThreadState.cpp
    void IPCThreadState::joinThreadPool(bool isMain)
    {
        LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());
        //设定线程状态,mOut属于Parcel对象
        mOut.writeInt32(isMain ? BC_ENTER_LOOPER : BC_REGISTER_LOOPER);
    
        mIsLooper = true;
        status_t result;
        do {
            processPendingDerefs();
            // now get the next command to be processed, waiting if necessary
            result = getAndExecuteCommand();
    
            if (result < NO_ERROR && result != TIMED_OUT && result != -ECONNREFUSED && result != -EBADF) {
                LOG_ALWAYS_FATAL("getAndExecuteCommand(fd=%d) returned unexpected error %d, aborting",
                      mProcess->mDriverFD, result);
            }
    
            // Let this thread exit the thread pool if it is no longer
            // needed and it is not the main process thread.
            if(result == TIMED_OUT && !isMain) {
                break;
            }
        } while (result != -ECONNREFUSED && result != -EBADF);
    
        LOG_THREADPOOL("**** THREAD %p (PID %d) IS LEAVING THE THREAD POOL err=%d\n",
            (void*)pthread_self(), getpid(), result);
    
        mOut.writeInt32(BC_EXIT_LOOPER);
        mIsLooper = false;
        talkWithDriver(false);
    }
    
    //从binder中获取command并执行
    status_t IPCThreadState::getAndExecuteCommand()
    {
        status_t result;
        int32_t cmd;
    
        result = talkWithDriver();
        if (result >= NO_ERROR) {
            //mIn属于Parcel对象,从中获取binder driver传递的command
            size_t IN = mIn.dataAvail();
            if (IN < sizeof(int32_t)) return result;
            cmd = mIn.readInt32();
            IF_LOG_COMMANDS() {
                alog << "Processing top-level Command: "
                     << getReturnString(cmd) << endl;
            }
    
            pthread_mutex_lock(&mProcess->mThreadCountLock);
            mProcess->mExecutingThreadsCount++;
            if (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads &&
                    mProcess->mStarvationStartTimeMs == 0) {
                mProcess->mStarvationStartTimeMs = uptimeMillis();
            }
            pthread_mutex_unlock(&mProcess->mThreadCountLock);
    
            result = executeCommand(cmd);
    
            pthread_mutex_lock(&mProcess->mThreadCountLock);
            mProcess->mExecutingThreadsCount--;
            if (mProcess->mExecutingThreadsCount < mProcess->mMaxThreads &&
                    mProcess->mStarvationStartTimeMs != 0) {
                int64_t starvationTimeMs = uptimeMillis() - mProcess->mStarvationStartTimeMs;
                if (starvationTimeMs > 100) {
                    ALOGE("binder thread pool (%zu threads) starved for %" PRId64 " ms",
                          mProcess->mMaxThreads, starvationTimeMs);
                }
                mProcess->mStarvationStartTimeMs = 0;
            }
    
            // Cond broadcast can be expensive, so don't send it every time a binder
            // call is processed. b/168806193
            if (mProcess->mWaitingForThreads > 0) {
                pthread_cond_broadcast(&mProcess->mThreadCountDecrement);
            }
            pthread_mutex_unlock(&mProcess->mThreadCountLock);
        }
        return result;
    }
    

    整个实现过程中最为关键的函数为executeCommand,其内部实现简单来讲就是根据mIn传递的binder驱动指令(BR_XXX)执行相关动作,再将执行结果(BC_XXX)通过mOut返回至binder驱动。

    总结

    这里我们再简单总结一下如何实现一个安卓Native Service:

    1.在头文件中include以下头文件:

    #include <binder/IPCThreadState.h>
    #include <binder/IServiceManager.h>
    #include <binder/BinderService.h>

    声明MyOwnService类,并使其继承public BinderService<MyOwnService>,并将BinderService<MyOwnService>设置为友元类;并实现如下函数:

    MyOwnService();//默认构造函数
    static char const* getServiceName();  //用于定义service名称

    如果我们需要在MyOwnService中实现AIDL接口,如IMyOwnService.aidl,需要继承BnMyOwnService类,并覆写 IMyOwnService.aidl中所定义的接口。

    如果需要处理BinderDied这种异常情况,则需要继承IBinder::DeathRecipient,覆写binderDied接口。如下所示:

    //for service register
    #include <binder/IPCThreadState.h>
    #include <binder/IServiceManager.h>
    #include <binder/BinderService.h>
    
    class MyOwnService :public BinderService<MyOwnService>,public BnMyOwnService,public 
                         virtual IBinder::DeathRecipient{
    public:
          MyOwnService();
          static char const* getServiceName();
          .....
    private:
          void binderDied(const wp<IBinder>& who) override;
          .....
    }

    2.Main函数编写:

    void main(int argc,char * argv[])
    {
       configureRpcThreadpool(3, false /* callerWillJoin */);
       sp<ProcessState> proc(ProcessState::self());
       sp<IServiceManager> sm = defaultServiceManager();
       myOwnService::instantiate();
    
    //这两句一定放在服务准备工作完成之后,否则后续的语句不会执行
       ProcessState::self()->startThreadPool();
       IPCThreadState::self()->joinThreadPool();
    }

    至此服务就能注册到ServiceManager中,并可进行binder通信了。

    如果我们要在远端获取service,在Java层可以采用如下方式:

    import android.os.IBinder;
    import android.os.ServiceManager;
    
    //字符串必须与service实现的getServiceName接口所返回的一致
    IBinder binder = ServiceManager.getService("myOwnService");
    //将IBinder通过asInterface转换为具体的service远端对象
    mMyOwnService = IMyOwnService.Stub.asInterface(binder);

    关于IMyOwnService.Stub.asInterface接口的由来,可以参考我的另一篇文章。

    Happy
    Happy
    1 100 %
    Sad
    Sad
    0 0 %
    Excited
    Excited
    0 0 %
    Sleepy
    Sleepy
    0 0 %
    Angry
    Angry
    0 0 %
    Surprise
    Surprise
    0 0 %

    The post Android Native服务注册流程概述 first appeared on FranzKafka Blog.



沪ICP备19023445号-2号
友情链接