Multimedia Alooper 機制分析

Multimedia Alooper 機制分析,android 底層的錄制和播放都會用到ALooper,AHandler和AMessage,這個和上一篇講的looper有什麼不一樣呢?其實作用是差不多的,隻是實現的方式不一樣而已。

1、looper線程的創建

status_t ALooper::start(
        bool runOnCallingThread, bool canCallJava, int32_t priority) {
    if (runOnCallingThread) {  //如果傳入的參數為true,就會使用當前的線程作為looper線程,否則下面會再創建一個線程作為looper線程
        {
            Mutex::Autolock autoLock(mLock);

            if (mThread != NULL || mRunningLocally) {
                return INVALID_OPERATION;
            }

            mRunningLocally = true;
        }

        do {
        } while (loop());

        return OK;
    }

    Mutex::Autolock autoLock(mLock);

    if (mThread != NULL || mRunningLocally) {
        return INVALID_OPERATION;
    }

    mThread = new LooperThread(this, canCallJava);

    status_t err = mThread->run(
            mName.empty() ? "ALooper" : mName.c_str(), priority);
    if (err != OK) {
        mThread.clear();
    }

    return err;
}

調用ALooper的start()函數後,就會進入loop,也就是一直循環調用loop()函數,如果傳入的第一個參數是true,就會讓當前線程變成looper線程,否則會創建一個新的looper線程。

   virtual bool threadLoop() {
        return mLooper->loop();
    }

其實就是創建一個普通線程,然後循環調用loop()函數。

2、AHandler和Alooper進行綁定

ALooper::handler_id ALooper::registerHandler(const sp &handler) {
    return gLooperRoster.registerHandler(this, handler);
}

調用ALooper的registerHandler()接口後就能將AHandler對象和該ALooper對象進行綁定瞭。

ALooper::handler_id ALooperRoster::registerHandler(
        const sp looper, const sp &handler) {
    Mutex::Autolock autoLock(mLock);

    if (handler->id() != 0) {
        CHECK(!"A handler must only be registered once.");
        return INVALID_OPERATION;
    }

    HandlerInfo info;
    info.mLooper = looper;
    info.mHandler = handler;
    ALooper::handler_id handlerID = mNextHandlerID++;
    mHandlers.add(handlerID, info);

    handler->setID(handlerID, looper);

    return handlerID;
}

gLooperRoster 可以認為它是一個全局變量,主要的作用是管理AHandler和ALooper,返回的handlerID十分重要,L版本之前可以通過這個id找到對應的AHandler。

3、AMessage怎麼和AHandler進行綁定

AMessage::AMessage(uint32_t what, const sp &handler)
    : mWhat(what),
      mNumItems(0) {
    setTarget(handler);
}
void AMessage::setTarget(const sp &handler) {
    if (handler == NULL) {
        mTarget = 0;
        mHandler.clear();
        mLooper.clear();
    } else {
        mTarget = handler->id();
        mHandler = handler->getHandler();
        mLooper = handler->getLooper();
    }
}

創建AMessage 對象的時候可以把對應AHandler對象傳入進行綁定,或者通過setTarget()函數進行綁定。

4、AMessage從發送到處理流程

1)異步消息,不需要等待執行結果

post()到ALooper後,會把AMessage插入到mEventQueue隊列中,此時把Message封裝到Event中。

void ALooper::post(const sp &msg, int64_t delayUs) {
    Mutex::Autolock autoLock(mLock);

    int64_t whenUs;
    if (delayUs > 0) {
        whenUs = GetNowUs() + delayUs;
    } else {
        whenUs = GetNowUs();
    }

    List::iterator it = mEventQueue.begin();
    while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
        ++it;
    }

    Event event;
    event.mWhenUs = whenUs;
    event.mMessage = msg;

    if (it == mEventQueue.begin()) {   //如果需要插入到隊列頭部,則發一次信號
        mQueueChangedCondition.signal();
    }

    mEventQueue.insert(it, event);
}

上面的post()後,會把Event(AMessage)插入event隊列中,如果插在頭部,會發一次信號到loop()中。

bool ALooper::loop() {
    Event event;

    {
        Mutex::Autolock autoLock(mLock);
        if (mThread == NULL && !mRunningLocally) {
            return false;
        }
        if (mEventQueue.empty()) {
            mQueueChangedCondition.wait(mLock);
            return true;
        }
        int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
        int64_t nowUs = GetNowUs();

        if (whenUs > nowUs) {
            int64_t delayUs = whenUs - nowUs;
            mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll); //收到信號或者等待超時後會返回

            return true;
        }

        event = *mEventQueue.begin();
        mEventQueue.erase(mEventQueue.begin());
    }

    event.mMessage->deliver();

    // NOTE: It's important to note that at this point our "ALooper" object
    // may no longer exist (its final reference may have gone away while
    // delivering the message). We have made sure, however, that loop()
    // won't be called again.

    return true;
}

收到信號後,mQueueChangedCondition.waitRelative()會返回true,重新跑一次loop(),這時如果隊列中的第一個消息需要馬上處理(whenUs > nowUs 不成立),會繼續往下跑,從隊列中取出第一個消息,並從隊列移除,調用event.mMessage->deliver();就走到瞭後面AHandler的消息處理流程。

2)同步消息,需要等待消息處理完成之後才返回


和異步消息的流程差不多,隻不過多瞭等帶AHandler處理完消息後並postReply()後才會往下走,並且得到一個AMessage類型返回結果。AMessage可以保存很多類型的數據,通過的形式,在傳遞參數時,使用起來十分方便,有興趣的同學閱讀源碼深入瞭解。

對比一下:

Looper 通過epoll_wait()等待事件觸發或者超時。

int eventCount = epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis);

ALooper通過waitRelative()等待信號或者超時。

mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);

You May Also Like