AMessage,AHandler和ALooper源碼分析
AMessage繼承自RefBase類,它有AHandler和ALooper的成員mHandler和mLooper,並且ALooper還是它的友元。成員變量mWhat是消息id,成員變量mTarget指明消息的handler(只用於調試)。成員函數setWhat和setTarget分別設置這兩個屬性。
void AMessage::setWhat(uint32_t what) {
68 mWhat = what;
69}
70
71uint32_t AMessage::what() const {
72 return mWhat;
73}
74
75void AMessage::setTarget(const sp<const AHandler> &handler) {
76 if (handler == NULL) {
77 mTarget = 0;
78 mHandler.clear();
79 mLooper.clear();
80 } else {
81 mTarget = handler->id();
82 mHandler = handler->getHandler();
83 mLooper = handler->getLooper();
84 }
85}
成員函數what返回mWhat屬性。而setTarget方法,如果參數handler等於NULL,就把mTarget生成NULL(0),同時清空mHandler和mLooper隊列;否則,mTarget設成handler的id,mHandler和mLooper分別設置成handler中的handler和looper。
AMessage中有一組set函數:
void setInt32(const char *name, int32_t value);
98 void setInt64(const char *name, int64_t value);
99 void setSize(const char *name, size_t value);
100 void setFloat(const char *name, float value);
101 void setDouble(const char *name, double value);
102 void setPointer(const char *name, void *value);
103 void setString(const char *name, const char *s, ssize_t len = -1);
104 void setString(const char *name, const AString &s);
105 void setObject(const char *name, const sp<RefBase> &obj);
106 void setBuffer(const char *name, const sp<ABuffer> &buffer);
107 void setMessage(const char *name, const sp<AMessage> &obj);
108
109 void setRect(
110 const char *name,
111 int32_t left, int32_t top, int32_t right, int32_t bottom);
用來設置name對應的值。與之對應的又一組find函數:
bool findInt32(const char *name, int32_t *value) const;
116 bool findInt64(const char *name, int64_t *value) const;
117 bool findSize(const char *name, size_t *value) const;
118 bool findFloat(const char *name, float *value) const;
119 bool findDouble(const char *name, double *value) const;
120 bool findPointer(const char *name, void **value) const;
121 bool findString(const char *name, AString *value) const;
122 bool findObject(const char *name, sp<RefBase> *obj) const;
123 bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
124 bool findMessage(const char *name, sp<AMessage> *obj) const;
125
126 // finds any numeric type cast to a float
127 bool findAsFloat(const char *name, float *value) const;
128
129 bool findRect(
130 const char *name,
131 int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
用來根據name查找對應的值。
這裏我們重點分析一下setMessage和findMessage的實現。首先看setMessage的代碼:
void AMessage::setMessage(const char *name, const sp<AMessage> &obj) {
Item *item = allocateItem(name);
item->mType = kTypeMessage;
if (obj != NULL) { obj->incStrong(this); }
item->u.refValue = obj.get();
}
首先調用allocateItem,根據name創建一個Item,item的type設置成kTypeMessage。如果參數obj不等於NULL,就增加obj的強引用計數,同時,item中的refValue要設置成參數obj的值。kTypeMessage是一個枚舉值,它的定義在AMessage.h中:
enum Type {
167 kTypeInt32,
168 kTypeInt64,
169 kTypeSize,
170 kTypeFloat,
171 kTypeDouble,
172 kTypePointer,
173 kTypeString,
174 kTypeObject,
175 kTypeMessage,
176 kTypeRect,
177 kTypeBuffer,
178 };
這裏用到的allocateItem函數的代碼是這樣的:
AMessage::Item *AMessage::allocateItem(const char *name) {
187 size_t len = strlen(name);
188 size_t i = findItemIndex(name, len);
189 Item *item;
190
191 if (i < mNumItems) {
192 item = &mItems[i];
193 freeItemValue(item);
194 } else {
195 CHECK(mNumItems < kMaxNumItems);
196 i = mNumItems++;
197 item = &mItems[i];
198 item->setName(name, len);
199 }
200
201 return item;
202}
獲取name的長度,調用findItemIndex獲取那麼的index i。如果i小於mNumItems,使item指向mItems的第i個item,然後調用freeItemValue,釋放對應的item。如果i大於或等於mNumItems,檢查mNumItems是否小於kMaxNumItems。mNumItems的值賦值給i,然後使mNumItems的值加1,item指向mItems的第i個item,設置item的name爲參數name。findItemIndex的代碼如下:
inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
151#ifdef DUMP_STATS
152 size_t memchecks = 0;
153#endif
154 size_t i = 0;
155 for (; i < mNumItems; i++) {
156 if (len != mItems[i].mNameLength) {
157 continue;
158 }
159#ifdef DUMP_STATS
160 ++memchecks;
161#endif
162 if (!memcmp(mItems[i].mName, name, len)) {
163 break;
164 }
165 }
166#ifdef DUMP_STATS
167 {
168 Mutex::Autolock _l(gLock);
169 ++gFindItemCalls;
170 gAverageNumItems += mNumItems;
171 gAverageNumMemChecks += memchecks;
172 gAverageNumChecks += i;
173 reportStats();
174 }
175#endif
176 return i;
177}
這是一個內聯函數。
· freeItemValue
freeItemValue的代碼如下:
void AMessage::freeItemValue(Item *item) {
98 switch (item->mType) {
99 case kTypeString:
100 {
101 delete item->u.stringValue;
102 break;
103 }
104
105 case kTypeObject:
106 case kTypeMessage:
107 case kTypeBuffer:
108 {
109 if (item->u.refValue != NULL) {
110 item->u.refValue->decStrong(this);
111 }
112 break;
113 }
114
115 default:
116 break;
117 }
118}
119
根據item的類型,執行不同的free操作。
· findMessage
下面我們再來分析一下findMessage的代碼:
bool AMessage::findMessage(const char *name, sp<AMessage> *obj) const {
350 const Item *item = findItem(name, kTypeMessage);
351 if (item) {
352 *obj = static_cast<AMessage *>(item->u.refValue);
353 return true;
354 }
355 return false;
356}
比較簡單,調用findItem,根據那麼,和類型“kTypeMessage”,調用findItem獲取item,如果item不爲NULL,就把item的refValue轉化爲AMessage類型的指針,返回true;否則,返回false。
AMessage中,我們最關心的是以下方法:postAndAwaitResponse等。
status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
396 sp<ALooper> looper = mLooper.promote();
397 if (looper == NULL) {
398 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
399 return -ENOENT;
400 }
401
402 sp<AReplyToken> token = looper->createReplyToken();
403 if (token == NULL) {
404 ALOGE("failed to create reply token");
405 return -ENOMEM;
406 }
407 setObject("replyID", token);
408
409 looper->post(this, 0 /* delayUs */);
410 return looper->awaitResponse(token, response);
411}
412
413status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
414 if (replyToken == NULL) {
415 ALOGW("failed to post reply to a NULL token");
416 return -ENOENT;
417 }
418 sp<ALooper> looper = replyToken->getLooper();
419 if (looper == NULL) {
420 ALOGW("failed to post reply as target looper is gone.");
421 return -ENOENT;
422 }
423 return looper->postReply(replyToken, this);
424}
postAndAwaitResponse方法中,首先通過mLooper的promote方法,獲取ALooper的一個強引用計數looper,如果looper爲NULL,直接返回ENOMEM。通過looper->createReplyToken()創建AReplyToken的強引用計數token。調用setObject("replyID", token)
設置replyID。調用looper->post(this, 0 /* delayUs */)發送消息,然後,looper->awaitResponse(token, response)等待返回。
AHandler類
AHandler類的代碼比較簡單,其中定義了一個ALooper的弱引用計數mLooper,一個ALooper::handler_id類型的mID。其中的deliverMessage方法代碼如下:
void AHandler::deliverMessage(const sp<AMessage> &msg) {
27 onMessageReceived(msg);
28 mMessageCounter++;
29
30 if (mVerboseStats) {
31 uint32_t what = msg->what();
32 ssize_t idx = mMessages.indexOfKey(what);
33 if (idx < 0) {
34 mMessages.add(what, 1);
35 } else {
36 mMessages.editValueAt(idx)++;
37 }
38 }
39}
首先觸發本類的onMessageReceived(msg),這是一個純虛函數,子類中需要有它的具體實現。然後把Message技術mMessageCounter加1。獲取message的類型(what)和idx。如果idx小於0,在mMessages中添加一個what類型的消息;否則,編輯idx出的Message。
ALooper類
ALooper類也是RefBase的子類。ALooper中有一個內部的struct LooperThread,繼承自Thread,並且,這個struct中有一個指向ALooper類型的指針mLooper。ALooper中的成員變量mThread是一個LooperThread的強引用計數。ALooper的start方法開啓Looper,其代碼如下:
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}
如果runOnCallingThread爲true(在調用線程運行),首先使用mLock加同步鎖,如果mThread爲NULL,或者mRunningLocally爲true(在本地線程運行),直接返回INVALID_OPERATION。將mRunningLocally設爲true。執行一個無限循環,直到loop方法返回false爲止。返回OK。如果runOnCallingThread爲false,先用mLock加同步鎖,如果mThread爲NULL,或者mRunningLocally爲true(在本地線程運行),直接返回INVALID_OPERATION。生成一個新的LooperThread,賦值給mThread。調用mThread的run方法。如果run方法返回的狀態不是OK,需要調用clear方法。
loop方法的代碼如下:
bool ALooper::loop() {
195 Event event;
196
197 {
198 Mutex::Autolock autoLock(mLock);
199 if (mThread == NULL && !mRunningLocally) {
200 return false;
201 }
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}
首先加同步鎖。如果mThread爲NULL,或者mRunningLocally爲false(非本地線程執行),返回false。如果mEventQueue列表爲空,等待解鎖,並且返回true。獲取mEventQueue中的一個元素的mWhenUs屬性(當時的微秒數)whenUs,以及當前的微秒數nowUs,如果whenUs大於nowUs,whenUs減去nowUs的差值delayUs。等待一個delayUs * 1000的相對時間後解鎖,並返回true。獲取mQueue中的第一個event,並且從mQueue中移除這個event。調用event.mMessage->deliver()投遞消息到handler,返回true。
mEventQueue中的Event從何而來呢?是通過post方法加入的。post方法的代碼如下:
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}
首先要加同步鎖,得到whenUs的值,通過迭代器遍歷mEventQueue,在mEventQueue中找到mWhenUs大於whenUs的Event的位置。創建新Event,event的mWhenUs就是之前的whenUs,mMessage是參數msg。如果找到的位置位於mEventQueue的開始,直接調用mQueueChangedCondition.signal()激活解鎖。把event插入到前面找到的位置。
ALooper中還有個重要的方法stop:
status_t ALooper::stop() {
133 sp<LooperThread> thread;
134 bool runningLocally;
135
136 {
137 Mutex::Autolock autoLock(mLock);
138
139 thread = mThread;
140 runningLocally = mRunningLocally;
141 mThread.clear();
142 mRunningLocally = false;
143 }
144
145 if (thread == NULL && !runningLocally) {
146 return INVALID_OPERATION;
147 }
148
149 if (thread != NULL) {
150 thread->requestExit();
151 }
152
153 mQueueChangedCondition.signal();
154 {
155 Mutex::Autolock autoLock(mRepliesLock);
156 mRepliesCondition.broadcast();
157 }
158
159 if (!runningLocally && !thread->isCurrentThread()) {
160 // If not running locally and this thread _is_ the looper thread,
161 // the loop() function will return and never be called again.
162 thread->requestExitAndWait();
163 }
164
165 return OK;
166}
首先加同步鎖,調用mThread的clear,恢復mRunningLocally爲false。如果thread爲NULL,或者mRunningLocally爲false,返回INVALID_OPERATION。stop主要做一些退出前的清理操作。