Android MultiMedia框架——ALooper AHandler AMessage

huatechinfo
发布于 2021-3-31 13:47
浏览
0收藏

基于Android 9.0源码分析
在分析meidacodec framework层代码有看到ALooper、AHandler、AMessage这几个类,这主要分析下其内部原理

代码路径:frameworks/av/media/libstagefright/foundation/

ALooper

Android MultiMedia框架——ALooper AHandler AMessage-鸿蒙开发者社区首先看下ALooper使用示例

mLooper = new ALooper;
mLooper->setName("MediaCodec_looper");

mLooper->start(
  false,      // runOnCallingThread
  true,       // canCallJava
  ANDROID_PRIORITY_VIDEO);


1 初始化

ALooper::ALooper()
    : mRunningLocally(false) {
    // clean up stale AHandlers. Doing it here instead of in the destructor avoids
    // the side effect of objects being deleted from the unregister function recursively.
    gLooperRoster.unregisterStaleHandlers();
}


mRunningLocally用来区分ALooper执行线程是否在调用线程,start函数会进行复制;
清理过时的AHandler;
2 start

status_t ALooper::start(
        bool runOnCallingThread, bool canCallJava, int32_t priority) {
    if (runOnCallingThread) {
        {
            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;
}


runOnCallingThread参数用来区分ALooper执行时在调用者线程还是新创建线程;

runOnCallingThread为ture,则在调用者线程进行loop循环;

runOnCallingThread为false,创建LooperThread,并调用其run方法;

接着看下LooperThread

struct ALooper::LooperThread : public Thread {
    LooperThread(ALooper *looper, bool canCallJava)
        : Thread(canCallJava),
          mLooper(looper),
          mThreadId(NULL) {
    }

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

    //.........  
}


LooperThread继承于Thread类,其run函数会调用到threadLoop函数中;
threadLoop会调用ALooper的loop函数,进行消息的分发;
3 loop
先看下ALooper类的一些变量

private:
    friend struct AMessage;       // post()
 //封装消息 结构体
    struct Event {
        int64_t mWhenUs;
        sp<AMessage> mMessage;
    };

    Mutex mLock;   //锁
    Condition mQueueChangedCondition;

    AString mName;
 //event队列
    List<Event> mEventQueue;

    struct LooperThread;
    sp<LooperThread> mThread;  //新建的运行线程
    bool mRunningLocally;  //是否在调用者线程运行


Event结构体封装了AMessage及对应的时间,mEventQueue则对应接收到的消息队列。

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


mEventQueue如果内部空,没有元素则进行阻塞等待;
mEventQueue不为空,则获取第一个元素的时间,如果时间大于当前时间则表示没有到时间,则阻塞指定时间并返回;
如果whenUs不大于当前时间,则表示应该执行第一个任务了;
取出第一个event,并从mEventQueue中擦除,执行message deliver函数,稍后分析deliver;
ALooper loop函数负责从mEventQueue获取事件,并进行分发;

AMessage
先看使用示例

sp<AMessage> msg = new AMessage(kWhatInit, this);
msg->setMessage("on-frame-rendered", notify);
msg->post()


接着看下AMessage内部实现

AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
    : mWhat(what),
      mNumItems(0) {
    setTarget(handler);
}

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


初始化AMessage,设置其what值,并且和handler、Looper绑定关系。

status_t AMessage::post(int64_t delayUs) {
    sp<ALooper> looper = mLooper.promote();
    if (looper == NULL) {
        ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
        return -ENOENT;
    }

    looper->post(this, delayUs);
    return OK;
}


post获取ALooper指针,调用其post函数,将AMessage封装成Event,添加到mEventQueue队列中。

看下Amessage deliver函数,

void AMessage::deliver() {
    sp<AHandler> handler = mHandler.promote();
    if (handler == NULL) {
        ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
        return;
    }

    handler->deliverMessage(this);
}


deliver中获取AHandler指针,并将消息分发给AHandler处理;

AHandler

void AHandler::deliverMessage(const sp<AMessage> &msg) {
    onMessageReceived(msg);
    mMessageCounter++;

    if (mVerboseStats) {
        uint32_t what = msg->what();
        ssize_t idx = mMessages.indexOfKey(what);
        if (idx < 0) {
            mMessages.add(what, 1);
        } else {
            mMessages.editValueAt(idx)++;
        }
    }
}


AHandler接收到消息,调用onMessageReceived函数进行处理,类似java 中handleMessage。

C++层和java层区别(AHandler 和Handler区别)

 

  • 都实现了线程间通信机制
  • ALooper在start时,确定其执行线程是在调用者线程,还是新建线程,而Looper则在初始化(prepare)时确定其执行线程为本线程;
  • C++层发送消息可以等待获取回应,java层不能阻塞获取回应。
    ————————————————
    版权声明:本文为博主「zpy_公众号_码农修仙儿」的原创文章

分类
收藏
回复
举报
回复
    相关推荐