Android MultiMedia框架——ALooper AHandler AMessage

Posted VNanyesheshou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android MultiMedia框架——ALooper AHandler AMessage相关的知识,希望对你有一定的参考价值。

Android MultiMedia框架——OMX服务启动
Android MultiMedia框架——OMXPlugin
Android MultiMedia框架——MediaCodec编码(上)
Android MultiMedia框架——MediaCodec编码(下)
Android MultiMedia框架——ACodec加载OMX
Android MultiMedia框架——ALooper AHandler AMessage

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

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

ALooper

首先看下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();

  1. mRunningLocally用来区分ALooper执行线程是否在调用线程,start函数会进行复制;
  2. 清理过时的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;

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

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

  2. 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;

  1. mEventQueue如果内部空,没有元素则进行阻塞等待;
  2. mEventQueue不为空,则获取第一个元素的时间,如果时间大于当前时间则表示没有到时间,则阻塞指定时间并返回;
  3. 如果whenUs不大于当前时间,则表示应该执行第一个任务了;
  4. 取出第一个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层不能阻塞获取回应。

以上是关于Android MultiMedia框架——ALooper AHandler AMessage的主要内容,如果未能解决你的问题,请参考以下文章

Android MultiMedia框架——OMXPlugin

Android MultiMedia框架——ACodec加载OMX

Android MultiMedia框架——ALooper AHandler AMessage

Android MultiMedia框架——MediaCodec编码(下)

Android MultiMedia框架——mediaserver启动

Android MultiMedia框架——mediaserver启动