Android多媒體框架(4)—— AMessage,AHandler和ALooper源碼分析

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主要做一些退出前的清理操作。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章