Android Media Player 框架分析-AHandler AMessage ALooper

在之前一篇中简单的介绍了一下setDataSource的流程,其中遇到了一个新的消息机制AHandler,其实这东西本来不需要介绍,因为消息机制原本就是一个很成熟和常见的技术技巧,这玩意里面包含了计算机哲学和计算机玄学的双学位问题,听起来牛逼轰轰,其实也就那回事了。为了这次文档的完整性,再一个后面可能要整理到公司的文档库中,所以在此介绍一下,熟悉的同学直接飘过了。


先说说为什么要用消息机制,在我们的软件开发中经常会遇到多线程的问题,由此便带来了线程同步的问题,比如各种锁,最常见的就是Mutex,而线程同步通常是有代价的,这个代价一方面来自于锁本身,而另一方面来自于程序设计,在一个有众多线程的进程中使用同步锁常常造成各种死锁问题,当然你可以说你水平高超没有这个问题,而通常解决锁之间的竞争往往在效率上也要付出相应的代价,当然了你也可以说你连这也能解决,那我也只能膜拜了。然而通常还有另一个问题,便是线程间的执行顺序问题,如果使用锁和条件变量来控制,在线程众多的情况下,可控性只会越来越差,另外通常来讲CPU的利用率也不高。那么消息机制是如何来解决这些问题的呢?


第一个问题是什么是消息机制,这里先介绍一个同步/异步的的概念,举例来说明,

比如说肚子饿了去饭店吃饭,点好菜后你坐那老老实实等着服务员上菜,什么时候菜做了好你才能结束等待,那这就是同步。

而异步就不用干等了,掏出手机,打开外卖软件,下单,OK,这时你就可以去干别的事情了,应该没有人死盯着手机干等吧,到时候饭店做好饭,小哥自然送上门。


听起来异步比同步是先进很多了,但在现实中事情往往没有想象的那么容易,首先你用外卖软件,如果我是老板,餐厅已经爆满了,顾客在饭店里已经骂娘了,哪还顾得上你,第二你点完得等送餐吧,又多了一段路程,而同步也有自己的缺点,坐在餐馆等饭的时间对于你而言算是浪费了,比如你还有其他事情没做此时也只能乖乖干坐着了。


好吧,扯太远了,回到消息机制上来。

当我们想要我们的程序执行一些事情的时候要么同步,要么异步,而消息机制便是一种异步的方式,首先创建一个消息队列,这个消息队列在一个单独的线程中轮询,一旦有人发送消息给它,它就会将消息取出执行,执行后又回到等待状态直到有新的消息到来。

如下图:


消息被投递到一个消息队列中去,而Looper会持续不断的从Message Queue中拿出消息,再投递给合适的Handler去处理。

好了,开始对Android的这个消息队列进行分析吧,依旧从使用上入手,通常在使用的开始会创建一个ALooper对象,然后会实现一个AHandler的子类,最后创建消息进行投递进入Message Queue。

首先我们先看一下AHandler的定义。代码不多直接贴上来。

  1. namespace android {  
  2.   
  3. struct AMessage;  
  4. struct AHandler : public RefBase {  
  5.   
  6.     AHandler()  
  7.         : mID(0),  
  8.           mVerboseStats(false),  
  9.           mMessageCounter(0) {  
  10.     }  
  11.   
  12.     ALooper::handler_id id() const {  
  13.         return mID;  
  14.     }  
  15.   
  16.     sp<ALooper> looper() const {  
  17.         return mLooper.promote();  
  18.     }  
  19.   
  20.     wp<ALooper> getLooper() const {  
  21.         return mLooper;  
  22.     }  
  23.   
  24.     wp<AHandler> getHandler() const {  
  25.         // allow getting a weak reference to a const handler  
  26.         return const_cast<AHandler *>(this);  
  27.     }  
  28.   
  29. protected:  
  30.     virtual void onMessageReceived(const sp<AMessage> &msg) = 0;  
  31.   
  32. private:  
  33.     friend struct AMessage;      // deliverMessage()  
  34.     friend struct ALooperRoster; // setID()  
  35.     ALooper::handler_id mID;  
  36.     wp<ALooper> mLooper;  
  37.   
  38.     inline void setID(ALooper::handler_id id, wp<ALooper> looper) {  
  39.         mID = id;  
  40.         mLooper = looper;  
  41.     }  
  42.   
  43.     bool mVerboseStats;  
  44.     uint32_t mMessageCounter;  
  45.     KeyedVector<uint32_t, uint32_t> mMessages;  
  46.     void deliverMessage(const sp<AMessage> &msg);  
  47.   
  48.     DISALLOW_EVIL_CONSTRUCTORS(AHandler);  
  49. };  
  50.   
  51.   
  52.   
  53. }  // namespace android  

cpp文件:

  1. namespace android {  
  2.   
  3. void AHandler::deliverMessage(const sp<AMessage> &msg) {  
  4.     onMessageReceived(msg);  
  5.     mMessageCounter++;  
  6.   
  7.     if (mVerboseStats) {  
  8.         uint32_t what = msg->what();  
  9.         ssize_t idx = mMessages.indexOfKey(what);  
  10.         if (idx < 0) {  
  11.             mMessages.add(what, 1);  
  12.         } else {  
  13.             mMessages.editValueAt(idx)++;  
  14.         }  
  15.     }  
  16. }  
  17. }  // namespace android  

由于该类为基类,在使用时需要自己定义子类去继承重新类中的方法,所先以该类的Cpp文件相对比较简单,只定义了一个deliverMessage方法,
先看看.h文件中该类的构成,其中有一个容易混淆的成员mMessages被定义为KeyedVector类型,该并不是真正的Message Queue,相反该对象并没有什么太大的实际作用,只有在verbose模式下才存储一个消息被传递的次数,对我们分析没什么帮助。剩下的就是一个id值,和一个ALooper的弱引用。刚刚我们已经说过了,Looper负责将消息源源不断的发送给Handler来处理,所以两者是必然有关联的。另外还有一个mVerboseStats的bool值,这玩意实际上没啥用,先不看了。之后看看一个重要的纯虚函数onMessageReceived,我们定义的子类最重要的就是实现这个方法。之后会通过调用把Message发给这个函数,而这个函数会根据这个Message中的what值来判断需要进行什么操作,习惯用法是通过一个switch来处理。


实际的Media代码中这个AHandler的使用非常之多,只需简单搜索便可以找到很多的例子来查看。
现在应该来看看ALooper这个类了,这个类的作用非常明确,在创建时会开启一个线程,不断的对消息队列进行检查,如果一旦有消息便拿出来给相应的AHandler处理。比较熟悉的人应该可以想到这种情景下需要一个Condition条件变量来控制循环,否则持续的轮询会给系统产生可怕的负担。
代码都不多直接全放上来好了,先看.h文件
  1. namespace android {  
  2.   
  3. struct AHandler;  
  4. struct AMessage;  
  5. struct AReplyToken;  
  6.   
  7. struct ALooper : public RefBase {  
  8.     typedef int32_t event_id;  
  9.     typedef int32_t handler_id;  
  10.   
  11.     ALooper();  
  12.   
  13.     // Takes effect in a subsequent call to start().  
  14.     void setName(const char *name);  
  15.   
  16.     handler_id registerHandler(const sp<AHandler> &handler);  
  17.   
  18.     void unregisterHandler(handler_id handlerID);  
  19.   
  20.     status_t start(  
  21.             bool runOnCallingThread = false,  
  22.             bool canCallJava = false,  
  23.             int32_t priority = PRIORITY_DEFAULT  
  24.             );  
  25.   
  26.     status_t stop();  
  27.   
  28.     static int64_t GetNowUs();  
  29.   
  30.     const char *getName() const {  
  31.         return mName.c_str();  
  32.     }  
  33.   
  34. protected:  
  35.     virtual ~ALooper();  
  36.   
  37. private:  
  38.     friend struct AMessage;       // post()  
  39.   
  40.     struct Event {  
  41.         int64_t mWhenUs;  
  42.         sp<AMessage> mMessage;  
  43.     };  
  44.   
  45.     Mutex mLock;  
  46.     Condition mQueueChangedCondition;  
  47.     AString mName;  
  48.   
  49.     List<Event> mEventQueue;  
  50.   
  51.     struct LooperThread;  
  52.     sp<LooperThread> mThread;  
  53.     bool mRunningLocally;  
  54.   
  55.     // use a separate lock for reply handling, as it is always on another thread  
  56.     // use a central lock, however, to avoid creating a mutex for each reply  
  57.     Mutex mRepliesLock;  
  58.     Condition mRepliesCondition;  
  59.   
  60.     // START --- methods used only by AMessage  
  61.     // posts a message on this looper with the given timeout  
  62.     void post(const sp<AMessage> &msg, int64_t delayUs);  
  63.   
  64.     // creates a reply token to be used with this looper  
  65.     sp<AReplyToken> createReplyToken();  
  66.   
  67.     // waits for a response for the reply token.  If status is OK, the response  
  68.     // is stored into the supplied variable.  Otherwise, it is unchanged.  
  69.     status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);  
  70.   
  71.     // posts a reply for a reply token.  If the reply could be successfully posted,  
  72.     // it returns OK. Otherwise, it returns an error value.  
  73.     status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);  
  74.   
  75.     // END --- methods used only by AMessage  
  76.     bool loop();  
  77.     DISALLOW_EVIL_CONSTRUCTORS(ALooper);  
  78. };  
  79. // namespace android  
.cpp文件:
  1. namespace android {  
  2.   
  3. ALooperRoster gLooperRoster;  
  4. struct ALooper::LooperThread : public Thread {  
  5.     LooperThread(ALooper *looper, bool canCallJava)  
  6.         : Thread(canCallJava),  
  7.           mLooper(looper),  
  8.           mThreadId(NULL) {  
  9.     }  
  10.     virtual status_t readyToRun() {  
  11.         mThreadId = androidGetThreadId();  
  12.         return Thread::readyToRun();  
  13.     }  
  14.   
  15.     virtual bool threadLoop() {  
  16.         return mLooper->loop();  
  17.     }  
  18.   
  19.     bool isCurrentThread() const {  
  20.         return mThreadId == androidGetThreadId();  
  21.     }  
  22.   
  23. protected:  
  24.     virtual ~LooperThread() {}  
  25.   
  26. private:  
  27.     ALooper *mLooper;  
  28.     android_thread_id_t mThreadId;  
  29.     DISALLOW_EVIL_CONSTRUCTORS(LooperThread);  
  30. };  
  31.   
  32. // static  
  33. int64_t ALooper::GetNowUs() {  
  34.     return systemTime(SYSTEM_TIME_MONOTONIC) / 1000ll;  
  35. }  
  36.   
  37. ALooper::ALooper()  
  38.     : mRunningLocally(false) {  
  39.     // clean up stale AHandlers. Doing it here instead of in the destructor avoids  
  40.     // the side effect of objects being deleted from the unregister function recursively.  
  41.     gLooperRoster.unregisterStaleHandlers();  
  42. }  
  43.   
  44. ALooper::~ALooper() {  
  45.     stop();  
  46.     // stale AHandlers are now cleaned up in the constructor of the next ALooper to come along  
  47. }  
  48.   
  49. void ALooper::setName(const char *name) {  
  50.     mName = name;  
  51. }  
  52.   
  53. ALooper::handler_id ALooper::registerHandler(const sp<AHandler> &handler) {  
  54.     return gLooperRoster.registerHandler(this, handler);  
  55. }  
  56.   
  57. void ALooper::unregisterHandler(handler_id handlerID) {  
  58.     gLooperRoster.unregisterHandler(handlerID);  
  59. }  
  60.   
  61. status_t ALooper::start(  
  62.         bool runOnCallingThread, bool canCallJava, int32_t priority) {  
  63.     if (runOnCallingThread) {  
  64.         {  
  65.             Mutex::Autolock autoLock(mLock);  
  66.             if (mThread != NULL || mRunningLocally) {  
  67.                 return INVALID_OPERATION;  
  68.             }  
  69.             mRunningLocally = true;  
  70.         }  
  71.   
  72.         do {  
  73.         } while (loop());  
  74.         return OK;  
  75.     }  
  76.   
  77.     Mutex::Autolock autoLock(mLock);  
  78.   
  79.     if (mThread != NULL || mRunningLocally) {  
  80.         return INVALID_OPERATION;  
  81.     }  
  82.   
  83.     mThread = new LooperThread(this, canCallJava);  
  84.   
  85.     status_t err = mThread->run(  
  86.             mName.empty() ? "ALooper" : mName.c_str(), priority);  
  87.   
  88.     if (err != OK) {  
  89.         mThread.clear();  
  90.     }  
  91.     return err;  
  92. }  
  93.   
  94. status_t ALooper::stop() {  
  95.     sp<LooperThread> thread;  
  96.     bool runningLocally;  
  97.     {  
  98.         Mutex::Autolock autoLock(mLock);  
  99.   
  100.         thread = mThread;  
  101.         runningLocally = mRunningLocally;  
  102.         mThread.clear();  
  103.         mRunningLocally = false;  
  104.     }  
  105.   
  106.     if (thread == NULL && !runningLocally) {  
  107.         return INVALID_OPERATION;  
  108.     }  
  109.   
  110.     if (thread != NULL) {  
  111.         thread->requestExit();  
  112.     }  
  113.   
  114.     mQueueChangedCondition.signal();  
  115.     {  
  116.         Mutex::Autolock autoLock(mRepliesLock);  
  117.         mRepliesCondition.broadcast();  
  118.     }  
  119.   
  120.     if (!runningLocally && !thread->isCurrentThread()) {  
  121.         // If not running locally and this thread _is_ the looper thread,  
  122.         // the loop() function will return and never be called again.  
  123.         thread->requestExitAndWait();  
  124.     }  
  125.     return OK;  
  126. }  
  127.   
  128. void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {  
  129.     Mutex::Autolock autoLock(mLock);  
  130.     int64_t whenUs;  
  131.     if (delayUs > 0) {  
  132.         whenUs = GetNowUs() + delayUs;  
  133.     } else {  
  134.         whenUs = GetNowUs();  
  135.     }  
  136.   
  137.     List<Event>::iterator it = mEventQueue.begin();  
  138.     while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {  
  139.         ++it;  
  140.     }  
  141.   
  142.     Event event;  
  143.     event.mWhenUs = whenUs;  
  144.     event.mMessage = msg;  
  145.   
  146.     if (it == mEventQueue.begin()) {  
  147.         mQueueChangedCondition.signal();  
  148.     }  
  149.     mEventQueue.insert(it, event);  
  150. }  
  151.   
  152. bool ALooper::loop() {  
  153.     Event event;  
  154.     {  
  155.         Mutex::Autolock autoLock(mLock);  
  156.         if (mThread == NULL && !mRunningLocally) {  
  157.             return false;  
  158.         }  
  159.         if (mEventQueue.empty()) {  
  160.             mQueueChangedCondition.wait(mLock);  
  161.             return true;  
  162.         }  
  163.         int64_t whenUs = (*mEventQueue.begin()).mWhenUs;  
  164.         int64_t nowUs = GetNowUs();  
  165.   
  166.         if (whenUs > nowUs) {  
  167.             int64_t delayUs = whenUs - nowUs;  
  168.             mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);  
  169.             return true;  
  170.         }  
  171.   
  172.         event = *mEventQueue.begin();  
  173.         mEventQueue.erase(mEventQueue.begin());  
  174.     }  
  175.   
  176.     event.mMessage->deliver();  
  177.   
  178.     // NOTE: It's important to note that at this point our "ALooper" object  
  179.     // may no longer exist (its final reference may have gone away while  
  180.     // delivering the message). We have made sure, however, that loop()  
  181.     // won't be called again.  
  182.     return true;  
  183. }  
  184.   
  185. // to be called by AMessage::postAndAwaitResponse only  
  186. sp<AReplyToken> ALooper::createReplyToken() {  
  187.     return new AReplyToken(this);  
  188. }  
  189.   
  190. // to be called by AMessage::postAndAwaitResponse only  
  191. status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {  
  192.     // return status in case we want to handle an interrupted wait  
  193.     Mutex::Autolock autoLock(mRepliesLock);  
  194.     CHECK(replyToken != NULL);  
  195.   
  196.     while (!replyToken->retrieveReply(response)) {  
  197.         {  
  198.             Mutex::Autolock autoLock(mLock);  
  199.             if (mThread == NULL) {  
  200.                 return -ENOENT;  
  201.             }  
  202.         }  
  203.         mRepliesCondition.wait(mRepliesLock);  
  204.     }  
  205.     return OK;  
  206. }  
  207.   
  208. status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {  
  209.     Mutex::Autolock autoLock(mRepliesLock);  
  210.     status_t err = replyToken->setReply(reply);  
  211.     if (err == OK) {  
  212.         mRepliesCondition.broadcast();  
  213.     }  
  214.     return err;  
  215. }  
  216.   
  217. }  // namespace android  


首先看一下cpp文件开始变声明了一个LooperThread的内部类型,该类型继承与Thread类。通过构造函数保存了ALooper指针,这些没什么可说的,看一下threadLoop函数直接调用了ALooper的loop函数,果然和我们之前描述的一致,该线程不断的调用loop函数,而loop函数自身则是对消息队列的查询,如此,整个消息队列便在Looper的驱动下活动起来了。成员对象List<Event> mEventQueue;便是我们要寻找的Message Queue了,其他的接口主要有setName给Looper起个名字,这个名字其实蛮重要的,因为最后会用作LooperThread的名字,线程的名字是一个很重要的信息,start函数就无需多言了创建LooperThread然后调用run函数把线程跑起来,就可以了,而这个线程便会不断调用ALooper的loop函数来驱动消息队列。
再来看一下ALooper的成员变量。
  1. Mutex mLock;  
  2. Condition mQueueChangedCondition;  
  3. Mutex mRepliesLock;  
  4. Condition mRepliesCondition;  
首先是两对搭配使用的Mutex和Condition,mQueueChangedCondition是用来阻塞loop函数的,如果没有它loop函数会在消息队列中没有Event时继续空转,那CPU就耗光了,而mRepliesCondition则是用来做消息的同步等待回复的,后续碰到再说吧。
剩下的几个函数,我们先说简单常用的,post方法,该方法是将消息投递到队列中,第一个参数是AMessage也就是消息,第二个参数是延迟时间,实现非常简单,创建一个Event然后将其加入队列即可,另外就是如果消息队列原本为空就通过mQueueChangedCondition.signal();唤醒队列的线程。
其中的内部类型Event就不多说了,对message的简单包装,剩下的createReplyToken/awaitResponse/postReply是用来发同步消息等待反馈的,我们一会再说。
再看看loop方法的具体细节,首先会判断如果mThread==NULL并且mRunningLocally==false则函数返回false,如果返回了false,线程就不会在执行下一次的loop函数了。接下来判断mEventQueue是否为空,也就是判断消息队列中是否有消息,如果没有就使用mQueueChangedCondition.wait使线程阻塞,直到刚才介绍post时说的那样被唤醒。剩下的如果是队列中第一个要执行的消息有延迟时间,那么就是用Condition的waitRelative方法阻塞等待。最后一切都没问题了就准备处理消息了,先把消息从队列删除,之后通过调用event.mMessage->deliver()方法来处理消息。处理的细节我们一会介绍AMessage时再来看。

前面说了ALooper和AHandler相对都是比较简单的,剩下一个AMessage反倒是这个消息队列中比较复杂的一个组成部分了,代码稍微有点多,所以还是分段来看。
首先说一点,这个Message不仅仅是传递消息这么简单,它可以附带上很多的键值对在身上,也就是说这个Message在传递的时候除了最重要的what值之外还能带上一些其他的值,而每个值都有一个对应的key,这样接收方在处理消息时可以根据这个key值拿出在Message中存储的value,这样一次可以传递的信息就大大增加了。
在AMessage的定义中有如下的一个内部类的定义
  1. struct Item {  
  2.     union {  
  3.         int32_t int32Value;  
  4.         int64_t int64Value;  
  5.         size_t sizeValue;  
  6.         float floatValue;  
  7.         double doubleValue;  
  8.         void *ptrValue;  
  9.         RefBase *refValue;  
  10.         AString *stringValue;  
  11.         Rect rectValue;  
  12.     } u;  
  13.   
  14.     const char *mName;  
  15.     size_t      mNameLength;  
  16.     Type mType;  
  17.     void setName(const char *name, size_t len);  
  18.   
  19. };  

这个类型所定义的就是一个key-value,被命名为Item, 其中使用联合体这段空间来存储value,使用mName来作为key。mNameLength来存储key值得长度,这个长度在这里还挺重要的,后面我们再看,mType是一个枚举值,保存了所存数据是什么类型的,枚举体定义如下:
  1. enum Type {  
  2.     kTypeInt32,  
  3.     kTypeInt64,  
  4.     kTypeSize,  
  5.     kTypeFloat,  
  6.     kTypeDouble,  
  7.     kTypePointer,  
  8.     kTypeString,  
  9.     kTypeObject,  
  10.     kTypeMessage,  
  11.     kTypeRect,  
  12.     kTypeBuffer,  
  13. };  
之后AMessage定义了一个数组Item mItems[kMaxNumItems];保存所有的Item不过这样确定不浪费空间吗?另外便定义了一堆的find和set函数,都是用来设置这些键值对的。一个AMessage最多携带kMaxNumItems个Item,默认为64.
除了这个之外还有一个类AReplyToken,这个虽然不是AMessage的内部类,但我猜想这个类不作为内部类的原因更多的可能是因为C++的一个语法限制。这个类的作用我们等会再说,先看看AMessage的另外两个成员变量
  1. wp<AHandler> mHandler;  
  2. wp<ALooper> mLooper;  
这两个猜都知道啦,一个是处理该消息的Handler一个是处理消息队列轮询的Looper。
当然AMessage中少不了的还有个what值,定义如下:
  1. uint32_t mWhat;  
因为一个Handler不是给一个Message专用的,可能会处理很多种的消息,那么为了区分便加入一个what值来告诉Handler现在的消息是哪种,一般Handler会使用一个switch来进行处理,这个源码中例子多的不要不要的,自己看吧。

好啦,看看构造函数先:
  1. AMessage();  
  2. AMessage(uint32_t what, const sp<const AHandler> &handler);  
  3.   
  4. AMessage::AMessage(void)  
  5.     : mWhat(0),  
  6.       mTarget(0),  
  7.       mNumItems(0) {  
  8. }  
  9.   
  10. AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)  
  11.     : mWhat(what),  
  12.       mNumItems(0) {  
  13.     setTarget(handler);  
  14. }  
一般使用第二种了,传入消息的what值和handler,mNumItems赋0表示目前还没有携带的附加信息,也就是键值对Item啦。之后调用setTarget
  1. void AMessage::setTarget(const sp<const AHandler> &handler) {  
  2.     if (handler == NULL) {  
  3.         mTarget = 0;  
  4.         mHandler.clear();  
  5.         mLooper.clear();  
  6.     } else {  
  7.         mTarget = handler->id();  
  8.         mHandler = handler->getHandler();  
  9.         mLooper = handler->getLooper();  
  10.     }  
  11. }  
mTarge是handler的一个id值,这个id是累加生成的,回头再说吧,暂时用不到,剩下的就没什么,简单赋值。另外为啥要调用handler的getHandler的方法而不直接赋值呢?主要是因为有可能AHandler是一个const的指针,getHandler方法会将其通过const_cast转换,那为啥要搞成非const的呢,因为要用wp,那为啥用wp就要非const呢。。。不想回答你。。。
好吧,看看AMessage的post方法吧,这是我们要分析的重点,
  1. status_t AMessage::post(int64_t delayUs) {  
  2.     sp<ALooper> looper = mLooper.promote();  
  3.   
  4.     if (looper == NULL) {  
  5.         ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);  
  6.         return -ENOENT;  
  7.     }  
  8.     looper->post(this, delayUs);  
  9.     return OK;  
  10. }  
实现挺简单的吧,直接调用ALooper的post方法。ALooper的post我们已经说过了加入到消息队列就没了。之后loop函数会把消息取出来调用Message的deliver方法,我们来看看这个deliver方法是干嘛的。
  1. void AMessage::deliver() {  
  2.     sp<AHandler> handler = mHandler.promote();  
  3.     if (handler == NULL) {  
  4.         ALOGW("failed to deliver message as target handler %d is gone.", mTarget);  
  5.         return;  
  6.     }  
  7.   
  8.     handler->deliverMessage(this);  
  9. }  
直接拿出handler调用了deliverMessage方法,这个方法我们刚才说过了。会不会想为啥AMessage的post方法不直接调用deliver方法呢,如果有这个问题证明你压根没看懂,再看一遍吧,当ALooper通过loop函数拿出消息调用deliver的时候,这个deliver才会在Looper的线程里面执行,而如果直接调用那就成了当前线程同步调用了。

好,我们看最后一个问题,AMessage中的 postAndAwaitResponse方法,这个方法也是用来发送消息的,不同之处在于这个方法发送完消息以后会等待接收方返回一个答复,所以你懂的,main thread里面肾用。

好,此时我们需要看看刚才提了一下的
  1. struct AReplyToken : public RefBase {  
  2.   
  3.     AReplyToken(const sp<ALooper> &looper)  
  4.         : mLooper(looper),  
  5.           mReplied(false) {  
  6.     }  
  7.   
  8. private:  
  9.     friend struct AMessage;  
  10.     friend struct ALooper;  
  11.     wp<ALooper> mLooper;  
  12.     sp<AMessage> mReply;  
  13.     bool mReplied;  
  14.   
  15.     sp<ALooper> getLooper() const {  
  16.         return mLooper.promote();  
  17.     }  
  18.   
  19.     // if reply is not set, returns false; otherwise, it retrieves the reply and returns true  
  20.     bool retrieveReply(sp<AMessage> *reply) {  
  21.         if (mReplied) {  
  22.             *reply = mReply;  
  23.             mReply.clear();  
  24.         }  
  25.         return mReplied;  
  26.     }  
  27.   
  28.     // sets the reply for this token. returns OK or error  
  29.     status_t setReply(const sp<AMessage> &reply);  
  30. };  
这个类先放着,到底干嘛用的一会再说。

我们还是从源头上来看,这种情形通常是从AMessage的对象调用postAndAwaitResponse开始的,这个函数有一个参数是sp<AMessage>*类型了,sp包含的已经是指针了,那这里显然是一个out型的参数,也就是在调用结束后这个参数会被赋值。我们先看看这个函数的定义。
  1. status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {  
  2.   
  3.     sp<ALooper> looper = mLooper.promote();  
  4.     if (looper == NULL) {  
  5.         ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);  
  6.         return -ENOENT;  
  7.     }  
  8.   
  9.     sp<AReplyToken> token = looper->createReplyToken();  
  10.     if (token == NULL) {  
  11.         ALOGE("failed to create reply token");  
  12.         return -ENOMEM;  
  13.     }  
  14.     setObject("replyID", token);  
  15.   
  16.     looper->post(this, 0 /* delayUs */);  
  17.     return looper->awaitResponse(token, response);  
  18.   
  19. }  
首先拿到looper调用createReplyToken创建了一个token,这点我们一会来看,紧接着looper调用post把消息post出去了。最后调用了looper的awaitResponse方法,这个方法的代码前面已经给出,我们这里再单独拿出来看看
  1. // to be called by AMessage::postAndAwaitResponse only  
  2. status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {  
  3.     // return status in case we want to handle an interrupted wait  
  4.     Mutex::Autolock autoLock(mRepliesLock);  
  5.     CHECK(replyToken != NULL);  
  6.     while (!replyToken->retrieveReply(response)) {  
  7.         {  
  8.             Mutex::Autolock autoLock(mLock);  
  9.             if (mThread == NULL) {  
  10.                 return -ENOENT;  
  11.             }  
  12.         }  
  13.         mRepliesCondition.wait(mRepliesLock);  
  14.     }  
  15.     return OK;  
  16. }  
很明显该函数会在mRepliesCondition这个条件变量上等待,直到条件变成replyToken->retrieveReply返回ture。通过上面的代码可以知道这里的replyToken就是刚才从AMessage传过来的,但是有时这个Looper自己调用createReplyToken创建的,而这个创建不过就是调用了AReplyToken的构造函数,然后把Looper自己的指针传了过去。这到底有啥关联呢,我们先不着急看这个,先看看mRepliesCondition这个条件变量在何时才能signal或者broadcast,找到突破口,一共有两处一处是postReply方法,一处是stop方法,不用看也知道stop是万万不行滴。那么就只能是这个postReply了,代码如下:
  1. status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {  
  2.     Mutex::Autolock autoLock(mRepliesLock);  
  3.     status_t err = replyToken->setReply(reply);  
  4.     if (err == OK) {  
  5.         mRepliesCondition.broadcast();  
  6.     }  
  7.     return err;  
  8. }  
处理唤醒broadcast调用外,还调用了replyToken的setReply方法,先看看这个setReply,前面已经给出过代码了,这里重复一下:
  1. status_t AReplyToken::setReply(const sp<AMessage> &reply) {  
  2.     if (mReplied) {  
  3.         ALOGE("trying to post a duplicate reply");  
  4.         return -EBUSY;  
  5.     }  
  6.     CHECK(mReply == NULL);  
  7.     mReply = reply;  
  8.     mReplied = true;  
  9.     return OK;  
  10. }  
做了两件事情,给成员mReply赋值为参数,mReplied赋值为ture,好像看不出来啥用。我们接着看看上面的postReply既然broadcast已经发了,那么之前在ALooper::awaitResponse函数中while循环也得跳出吧,现在是时候看看这个while中的retrieveReply返回啥玩意了。

  1. bool retrieveReply(sp<AMessage> *reply) {  
  2.     if (mReplied) {  
  3.         *reply = mReply;  
  4.         mReply.clear();  
  5.     }  
  6.     return mReplied;  
  7. }  
  8. // sets the reply for this token. returns OK or error  
  9. status_t setReply(const sp<AMessage> &reply);  
直接看返回语句,这个返回的值就是mReplied,也就是说如果mReplied为ture这事就算了了,这样就和前面的setReply对上了,只要调用setReply的这个AReplyToken和postReply参数里的那个token是同一个,这个条件变量就可以被唤醒了。那么问题是,谁来做这个postReply的发起人呢,token又从哪来,那么对外的接口而言,AMessage是首当其冲的,所以从它开始找,一找就找到了。AMessage有一个同名函数也叫postReply,刚好就调用了ALooper的postReply函数,我们来仔细看看。
  1. status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {  
  2.     if (replyToken == NULL) {  
  3.         ALOGW("failed to post reply to a NULL token");  
  4.         return -ENOENT;  
  5.     }  
  6.     sp<ALooper> looper = replyToken->getLooper();  
  7.     if (looper == NULL) {  
  8.         ALOGW("failed to post reply as target looper is gone.");  
  9.         return -ENOENT;  
  10.     }  
  11.     return looper->postReply(replyToken, this);  
  12. }  
调用很简单,问题还是没变token从哪来。我们回想一下刚才在最初调用postAndAwaitResponse中,通过looper的createReplyToken函数创建了一个token,AMessage还通过setObject("replyID", token);这句把它设置为自己的一个item字段,这样我们想在唤醒时再次取到这个token当然要通过AMessage变量来了。直接告知答案了,AMessage有一个叫senderAwaitsResponse的方法,就是干这事的。
  1. bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {  
  2.     sp<RefBase> tmp;  
  3.     bool found = findObject("replyID", &tmp);  
  4.     if (!found) {  
  5.         return false;  
  6.     }  
  7.     *replyToken = static_cast<AReplyToken *>(tmp.get());  
  8.     tmp.clear();  
  9.     setObject("replyID", tmp);  
  10.   
  11.     // TODO: delete Object instead of setting it to NULL  
  12.     return *replyToken != NULL;  
  13. }  

代码中的参数replyToken是一个sp的指针,也就表示在函数中会对这个sp赋值,所以我们只需要声明一个sp<AReplyToken>对象,然后传入它的指针即可。
这样我们便拿到了这个token,那由谁来发送呢?答案是谁都可以,我们回想一下,AMessage的postReply方法是从参数token中拿到looper然后一路调用下去的,跟之前的AMessage可是没一点关系了。所以只需创建一个新的AMessage就行了。
一般的习惯用法,给出一个伪代码的参考:

sp<AMessage> msg = new AMessage(what, handler);
sp<AMessage> response;
msg->postAndAwaitResponse(response);


接收的Handler在处理完消息后发送答复:
  1. sp<AReplyToken> replyID;  
  2. CHECK(msg->senderAwaitsResponse(&replyID));  
  3. sp<AMessage> response = new AMessage;  
  4. response->postReply(replyID);  

这样整个await的消息就完成了。

文中有一点没有介绍,那就是ALooper有一个registerHandler的方法,这个方法除了调用AHandler的setID将Looper和Handler关联起来之外,其中还引出了一个LooperRoster的类型,而且是一个全局对象,那么这个对象有什么用,这个registerHandler方法不调用行不行,留给各位自己研究啦。 大笑
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值