Android 12(S) Binder(二)


前面一節學習了ServiceManager這個特殊service的工作過程,這一節來看看普通service的工作過程。

就用media.extractor這個service來當例子!

 

1、服務的注冊及啟動

media.extractor這個service的注冊及啟動在 frameworks/av/services/mediaextractor/main_extractorservice.cpp

int main(int argc __unused, char** argv)
{

#if __has_feature(hwaddress_sanitizer)
    ALOGI("disable media.extractor memory limits (hwasan enabled)");
#else
    ALOGI("enable media.extractor memory limits");
    limitProcessMemory(
        "ro.media.maxmem", /* property that defines limit */
        SIZE_MAX, /* upper limit in bytes */
        20 /* upper limit as percentage of physical RAM */);
#endif

    signal(SIGPIPE, SIG_IGN);

    //b/62255959: this forces libutis.so to dlopen vendor version of libutils.so
    //before minijail is on. This is dirty but required since some syscalls such
    //as pread64 are used by linker but aren't allowed in the minijail. By
    //calling the function before entering minijail, we can force dlopen.
    android::report_sysprop_change();

    SetUpMinijail(kSystemSeccompPolicyPath, kVendorSeccompPolicyPath);

    strcpy(argv[0], "media.extractor");
    // 1、打開binder driver
    sp<ProcessState> proc(ProcessState::self());
    // 2、獲取ServiceManager
    sp<IServiceManager> sm = defaultServiceManager();
    // 3、實例化MediaExtractorService,並注冊到ServiceManager當中
    MediaExtractorService::instantiate();
    // 4、
    ProcessState::self()->startThreadPool();
    // 5、
    IPCThreadState::self()->joinThreadPool();
}

前面兩個步驟已經很熟悉了,就直接來看看后面三步在干什么:

a.  實例化MediaExtractorService,並注冊到ServiceManager當中

MediaExtractorService繼承與BinderService,instantiate聲明在 frameworks/native/libs/binder/include/binder/BinderService.h 中,同樣被包含在libbinder中

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();
    }
};

服務的注冊過程前面一節已經看過了,ServiceManager中的map會記錄下傳進來的這個BBinder對象。

b.  ProcessState::self()->startThreadPool()

void ProcessState::startThreadPool()
{
    AutoMutex _l(mLock);
    if (!mThreadPoolStarted) {
        mThreadPoolStarted = 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());
    }
}

class PoolThread : public Thread
{
public:
    explicit PoolThread(bool isMain)
        : mIsMain(isMain)
    {
    }

protected:
    virtual bool threadLoop()
    {
        IPCThreadState::self()->joinThreadPool(mIsMain);
        return false;
    }

    const bool mIsMain;
};

在ProcessState中開了一個PoolThread線程來執行 IPCThreadState::self()->joinThreadPool,但是看看main函數執行的最后一句代碼也是 IPCThreadState::self()->joinThreadPool,做了同樣的事情,接下來看看:

void IPCThreadState::joinThreadPool(bool isMain)
{
    LOG_THREADPOOL("**** THREAD %p (PID %d) IS JOINING THE THREAD POOL\n", (void*)pthread_self(), getpid());

    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);
}

這里有個do while循環用來檢查是否client端有信息發過來並且處理信息,同時不讓server進程結束。至於為什么調用了兩次 IPCThreadState::joinThreadPool,這可能是和server端的多線程處理有關,這邊后續再研究。

 


 

 

2、服務的獲取

注冊並啟動服務之后我們要使用服務,首先要用ServiceManager來獲取服務

這里摘一段MediaExtractorFactory中的代碼:

sp<IBinder> binder = defaultServiceManager()->getService(String16("media.extractor"));
sp<IMediaExtractorService> mediaExService(interface_cast<IMediaExtractorService>(binder));
sp<IMediaExtractor> ex;
mediaExService->makeExtractor(
       CreateIDataSourceFromDataSource(source),
       mime ? std::optional<std::string>(mime) : std::nullopt,
                    &ex);

先來看看getService

sp<IBinder> ServiceManagerShim::getService(const String16& name) const
{
    static bool gSystemBootCompleted = false;

    sp<IBinder> svc = checkService(name);
    if (svc != nullptr) return svc;

    const bool isVendorService =
        strcmp(ProcessState::self()->getDriverName().c_str(), "/dev/vndbinder") == 0;
    constexpr int64_t timeout = 5000;
    int64_t startTime = uptimeMillis();
    // Vendor code can't access system properties
    if (!gSystemBootCompleted && !isVendorService) {
#ifdef __ANDROID__
        char bootCompleted[PROPERTY_VALUE_MAX];
        property_get("sys.boot_completed", bootCompleted, "0");
        gSystemBootCompleted = strcmp(bootCompleted, "1") == 0 ? true : false;
#else
        gSystemBootCompleted = true;
#endif
    }
    // retry interval in millisecond; note that vendor services stay at 100ms
    const useconds_t sleepTime = gSystemBootCompleted ? 1000 : 100;

    ALOGI("Waiting for service '%s' on '%s'...", String8(name).string(),
          ProcessState::self()->getDriverName().c_str());

    int n = 0;
    while (uptimeMillis() - startTime < timeout) {
        n++;
        usleep(1000*sleepTime);

        sp<IBinder> svc = checkService(name);
        if (svc != nullptr) {
            ALOGI("Waiting for service '%s' on '%s' successful after waiting %" PRIi64 "ms",
                  String8(name).string(), ProcessState::self()->getDriverName().c_str(),
                  uptimeMillis() - startTime);
            return svc;
        }
    }
    ALOGW("Service %s didn't start. Returning NULL", String8(name).string());
    return nullptr;
}

核心方法就是checkService

sp<IBinder> ServiceManagerShim::checkService(const String16& name) const
{
    sp<IBinder> ret;
    if (!mTheRealServiceManager->checkService(String8(name).c_str(), &ret).isOk()) {
        return nullptr;
    }
    return ret;
}

調用的就是BpServiceManager的checkService方法,對外的接口參數是String16,而BpServiceManager接口參數為String8。經過Binder驅動的處理最終調用到server端的checkService

Status ServiceManager::checkService(const std::string& name, sp<IBinder>* outBinder) {
    *outBinder = tryGetService(name, false);
    // 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) {
            uid_t appid = multiuser_get_app_id(ctx.uid);
            bool isIsolated = appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END;

            if (isIsolated) {
                return nullptr;
            }
        }
        out = service->binder;
    }

    if (!mAccess->canFind(ctx, name)) {
        return nullptr;
    }

    if (!out && startIfNotFound) {
        tryStartService(name);
    }

    if (out) {
        // Setting this guarantee each time we hand out a binder ensures that the client-checking
        // loop knows about the event even if the client immediately drops the service
        service->guaranteeClient = true;
    }

    return out;
}

注意到在addService時,保存到map中的IBinder實際是一個BnBinder對象,那Server端getSevice獲得的也是一個BnBinder對象,返回給調用進程的就是這個BnBinder對象嗎?其實不是的。

來看看BpServiceManager的checkService代碼:

::android::binder::Status BpServiceManager::checkService(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());
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = _aidl_data.writeUtf8AsUtf16(name);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_ret_status = remote()->transact(BnServiceManager::TRANSACTION_checkService, _aidl_data, &_aidl_reply, 0);
  if (UNLIKELY(_aidl_ret_status == ::android::UNKNOWN_TRANSACTION && IServiceManager::getDefaultImpl())) {
     return IServiceManager::getDefaultImpl()->checkService(name, _aidl_return);
  }
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _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_ret_status = _aidl_reply.readNullableStrongBinder(_aidl_return);
  if (((_aidl_ret_status) != (::android::OK))) {
    goto _aidl_error;
  }
  _aidl_error:
  _aidl_status.setFromStatusT(_aidl_ret_status);
  return _aidl_status;
}

獲得RPC調用結果aidl_reply之后,最后面還有一句Parcel.readNullableStrongBinder,目的就是獲取代理

status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
    return unflattenBinder(val);
}

status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
    if (isForRpc()) {
        LOG_ALWAYS_FATAL_IF(mSession == nullptr, "RpcSession required to read from remote parcel");

        int32_t isNull;
        status_t status = readInt32(&isNull);
        if (status != OK) return status;

        sp<IBinder> binder;

        if (isNull & 1) {
            auto addr = RpcAddress::zero();
            status_t status = addr.readFromParcel(*this);
            if (status != OK) return status;
            binder = mSession->state()->onBinderEntering(mSession, addr);
        }

        return finishUnflattenBinder(binder, out);
    }

    // 這里可以拿到一個Handle
    const flat_binder_object* flat = readObject(false);

    if (flat) {
        switch (flat->hdr.type) {
            case BINDER_TYPE_BINDER: {
                sp<IBinder> binder =
                        sp<IBinder>::fromExisting(reinterpret_cast<IBinder*>(flat->cookie));
                return finishUnflattenBinder(binder, out);
            }
            case BINDER_TYPE_HANDLE: {
                // 創建一個BpBinder(handle)
                sp<IBinder> binder =
                    ProcessState::self()->getStrongProxyForHandle(flat->handle);
                return finishUnflattenBinder(binder, out);
            }
        }
    }
    return BAD_TYPE;
}

后面調用interface_cast 獲取一個 BpMediaExtractorService,這和之前SeviceManager是相同的。

template<typename INTERFACE>
inline sp<IMediaExtractorService> interface_cast(const sp<IBinder>& obj)
{
    return IMediaExtractorService::asInterface(obj);
}

::android::sp<IMediaExtractorService> IMediaExtractorService::asInterface(              
        const ::android::sp<::android::IBinder>& obj)               
{                                                                   
    ::android::sp<IMediaExtractorService> intr;                               
    if (obj != nullptr) {                                           
        intr = ::android::sp<IMediaExtractorService>::cast(                   
            obj->queryLocalInterface(IMediaExtractorService::descriptor));    
        if (intr == nullptr) {                                                                           
            intr = ::android::sp<BpMediaExtractorService>::make(obj);         
        }                                                           
    }                                                               
    return intr;                                                    
}

template<typename INTERFACE>
inline sp<IInterface> BnInterface<IMediaExtractorService>::queryLocalInterface(
        const String16& _descriptor)
{
    if (_descriptor == IMediaExtractorService::descriptor) return sp<IInterface>::fromExisting(this);
    return nullptr;
}

 


 

 

3、服務的使用

client使用就不再看了,看到server端時想到一個問題,IPCThreadState監聽消息,但是沒有指定由誰來執行。之前ServiceManager調用了setTheContextObject指定執行對象,但是media.extractor沒有執行這一句,但是仔細看代碼,似乎是從client發送的數據中可以找到target

            binder_transaction_data_secctx tr_secctx;
            binder_transaction_data& tr = tr_secctx.transaction_data;
            // ......
            if (cmd == (int) BR_TRANSACTION_SEC_CTX) {
                result = mIn.read(&tr_secctx, sizeof(tr_secctx));
            } else {
                result = mIn.read(&tr, sizeof(tr));
                tr_secctx.secctx = 0;
            }
            // ......
            if (tr.target.ptr) {
                // We only have a weak reference on the target object, so we must first try to
                // safely acquire a strong reference before doing anything else with it.
                if (reinterpret_cast<RefBase::weakref_type*>(
                        tr.target.ptr)->attemptIncStrong(this)) {
                    error = reinterpret_cast<BBinder*>(tr.cookie)->transact(tr.code, buffer,
                            &reply, tr.flags);
                    reinterpret_cast<BBinder*>(tr.cookie)->decStrong(this);
                } else {
                    error = UNKNOWN_TRANSACTION;
                }

            } else {
                error = the_context_object->transact(tr.code, buffer, &reply, tr.flags);
            }

 

到這里binder service框架大致就了解了,之后看到相關內容也更加從容,binder驅動之后有空再學習。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM