作为AMessage/ALooper/AHandler中最复杂的一环, AMessage被我放到了最后来讲. 希望能讲的简洁明了.
声明
#ifndef A_MESSAGE_H_
#define A_MESSAGE_H_
#include <media/stagefright/foundation/ABase.h>
#include <media/stagefright/foundation/ALooper.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
namespace android {
struct ABuffer;
struct AHandler;
struct AString;
class Parcel;
//在讲ALooper的时候已经讲过了
struct AReplyToken : public RefBase {
AReplyToken(const sp<ALooper> &looper)
: mLooper(looper),
mReplied(false) {
}
private:
friend struct AMessage;
friend struct ALooper;
wp<ALooper> mLooper;
sp<AMessage> mReply;
bool mReplied;
//获得指定Looper的使用权
sp<ALooper> getLooper() const {
return mLooper.promote();
}
// if reply is not set, returns false; otherwise, it retrieves the reply and returns true
bool retrieveReply(sp<AMessage> *reply) {
if (mReplied) {
*reply = mReply;
mReply.clear();
}
return mReplied;
}
// sets the reply for this token. returns OK or error
status_t setReply(const sp<AMessage> &reply);
};
struct AMessage : public RefBase {
AMessage();
AMessage(uint32_t what, const sp<const AHandler> &handler);
// Construct an AMessage from a parcel.
// nestingAllowed determines how many levels AMessage can be nested inside
// AMessage. The default value here is arbitrarily set to 255.
// FromParcel() returns NULL on error, which occurs when the input parcel
// contains
// - an AMessage nested deeper than maxNestingLevel; or
// - an item whose type is not recognized by this function.
// Types currently recognized by this function are:
// Item types set/find function suffixes
// ==========================================
// int32_t Int32
// int64_t Int64
// size_t Size
// float Float
// double Double
// AString String
// AMessage Message
//从Parcel中获取AMessage
static sp<AMessage> FromParcel(const Parcel &parcel,
size_t maxNestingLevel = 255);
// Write this AMessage to a parcel.
// All items in the AMessage must have types that are recognized by
// FromParcel(); otherwise, TRESPASS error will occur.
//将Parcel写入AMessage
void writeToParcel(Parcel *parcel) const;
//设置whay值相关(用于传递)
void setWhat(uint32_t what);
uint32_t what() const;
void setTarget(const sp<const AHandler> &handler);
void clear();
//以下就是各种set值了(用于传递消息)
void setInt32(const char *name, int32_t value);
void setInt64(const char *name, int64_t value);
void setSize(const char *name, size_t value);
void setFloat(const char *name, float value);
void setDouble(const char *name, double value);
void setPointer(const char *name, void *value);
void setString(const char *name, const char *s, ssize_t len = -1);
void setString(const char *name, const AString &s);
void setObject(const char *name, const sp<RefBase> &obj);
void setBuffer(const char *name, const sp<ABuffer> &buffer);
void setMessage(const char *name, const sp<AMessage> &obj);
void setRect(
const char *name,
int32_t left, int32_t top, int32_t right, int32_t bottom);
bool contains(const char *name) const;
//以下是对应的各种find值(用于得到传递的消息)
bool findInt32(const char *name, int32_t *value) const;
bool findInt64(const char *name, int64_t *value) const;
bool findSize(const char *name, size_t *value) const;
bool findFloat(const char *name, float *value) const;
bool findDouble(const char *name, double *value) const;
bool findPointer(const char *name, void **value) const;
bool findString(const char *name, AString *value) const;
bool findObject(const char *name, sp<RefBase> *obj) const;
bool findBuffer(const char *name, sp<ABuffer> *buffer) const;
bool findMessage(const char *name, sp<AMessage> *obj) const;
// finds any numeric type cast to a float
bool findAsFloat(const char *name, float *value) const;
bool findRect(
const char *name,
int32_t *left, int32_t *top, int32_t *right, int32_t *bottom) const;
//post消息
status_t post(int64_t delayUs = 0);
// Posts the message to its target and waits for a response (or error)
// before returning.
//同步操作, post消息等待回复
status_t postAndAwaitResponse(sp<AMessage> *response);
// If this returns true, the sender of this message is synchronously
// awaiting a response and the reply token is consumed from the message
// and stored into replyID. The reply token must be used to send the response
// using "postReply" below.
bool senderAwaitsResponse(sp<AReplyToken> *replyID);
// Posts the message as a response to a reply token. A reply token can
// only be used once. Returns OK if the response could be posted; otherwise,
// an error.
status_t postReply(const sp<AReplyToken> &replyID);
// Performs a deep-copy of "this", contained messages are in turn "dup'ed".
// Warning: RefBase items, i.e. "objects" are _not_ copied but only have
// their refcount incremented.
sp<AMessage> dup() const;
// Performs a shallow or deep comparison of |this| and |other| and returns
// an AMessage with the differences.
// Warning: RefBase items, i.e. "objects" are _not_ copied but only have
// their refcount incremented.
// This is true for AMessages that have no corresponding AMessage equivalent in |other|.
// (E.g. there is no such key or the type is different.) On the other hand, changes in
// the AMessage (or AMessages if deep is |false|) are returned in new objects.
sp<AMessage> changesFrom(const sp<const AMessage> &other, bool deep = false) const;
AString debugString(int32_t indent = 0) const;
//键值对中的"键"
enum Type {
kTypeInt32,
kTypeInt64,
kTypeSize,
kTypeFloat,
kTypeDouble,
kTypePointer,
kTypeString,
kTypeObject,
kTypeMessage,
kTypeRect,
kTypeBuffer,
};
size_t countEntries() const;
const char *getEntryNameAt(size_t index, Type *type) const;
protected:
virtual ~AMessage();
private:
friend struct ALooper; // deliver()
uint32_t mWhat;
// used only for debugging
ALooper::handler_id mTarget;
wp<AHandler> mHandler;
wp<ALooper> mLooper;
struct Rect {
int32_t mLeft, mTop, mRight, mBottom;
};
//键值对中的"值"
struct Item {
union {
int32_t int32Value;
int64_t int64Value;
size_t sizeValue;
float floatValue;
double doubleValue;
void *ptrValue;
RefBase *refValue;
AString *stringValue;
Rect rectValue;
} u;
const char *mName;
size_t mNameLength;
Type mType;
void setName(const char *name, size_t len);
};
enum {
kMaxNumItems = 64
};
Item mItems[kMaxNumItems];
size_t mNumItems;
Item *allocateItem(const char *name);
void freeItemValue(Item *item);
const Item *findItem(const char *name, Type type) const;
void setObjectInternal(
const char *name, const sp<RefBase> &obj, Type type);
size_t findItemIndex(const char *name, size_t len) const;
void deliver();
DISALLOW_EVIL_CONSTRUCTORS(AMessage);
};
} // namespace android
#endif // A_MESSAGE_H_
在讲头文件进行了简要的注释后, 我们来看看CPP文件中, 几个以后比较常见也比较重要的方法是长什么样子的.
构造函数
AMessage::AMessage(void)
: mWhat(0),
mTarget(0),
mNumItems(0) {
}
AMessage::AMessage(uint32_t what, const sp<const AHandler> &handler)
: mWhat(what),
mNumItems(0) {
setTarget(handler);
}
可以看到, 有两个构造函数.
- 不带参数的构造函数三个字段直接全部赋值为0
- 带参数的构造函数, 将发送的what值和发送哪一个handler(处理者)指定了
有同学会问,setTarget
具体长什么样子? 好嘛, 给你看.
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();
}
}
其实, 就是把handler的ID呀, handler自身呀和handler所在的Looper拿到了手中.
set/find系列相关方法
在了解各种setXXX和findXXX方法之前, 有两个关于Item的方法, 值得我们看一下.
1. void AMessage::Item::setName(const char *name, size_t len)
// assumes item's name was uninitialized or NULL
void AMessage::Item::setName(const char *name, size_t len) {
mNameLength = len;
mName = new char[len + 1];
memcpy((void*)mName, name, len + 1);
}
这个函数做了两件事情
- 将设置的len给了mNameLength字段, 标明name的长度;
- 分配空间, 将设置的name复制到分配给字段mName的内存空间中;
2. inline size_t AMessage::findItemIndex(const char *name, size_t len) const
inline size_t AMessage::findItemIndex(const char *name, size_t len) const {
#ifdef DUMP_STATS
size_t memchecks = 0;
#endif
size_t i = 0;
for (; i < mNumItems; i++) {
if (len != mItems[i].mNameLength) {
continue;
}
#ifdef DUMP_STATS
++memchecks;
#endif
if (!memcmp(mItems[i].mName, name, len)) {
break;
}
}
#ifdef DUMP_STATS
{
Mutex::Autolock _l(gLock);
++gFindItemCalls;
gAverageNumItems += mNumItems;
gAverageNumMemChecks += memchecks;
gAverageNumChecks += i;
reportStats();
}
#endif
return i;
}
这里分析下没有打开宏DUMP_STATS
的情况.
- 首先看到一个for循环, 其实就是在这个循环中, 找到我们设置的len长度相匹配的名字(长度为len, 名字为name的项)
- 返回这个项的下标
3. AMessage::Item *AMessage::allocateItem(const char *name)
AMessage::Item *AMessage::allocateItem(const char *name) {
size_t len = strlen(name);
size_t i = findItemIndex(name, len);
Item *item;
if (i < mNumItems) {
item = &mItems[i];
freeItemValue(item);
} else {
CHECK(mNumItems < kMaxNumItems);
i = mNumItems++;
item = &mItems[i];
item->setName(name, len);
}
return item;
}
这个方法里面包含了一个freeItemValue
, 什么滴干活? 释放资源的干活, 不单独讲了.
void AMessage::freeItemValue(Item *item) {
switch (item->mType) {
case kTypeString:
{
delete item->u.stringValue;
break;
}
case kTypeObject:
case kTypeMessage:
case kTypeBuffer:
{
if (item->u.refValue != NULL) {
item->u.refValue->decStrong(this);
}
break;
}
default:
break;
}
}
很简单, 说明一下
- 获取到要设置的name的len, 并根据这个len和name在Items中找找看有没有设置过;
- 如果有, 那就删除该位置的值(stringValue或者是refValue的情况); 否则, 给mNumItems数组的下一个空的元素赋值
- 返回这个item(注意: 是一个指针, 指向刚刚操作过的元素)
4. const AMessage::Item * AMessage::findItem(const char *name, Type type)
const AMessage::Item *AMessage::findItem(
const char *name, Type type) const {
size_t i = findItemIndex(name, strlen(name));
if (i < mNumItems) {
const Item *item = &mItems[i];
return item->mType == type ? item : NULL;
}
return NULL;
}
- 首先在Items中寻找看有木有对应的上name和type的Item
- 如果有, 再看type是否对的上; 对的上的返回这个item, 其他情况, 一概返回NULL
5. void AMessage::setObjectInternal(const char *name, const sp<RefBase> &obj, Type type)
void AMessage::setObjectInternal(
const char *name, const sp<RefBase> &obj, Type type) {
Item *item = allocateItem(name);
item->mType = type;
if (obj != NULL) { obj->incStrong(this); }
item->u.refValue = obj.get();
}
这个方法也是很基础的, 简单来说
- 为一个Item对象分配了内存, 并且对type字段赋值
- 如果传入的指针obj不为空, 变为强指针且, 获得这个指针(赋值给refValue)
6. 两个重要的setXXX
1) AMessage::setBuffer
void AMessage::setBuffer(const char *name, const sp<ABuffer> &buffer) {
setObjectInternal(name, sp<RefBase>(buffer), kTypeBuffer);
}
调用了setObjectInternal
, 将name和指向这段buffer的指针对应起来了(通过创建的Item(键值对))
2) AMessage::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();
}
同样, 调用了setObjectInternal
, 将name和指向这个AMessage的指针对应起来了(通过创建的Item(键值对))
7. 对应的findXXX
findXXX系列方法大同小异, 这里仅仅选择一个作为代表吧
bool AMessage::findBuffer(const char *name, sp<ABuffer> *buf) const {
const Item *item = findItem(name, kTypeBuffer);
if (item) {
*buf = (ABuffer *)(item->u.refValue);
return true;
}
return false;
}
- 在键值对Items中, 根据name找到item;
- 如果找到了, 将ABuff类型的指针, 指向之前setBuffer设置好的buffer
8. void AMessage::deliver()
347 void AMessage::deliver() {
348 sp<AHandler> handler = mHandler.promote();
349 if (handler == NULL) {
350 ALOGW("failed to deliver message as target handler %d is gone.", mTarget);
351 return;
352 }
353
354 handler->deliverMessage(this);
355}
- 首先绑定上一个处理者handler;
- 使用handler的deliverMessage方法;
deliverMessage
方法, 我们在<AHanlder简析>一节中看到过, 就是放到Message的onMessageReceived中处理, 有兴趣的童鞋可以返回去看看, 这里不再说明了.
9. 发送消息相关方法
9.1 status_t AMessage::post(int64_t delayUs)
357 status_t AMessage::post(int64_t delayUs) {
358 sp<ALooper> looper = mLooper.promote();
359 if (looper == NULL) {
360 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
361 return -ENOENT;
362 }
363
364 looper->post(this, delayUs);
365 return OK;
366}
- 首先绑定了在构造函数中就已传入的消息监测者ALooper;
- 调用了looper的post. 这个post的方法在<ALooper>一节中讲到过, 这里就不再敖述.
9.2 AMessage::postAndAwaitResponse(sp<AMessage> *response)
368 status_t AMessage::postAndAwaitResponse(sp<AMessage> *response) {
369 sp<ALooper> looper = mLooper.promote();
370 if (looper == NULL) {
371 ALOGW("failed to post message as target looper for handler %d is gone.", mTarget);
372 return -ENOENT;
373 }
374
375 sp<AReplyToken> token = looper->createReplyToken();
376 if (token == NULL) {
377 ALOGE("failed to create reply token");
378 return -ENOMEM;
379 }
380 setObject("replyID", token);
381
382 looper->post(this, 0 /* delayUs */);
383 return looper->awaitResponse(token, response);
384 }
- 绑定上构造函数中就传入了ALooper;
- 创建一个AReplyToken(在ALooper中讲过);
- 将name"replyID"和这个token绑定在一起形成键值对;
- 立即post这个消息;
- 返回post这个消息后, 接收方返回的消息;
9.3 status_t AMessage::postReply(const sp<AReplyToken> &replyToken)
386 status_t AMessage::postReply(const sp<AReplyToken> &replyToken) {
387 if (replyToken == NULL) {
388 ALOGW("failed to post reply to a NULL token");
389 return -ENOENT;
390 }
391 sp<ALooper> looper = replyToken->getLooper();
392 if (looper == NULL) {
393 ALOGW("failed to post reply as target looper is gone.");
394 return -ENOENT;
395 }
396 return looper->postReply(replyToken, this);
397 }
和9.2所讲到的postAndAwaitResponse对应. 这里就是把AReplayToken和消息回复给传递消息过来, 并且要求回复的
9.4
399 bool AMessage::senderAwaitsResponse(sp<AReplyToken> *replyToken) {
400 sp<RefBase> tmp;
401 bool found = findObject("replyID", &tmp);
402
403 if (!found) {
404 return false;
405 }
406
407 *replyToken = static_cast<AReplyToken *>(tmp.get());
408 tmp.clear();
409 setObject("replyID", tmp);
410 // TODO: delete Object instead of setting it to NULL
411
412 return *replyToken != NULL;
413 }
经过前面两个方法的洗礼, 这里大概大家都能一眼看书来, 这里就是换一个replayToken吧
总结
分析到这里, 算是告一段落了吧. 因为时间和水平有限, 讲解的难免会有纰漏和错误, 还请各位看官批评指正.