Android 12(S) ALooper AHandler AMessage(一)
作者:互联网
卧榻之侧岂容他人酣睡,到现在ALooper AHandler AMessage的工作原理一直都没搞懂,很慌!看他们的路径都在libstagefright/foundation下,作为一个foundation怎么能不去搞明白,今天必须解决他们!
相关代码路径:
从哪里开始?就从他们怎么使用开始!然后顺着看
(一)正常使用这三剑客时,会先去创建一个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