ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android 12(S) ALooper AHandler AMessage(一)

2022-03-25 14:01:00  阅读:208  来源: 互联网

标签:12 return handler looper AMessage ALooper Android AHandler


卧榻之侧岂容他人酣睡,到现在ALooper AHandler AMessage的工作原理一直都没搞懂,很慌!看他们的路径都在libstagefright/foundation下,作为一个foundation怎么能不去搞明白,今天必须解决他们!

相关代码路径:

AHandler.cpp - OpenGrok cross reference for /frameworks/av/media/libstagefright/foundation/AHandler.cpp (aospxref.com)

ALooper.cpp - OpenGrok cross reference for /frameworks/av/media/libstagefright/foundation/ALooper.cpp (aospxref.com)

ALooperRoster.cpp - OpenGrok cross reference for /frameworks/av/media/libstagefright/foundation/ALooperRoster.cpp (aospxref.com)

AMessage.cpp - OpenGrok cross reference for /frameworks/av/media/libstagefright/foundation/AMessage.cpp (aospxref.com)

从哪里开始?就从他们怎么使用开始!然后顺着看

 

(一)正常使用这三剑客时,会先去创建一个ALooper以及AHandler,接着把AHandler注册到ALooper当中

1、ALooper构造函数

ALooperRoster gLooperRoster;
ALooper::ALooper()
    : mRunningLocally(false) {
    gLooperRoster.unregisterStaleHandlers();
}

从这里可以看到ALooper中维护了一个全局变量gLooperRoster

void ALooperRoster::unregisterStaleHandlers() {

    Vector<sp<ALooper> > activeLoopers;
    {
        Mutex::Autolock autoLock(mLock);

        for (size_t i = mHandlers.size(); i > 0;) {
            i--;
            const HandlerInfo &info = mHandlers.valueAt(i);

            sp<ALooper> looper = info.mLooper.promote();
            if (looper == NULL) {
                ALOGV("Unregistering stale handler %d", mHandlers.keyAt(i));
                mHandlers.removeItemsAt(i);
            } else {
                activeLoopers.add(looper);
            }
        }
    }
}

unregisterStaleHandlers方法用来移除已经被释放的Alooper

2、AHandler构造函数

    AHandler()
        : mID(0),
          mVerboseStats(false),
          mMessageCounter(0) {
    }

这个构造函数显得更为简单,初始化了Ahandler的id信息mID,以及持有的message的数量mMessageCounter

3、给ALooper注册Ahandler

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

将ALooper自身和AHandler绑定,一并交给ALooperRoster来管理

ALooper::handler_id ALooperRoster::registerHandler(
        const sp<ALooper> &looper, const sp<AHandler> &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;
}

KeyedVector<ALooper::handler_id, HandlerInfo> mHandlers;

ALooperRoster::registerHandler做了三件事:

a. 将ALooper和AHandler打包为一个HandlerInfo

b. 用一个递增的id mNextHandlerID,将HandlerInfo以KeyedVector的形式管理起来

c. 调用AHandler的setID方法,更新AHandler的id,通知AHandler持有它的ALooper是谁

在反过来看这个方法的一开头判断AHandler的id是否为0,这个就是用来防止AHandler被注册到多个ALooper当中去,意思就是一个ALooper可以有多个AHandler,但是一个AHandler不能注册到多个ALooper中去

    inline void setID(ALooper::handler_id id, const wp<ALooper> &looper) {
        mID = id;
        mLooper = looper;
    }

 4、让ALooper开始打工 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;
}

这里的参数有点奇怪,让我看看NuPlayer里怎么用的

mRendererLooper = new ALooper;
mRendererLooper->start(false, false, ANDROID_PRIORITY_AUDIO);

a. 第一个参数看起来是确定ALooper是否在调用线程中工作,

b. 第二个参数从名字上来看意为是否能调用java方法

c. 第三个参数为优先级,会传进Thread当中

下面来看start的内部实现,实现根据runOnCallingThread分为两种情况:

a. 例子中NuPlayer填的false,所以创建了一个LooperThread对象,执行其run方法开启线程(该方法在基类Thread当中)

Thread类:system\core\libutils\Threads.cpp,这里不做研究

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

最后应该会在一个新的线程中执行loop方法

b. 如果runOnCallingThread为true,那么就会在当前线程执行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;
            if (delayUs > INT64_MAX / 1000) {
                delayUs = INT64_MAX / 1000;
            }
            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;
}

仔细推究的话这里会有一个问题,如果在当前线程执行loop函数不会阻塞主线程吗?其实不会的,这里利用到了条件变量,执行到mQueueChangedCondition.wait时这个循环就会休眠,等待signal触发再运行,具体可以查看pthread_cond_t的工作原理。

 

 

(二)接下来就要看看他们传递处理的对象AMessage,AMessage可以只当作信息的载体,也可以作为异步信号

1、AMessage构造函数

AMessage::AMessage(void)
    : mWhat(0),
      mTarget(0) {
}

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

AMessage有两种构造函数,

a. 无参构造更加适合于对象只当信息载体,保存数据

b. 有参构造函数适合作为一个信号,用于程序间的异步调用。当然也可以先创建一个无参对象,再去调用setTarget设定处理它的AHandler

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

从setTarget方法可以看到AMessage会持有target AHanlder以及对应的ALooper对象

2、发送消息

有三种发送消息的方式,接下来一个个看:

a. post

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

看到AMessage::post中调用的是ALooper::post   (ALooper::post作为一个私有方法在AMessage中可以调用是因为ALooper定义AMessage是其友元)

void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
    Mutex::Autolock autoLock(mLock);
  
    // 计算什么时候post消息 
    int64_t whenUs;
    if (delayUs > 0) {
        int64_t nowUs = GetNowUs();
        whenUs = (delayUs > INT64_MAX - nowUs ? INT64_MAX : nowUs + delayUs);

    } else {
        whenUs = GetNowUs();
    }

    List<Event>::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);
}

在这里看到会将消息打包为Event 插入到ALooper的队列当中,同时通知loop循环开始工作;loop方法会调用AMessage的deliver方法(同样AMessage也是AHandler的友元)

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

deliverMessage是AHandler.cpp中唯一的方法,其调用的核心方法是onMessageReceived,这是一个纯虚函数,需要一个子类来实现!onMessageReceived这里就处理结束了

 

 

b. postAndAwaitResponse

从名字上来看,发出消息之后需要等待处理完成之后并返回结果

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

    sp<AReplyToken> token = looper->createReplyToken();
    if (token == NULL) {
        ALOGE("failed to create reply token");
        return -ENOMEM;
    }
    setObject("replyID", token);

    looper->post(this, 0 /* delayUs */);
    return looper->awaitResponse(token, response);
}

通过ALooper创建一个AReplyToken,并且把这个token加入到AMessage当中,接着post出去,到这里为止,调用的过程和直接基本相同,不同的是这里会最后会调用awaitResponse方法等待返回一个结果。

这个结果如何返回呢?那就是调用与其相对应的方法postReply,意思就是在调用完成后会创建一个新的AMessage保存结果,然后根据token将这个结果返回给调用者

status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
    if (replyToken == NULL) {
        ALOGW("failed to post reply to a NULL token");
        return -ENOENT;
    }
    sp<ALooper> looper = replyToken->getLooper();
    if (looper == NULL) {
        ALOGW("failed to post reply as target looper is gone.");
        return -ENOENT;
    }
    return looper->postReply(replyToken, this);
}

postReply方法调用了ALooper的postReply方法

status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
    Mutex::Autolock autoLock(mRepliesLock);
    status_t err = replyToken->setReply(reply);
    if (err == OK) {
        mRepliesCondition.broadcast();
    }
    return err;
}

调用replyToken的setReply方法将返回的结果保存到token当中,这样ALooper的awaitResponse方法可以拿回这个结果,这样一次完整的调用就结束了。

status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
    // return status in case we want to handle an interrupted wait
    Mutex::Autolock autoLock(mRepliesLock);
    CHECK(replyToken != NULL);
    while (!replyToken->retrieveReply(response)) {
        {
            Mutex::Autolock autoLock(mLock);
            if (mThread == NULL) {
                return -ENOENT;
            }
        }
        mRepliesCondition.wait(mRepliesLock);
    }
    return OK;
}

这里还有一个方法要看,在onMessageReceived方法中要如何拿到送过来的AReplyToken呢?AMessage给我们提供了一个方法:senderAwaitsResponse

bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
    sp<RefBase> tmp;
    bool found = findObject("replyID", &tmp);

    if (!found) {
        return false;
    }

    *replyToken = static_cast<AReplyToken *>(tmp.get());
    tmp.clear();
    setObject("replyID", tmp);
    // TODO: delete Object instead of setting it to NULL

    return *replyToken != NULL;
}

就是利用的findObject方法来查找的。

这三个方法postAndAwaitResponse、postReply、senderAwaitsResponse需要共同协作可以完成一次异步阻塞调用。

 

其他的AMessage中的方法可以直接去AMessage.cpp中查询。

 

 最后再贴一张时序图。

为什么post一条AMessage需要搞得这么复杂呢?

我觉得是:一个ALooper管理着多个AHandler,起着事件的存储和分发作用,为了让AMessage能够找到正确的AHandler处理,需要调用AMessage自身的deliver方法找到对应的AHandler。

从图上来看AHandler和ALooper没有什么关系,为什么创建handler之后要调用registerHandler呢?

我觉得是:创建AMessage之后,要去setTarget(也就是handler),这时候handler中也保存了Looper对象,调用AMessage的post方法时就能找到正确的Looper来处理了

 

标签:12,return,handler,looper,AMessage,ALooper,Android,AHandler
来源: https://www.cnblogs.com/rongmiao/p/16050682.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有