接著ALooper、AMessage入蛆、AHandler的簡(jiǎn)述,現(xiàn)在來(lái)分析下ALooper的聲明以及定義硕勿。
聲明
這篇重在細(xì)節(jié)哨毁,廢話不多說(shuō),各位看官搬好小板凳源武,且請(qǐng)看代碼(已加注釋)扼褪。
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/AString.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>
#include <utils/RefBase.h>
#include <utils/threads.h>
namespace android {
//前置聲明,在ALooper中只用到了這三個(gè)結(jié)構(gòu)體的指針或者引用粱栖。至于為什么要使用前置聲明话浇,我在C/C++專欄會(huì)寫
struct AHandler;
struct AMessage;
struct AReplyToken;
struct ALooper : public RefBase {
typedef int32_t event_id;
typedef int32_t handler_id;
//構(gòu)造函數(shù)
ALooper();
// Takes effect in a subsequent call to start().
//給這個(gè)Looper起名字
void setName(const char *name);
//將一個(gè)Handler注冊(cè)其中
handler_id registerHandler(const sp<AHandler> &handler);
//注銷對(duì)應(yīng)ID的AHandler
void unregisterHandler(handler_id handlerID);
//啟動(dòng)該Looper的獨(dú)立線程
status_t start(
bool runOnCallingThread = false,
bool canCallJava = false,
int32_t priority = PRIORITY_DEFAULT
);
//停止該Looper的獨(dú)立線程
status_t stop();
//獲得當(dāng)前的系統(tǒng)時(shí)間
static int64_t GetNowUs();
//獲取當(dāng)前Looper的名字
const char *getName() const {
return mName.c_str();
}
protected:
virtual ~ALooper();
private:
friend struct AMessage; // post()
//包裝Message
struct Event {
int64_t mWhenUs;
sp<AMessage> mMessage;
};
Mutex mLock;
Condition mQueueChangedCondition;
AString mName;
List<Event> mEventQueue;
//繼承于Thread
struct LooperThread;
sp<LooperThread> mThread;
bool mRunningLocally;
// use a separate lock for reply handling, as it is always on another thread
// use a central lock, however, to avoid creating a mutex for each reply
Mutex mRepliesLock;
Condition mRepliesCondition;
// START --- methods used only by AMessage
// posts a message on this looper with the given timeout
void post(const sp<AMessage> &msg, int64_t delayUs);
// creates a reply token to be used with this looper
sp<AReplyToken> createReplyToken();
// waits for a response for the reply token. If status is OK, the response
// is stored into the supplied variable. Otherwise, it is unchanged.
status_t awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response);
// posts a reply for a reply token. If the reply could be successfully posted,
// it returns OK. Otherwise, it returns an error value.
status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);
// END --- methods used only by AMessage
//如果有隊(duì)列中有消息,且未超過(guò)等待時(shí)間闹究,則將隊(duì)列頭的消息交付給對(duì)應(yīng)的handler處理
bool loop();
DISALLOW_EVIL_CONSTRUCTORS(ALooper);
};
下面幔崖,將就代碼中和結(jié)構(gòu)相關(guān)的部分簡(jiǎn)要分析一下。
struct Event {
int64_t mWhenUs;
sp<AMessage> mMessage;
};
List<Event> mEventQueue;
可以看到渣淤,Event結(jié)構(gòu)體對(duì)Message以及該Message所對(duì)應(yīng)的入隊(duì)時(shí)間進(jìn)行的組裝赏寇。而后,又將這些進(jìn)入該Looper的消息進(jìn)行的一個(gè)排隊(duì)(用一個(gè)List包起來(lái))砂代。如果大家還記得之前《ALooper蹋订、AMessage、AHandler的簡(jiǎn)述》一篇的圖1的話刻伊,就能很好的理解露戒,為什么稱ALooper為消息隊(duì)列了。
定義
下面捶箱,將就代碼中和重要功能相關(guān)的部分簡(jiǎn)要分析一下智什。
1. void ALooper::post(const sp<AMessage> &msg, int64_t delayUs)
168 void ALooper::post(const sp<AMessage> &msg, int64_t delayUs) {
169 Mutex::Autolock autoLock(mLock);
170
171 int64_t whenUs;
172 if (delayUs > 0) {
173 whenUs = GetNowUs() + delayUs;
174 } else {
175 whenUs = GetNowUs();
176 }
177
178 List<Event>::iterator it = mEventQueue.begin();
179 while (it != mEventQueue.end() && (*it).mWhenUs <= whenUs) {
180 ++it;
181 }
182
183 Event event;
184 event.mWhenUs = whenUs;
185 event.mMessage = msg;
186
187 if (it == mEventQueue.begin()) {
188 mQueueChangedCondition.signal();
189 }
190
191 mEventQueue.insert(it, event);
192}
這個(gè)函數(shù)很簡(jiǎn)單。
- 根據(jù)設(shè)置的delayUS(延時(shí)交付時(shí)間)和NowUS(系統(tǒng)時(shí)間)來(lái)計(jì)算真正這條Message需要交付的時(shí)間丁屎。
- 之后再根據(jù)這個(gè)時(shí)間計(jì)算當(dāng)前Message在消息隊(duì)列中的位置荠锭。
- 如果該消息是隊(duì)列頭消息,就通知一下(等待中的線程中只有一個(gè)會(huì)被喚醒執(zhí)行)晨川。
- 如果不是就加入到隊(duì)列的相應(yīng)位置中败京。
2. status_t postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &msg);
252 status_t ALooper::postReply(const sp<AReplyToken> &replyToken, const sp<AMessage> &reply) {
253 Mutex::Autolock autoLock(mRepliesLock);
254 status_t err = replyToken->setReply(reply);
255 if (err == OK) {
256 mRepliesCondition.broadcast();
257 }
258 return err;
259}
先看看replyToken是個(gè)什么鬼(他住在AMessage的家里)
33 struct AReplyToken : public RefBase {
34 AReplyToken(const sp<ALooper> &looper)
35 : mLooper(looper),
36 mReplied(false) {
37 }
再看看setReply做了什么事情。
40 status_t AReplyToken::setReply(const sp<AMessage> &reply) {
41 if (mReplied) {
42 ALOGE("trying to post a duplicate reply");
43 return -EBUSY;
44 }
45 CHECK(mReply == NULL);
46 mReply = reply;
47 mReplied = true;
48 return OK;
49}
現(xiàn)在就很清楚了
- 創(chuàng)建一個(gè)和當(dāng)前Looper相關(guān)聯(lián)的AReplyToken 隐绵,并且初始化reply狀態(tài)為false缠局,就是還沒(méi)有回復(fù)。
- 之后將reply的消息和reply的狀態(tài)(變?yōu)閠rue妈拌,意為這個(gè)時(shí)候已經(jīng)回復(fù)了)給這個(gè)ReplyToken
- 如果成功返回OK拥坛,就廣播一下(等待的線程都會(huì)被喚醒)
3. status_t ALooper::start(bool runOnCallingThread, bool canCallJava, int32_t priority)
96 status_t ALooper::start(
97 bool runOnCallingThread, bool canCallJava, int32_t priority) {
98 if (runOnCallingThread) {
99 {
100 Mutex::Autolock autoLock(mLock);
101
102 if (mThread != NULL || mRunningLocally) {
103 return INVALID_OPERATION;
104 }
105
106 mRunningLocally = true;
107 }
108
109 do {
110 } while (loop());
111
112 return OK;
113 }
114
115 Mutex::Autolock autoLock(mLock);
116
117 if (mThread != NULL || mRunningLocally) {
118 return INVALID_OPERATION;
119 }
120
121 mThread = new LooperThread(this, canCallJava);
122
123 status_t err = mThread->run(
124 mName.empty() ? "ALooper" : mName.c_str(), priority);
125 if (err != OK) {
126 mThread.clear();
127 }
128
129 return err;
130}
首先,我們可以知道這是該Looper線程啟動(dòng)的函數(shù). 當(dāng)設(shè)置了runOnCallingThread
為true的時(shí)候, 對(duì)應(yīng)邏輯里面有一個(gè)重要的代碼段:
do {
} while (loop());
那這個(gè)loop() 是干嘛用的? 我們來(lái)看一看.
194 bool ALooper::loop() {
195 Event event;
196
197 {
198 Mutex::Autolock autoLock(mLock);
199 if (mThread == NULL && !mRunningLocally) {
200 return false;
201 }//如果沒(méi)有分到線程且沒(méi)有在本地運(yùn)行,返回錯(cuò)誤
202 if (mEventQueue.empty()) {
203 mQueueChangedCondition.wait(mLock);
204 return true;
205 }
206 int64_t whenUs = (*mEventQueue.begin()).mWhenUs;
207 int64_t nowUs = GetNowUs();
208
209 if (whenUs > nowUs) {
210 int64_t delayUs = whenUs - nowUs;
211 mQueueChangedCondition.waitRelative(mLock, delayUs * 1000ll);
212
213 return true;
214 }
215
216 event = *mEventQueue.begin();
217 mEventQueue.erase(mEventQueue.begin());
218 }
219
220 event.mMessage->deliver();
221
222 // NOTE: It's important to note that at this point our "ALooper" object
223 // may no longer exist (its final reference may have gone away while
224 // delivering the message). We have made sure, however, that loop()
225 // won't be called again.
226
227 return true;
228}
重要的有以下幾點(diǎn)
if (mEventQueue.empty()) {
mQueueChangedCondition.wait(mLock);
return true;
}
不知道大家是否還記得,之前講異步消息機(jī)制簡(jiǎn)述那一篇中, 有提到過(guò)說(shuō), ALooper會(huì)檢查消息隊(duì)列中消息是否為空, 如果為空, 則等待事件, 降低CPU資源的消耗. 那么這段代碼就是上面所說(shuō)的具體實(shí)現(xiàn)了.
之后, 會(huì)判斷whenUS和nowUS, 根據(jù)這兩個(gè)值的比較來(lái)判斷是否還需要等待一段時(shí)間處理Event.
緊接著, 用上面定義了的Event event, 拿到消息隊(duì)列的列頭, 并清除原隊(duì)列的列頭.
最后, 交付這個(gè)消息. (這個(gè)交付的實(shí)現(xiàn), 會(huì)在AMessage中講解)
好回到start()
代碼的接下來(lái)的流程中. 接下來(lái)就很簡(jiǎn)單了:
- 創(chuàng)建一個(gè)LooperThread的實(shí)例;
- 把這個(gè)實(shí)例線程跑起來(lái).
接下來(lái),講兩個(gè)和AMessage::postAndAwaitResponse
方法緊密相連的兩個(gè)方法. 一個(gè)是ALooper::createReplyToken()
, 而另外一個(gè)是ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response)
首先, 來(lái)了解下
4. ALooper::createReplyToken()
這個(gè)玩意兒的代碼如下:
230 // to be called by AMessage::postAndAwaitResponse only
231 sp<AReplyToken> ALooper::createReplyToken() {
232 return new AReplyToken(this);
233 }
沒(méi)錯(cuò), 沒(méi)干什么事情, 只是用當(dāng)前的Looper, 實(shí)例化了一個(gè)AReplyToken(在第2點(diǎn)鐘有提到這個(gè)東東)并返回.
接著,來(lái)看這個(gè)
5. ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response)
它長(zhǎng)這個(gè)樣子:
236 status_t ALooper::awaitResponse(const sp<AReplyToken> &replyToken, sp<AMessage> *response) {
237 // return status in case we want to handle an interrupted wait
238 Mutex::Autolock autoLock(mRepliesLock);
239 CHECK(replyToken != NULL);
240 while (!replyToken->retrieveReply(response)) {
241 {
242 Mutex::Autolock autoLock(mLock);
243 if (mThread == NULL) {
244 return -ENOENT;
245 }
246 }
247 mRepliesCondition.wait(mRepliesLock);
248 }
249 return OK;
250}
我們遇到了陌生的retrieveReply
, 他長(zhǎng)這個(gè)樣子:
49 // if reply is not set, returns false; otherwise, it retrieves the reply and returns true
50 bool retrieveReply(sp<AMessage> *reply) {
51 if (mReplied) {
52 *reply = mReply;
53 mReply.clear();
54 }
55 return mReplied;
56 }
原生注釋已經(jīng)說(shuō)得很清楚了. 如果replay沒(méi)有設(shè)置,就返回false; 否則, 就獲得這個(gè)replay的Message并返回true.
回到awaitResponse
中. 當(dāng)retrieveReply
返回false, 也就是說(shuō)沒(méi)有拿到需要replay的Message的時(shí)候, 等待著, 一直等待到拿到這個(gè)消息為止(各位看官, 這里就是為了實(shí)現(xiàn)postAndAwaitResponse
的同步的目的了哦)
總結(jié)
這篇講述了一個(gè)叫ALooper的履帶。它將AMessage根據(jù)交付時(shí)間(whenUs)進(jìn)行排隊(duì)(List<mEvent>)。然后簡(jiǎn)單介紹了它是怎么將消息(AMessage交付的(有同步的, 也有異步的))猜惋。關(guān)于交付這一塊是不完整的丸氛,大部分的邏輯在AMessage中,今天先介紹到這里著摔,有空再寫最復(fù)雜的AMessage和相對(duì)簡(jiǎn)單的AHandler缓窜。