1.源码流程贴图
1.1源码例子部分代码贴图
NuPlayerDriver::NuPlayerDriver(pid_t pid)
: mState(STATE_IDLE),
mIsAsyncPrepare(false),
mAsyncResult(UNKNOWN_ERROR),
mSetSurfaceInProgress(false),
mDurationUs(-1),
mPositionUs(-1),
mSeekInProgress(false),
mLooper(new ALooper),
mPlayerFlags(0),
mAtEOS(false),
mLooping(false),
mAutoLoop(false) {
ALOGV("NuPlayerDriver(%p)", this);
mLooper->setName("NuPlayerDriver Looper");
mLooper->start(
false, /* runOnCallingThread */
true, /* canCallJava */
PRIORITY_AUDIO);
mPlayer = AVNuFactory::get()->createNuPlayer(pid);
mLooper->registerHandler(mPlayer);
mPlayer->setDriver(this);
}
主要部分:
mLooper(new ALooper),
mLooper->start(
false, /* runOnCallingThread */
true, /* canCallJava */
PRIORITY_AUDIO);
mLooper->registerHandler(mPlayer);
其中mLooper(new ALooper) 和mLooper->start创建一个线程,该线程不断地执行mLooper的loop函数,每执行一次loop函数就会从线程中由mLooper维护的事件链表取出首端事件,然后判断该事件的时间戳,如果该事件的时间戳小于或者等于当前系统的时间,则调用该事件消息的deliver函数将该事件的消息派发出去。
现在完成了这样一个创建,还没有向事件链表中添加任何事件。
下面贴出mLooper调用registerHandler函数的具体流程
==>
mLooper->registerHandler(mPlayer);
==>
ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {
return gLooperRoster.registerHandler(this, handler);
}
==>
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;
}
==>
handler->setID(handlerID, looper);
==>
inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
mID = id;
mLooper = looper;
}
由ALooper调用其registerHandler函数来完成注册,整个注册过程除了将ALooper和AHandler绑定成一对儿,然后给予一个唯一的键值,存储在全局对象gLooperRoster的mHandlers容器中,还通过调用handler->setID(handlerID, looper)将这个键值和 looper的引用保存在handler中。
将键值和 looper的引用保存在handler中这很重要,因为只有拥有ALooper的引用,才能调用ALooper提供的post接口将事件添加到ALooper维护的事件链表中。
这样以来,一个经过注册的AHandler对象,将拥有一个非零的键值用来标识自己和与自己绑定在一起的ALooper对象,并且该AHandler对象含有该ALooper对象的引用,后续会通过这个引用来调用ALooper对象的post接口向ALooper对象维护的事件链表中。
1.2创建一个消息
==>
void NuPlayer::start() {
(new AMessage(kWhatStart, this))->post();
}
==>
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();
}
}
==>
struct AHandler : public RefBase {
wp<ALooper> getLooper() const {
return mLooper;
}
wp<AHandler> getHandler() const {
// allow getting a weak reference to a const handler
return const_cast<AHandler *>(this);
}
};
创建消息的时候需要两个参数,一个是消息名,另一个是经过注册的消息处理者(AHandler),this这里是NuPlayer对象,也是前面的创建的mPlayer,是一个AHandler对象。
设置好了消息名后,然后调用setTarget(handler)函数,设置mTarget,mHandler,mLooper这些成员变量的值。其中mHandler和mLooper是一对儿经过注册的AHandler,ALooper对儿,mTarget是标识这一对儿的键值。
整个流程完成赋值后,形成的格局是:
有一对儿绑定在一起的AHandler,,ALooper跟据标识这一对儿的键值存储在全局对象gLooperRoster的mHandlers容器中。
然后这个经过注册的AHandler对象作为参数值来创建一个消息AMessage对象。这个AMessage对象通过传递的AHandler对象得到了这个AHandler对象的引用,并且获取到了他的handler ID 和ALooper对象的引用。
这样以来这个AMessage对象和AHandler对象都拥有了ALooper对象的引用引用,这样就可以通过调用ALooper对象的post函数来向ALooper对象维护的事件链表中添加事件。同时AMessage对象也拥有了AHandler对象的引用,这样就可以调用AHandler对象的函数来对该消息进行处理。
1.3发用消息
==>
void NuPlayer::start() {
(new AMessage(kWhatStart, this))->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;
}
==>
void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
Mutex::Autolock autoLock(mLock);
int64_t whenUs;
if (delayUs > 0) {
whenUs = GetNowUs() + 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);
}
通过调用该AMessage对象拥有的ALooper对象引用调用其post函数来向ALooper对象维护的事件链表添加消息。
1.4消息派发(deliver)
==>
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;
}
==>
event.mMessage->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);
}
通过AMessage对象拥有的AHandler对象的引用,然后调用AHandler对象对象的deliverMessage函数将消息派发出去。
1.5消息处理
==>
handler->deliverMessage(this);
==>
namespace android {
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)++;
}
}
}
} // namespace android
==>
onMessageReceived(msg);
handler->deliverMessage函数里调用了onMessageReceived(msg);
onMessageReceived在AHandler里是纯虚函数,NuPlayer继承自AHandler并且重写了onMessageReceived。所以通过虚函数机制最终是在NuPlayer的onMessageReceived函数里对msg进行处理的
下面贴出安卓N版本AHandler.h的原文
#ifndef A_HANDLER_H_
#define A_HANDLER_H_
#include <media/stagefright/foundation/ALooper.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
namespace android {
struct AMessage;
struct AHandler : public RefBase {
AHandler()
: mID(0),
mVerboseStats(false),
mMessageCounter(0) {
}
ALooper::handler_id id() const {
return mID;
}
sp<ALooper> looper() const {
return mLooper.promote();
}
wp<ALooper> getLooper() const {
return mLooper;
}
wp<AHandler> getHandler() const {
// allow getting a weak reference to a const handler
return const_cast<AHandler *>(this);
}
protected:
virtual void onMessageReceived(const sp<AMessage> &msg) = 0;
private:
friend struct AMessage; // deliverMessage()
friend struct ALooperRoster; // setID()
ALooper::handler_id mID;
wp<ALooper> mLooper;
inline void setID(ALooper::handler_id id, wp<ALooper> looper) {
mID = id;
mLooper = looper;
}
bool mVerboseStats;
uint32_t mMessageCounter;
KeyedVector<uint32_t, uint32_t> mMessages;
void deliverMessage(const sp<AMessage> &msg);
DISALLOW_EVIL_CONSTRUCTORS(AHandler);
};
} // namespace android
#endif // A_HANDLER_H_
2.总结
整体来说安卓N版本里异步消息处理机制较安卓M版本有了很大的变化,不过涉及到的还是ALooper,AHandler,AMessage这三个。只不过在实现机理上有了不小的变化。
我觉得N版本这个实现机理上还是比较好的,但是容易绕糊涂。
对这个版本的实现机理做个小结:
ALooper提供post函数用来向事件链表里添加消息,AHandler提供函数deliverMessage来完成消息派发。两个函数调用都是发生在AMessage提供的post和deliver函数里的。因此问题的关键就是这个中间者需要拥有ALooper,AHandler的引用这样就可以在自己的post和deliver函数里里分被调用ALooper提供的post函数和AHandler提供函数deliverMessage来完成事件的添加和消息的派发。