AMessage 간략 분석
성명
#ifndef A_MESSAGE_H_
#define A_MESSAGE_H_
#include
#include
#include
#include
namespace android {
struct ABuffer;
struct AHandler;
struct AString;
class Parcel;
// ALooper
struct AReplyToken : public RefBase {
AReplyToken(const sp &looper)
: mLooper(looper),
mReplied(false) {
}
private:
friend struct AMessage;
friend struct ALooper;
wp mLooper;
sp mReply;
bool mReplied;
// Looper
sp getLooper() const {
return mLooper.promote();
}
// if reply is not set, returns false; otherwise, it retrieves the reply and returns true
bool retrieveReply(sp *reply) {
if (mReplied) {
*reply = mReply;
mReply.clear();
}
return mReplied;
}
// sets the reply for this token. returns OK or error
status_t setReply(const sp &reply);
};
struct AMessage : public RefBase {
AMessage();
AMessage(uint32_t what, const sp &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 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 &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 &obj);
void setBuffer(const char *name, const sp &buffer);
void setMessage(const char *name, const sp &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 *obj) const;
bool findBuffer(const char *name, sp *buffer) const;
bool findMessage(const char *name, sp *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 *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 *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 &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 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 changesFrom(const sp &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 mHandler;
wp 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 &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 &handler)
: mWhat(what),
mNumItems(0) {
setTarget(handler);
}
보시다시피 두 개의 구조 함수가 있습니다.
setTarget
가 구체적으로 어떻게 생겼는지 물어본다.좋아, 보여줄게.void AMessage::setTarget(const sp &handler) {
if (handler == NULL) {
mTarget = 0;
mHandler.clear();
mLooper.clear();
} else {
mTarget = handler->id();
mHandler = handler->getHandler();
mLooper = handler->getLooper();
}
}
사실,handler의 아이디야,handler 자체야,handler가 있는 Looper를 손에 넣었다.
set/find 시리즈 관련 방법
각종 setXXX와findXX 방법을 이해하기 전에 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);
}
이 함수는 두 가지 일을 했다
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
가 열리지 않은 상황을 분석합니다.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;
}
}
간단합니다. 설명해 주세요.
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;
}
5. void AMessage::setObjectInternal(const char *name, const sp &obj, Type type)
void AMessage::setObjectInternal(
const char *name, const sp &obj, Type type) {
Item *item = allocateItem(name);
item->mType = type;
if (obj != NULL) { obj->incStrong(this); }
item->u.refValue = obj.get();
}
이 방법도 매우 기초적인 것으로 간단하게 말하면
6. 중요한 setXXX 2개
1)
AMessage::setBuffer
void AMessage::setBuffer(const char *name, const sp &buffer) {
setObjectInternal(name, sp(buffer), kTypeBuffer);
}
setObjectInternal
이 호출되었습니다.name과 이 버퍼를 가리키는 바늘이 대응합니다. (생성된 Item (키 값 쌍)2)
AMessage::setMessage
void AMessage::setMessage(const char *name, const sp &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 *buf) const {
const Item *item = findItem(name, kTypeBuffer);
if (item) {
*buf = (ABuffer *)(item->u.refValue);
return true;
}
return false;
}
8. void AMessage::deliver()
347 void AMessage::deliver() {
348 sp 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}
deliverMessage
방법, 우리가 1절에서 본 것은 바로 메시지의 onMessage Received에 넣고 처리하는 것이다. 관심 있는 어린이 신발은 되돌아가 볼 수 있다. 여기는 더 이상 설명하지 않는다.9. 메시지 발송 방법
9.1 status_t AMessage::post(int64_t delayUs)
357 status_t AMessage::post(int64_t delayUs) {
358 sp 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}
9.2 AMessage::postAndAwaitResponse(sp *response)
368 status_t AMessage::postAndAwaitResponse(sp *response) {
369 sp 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 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 }
9.3 status_t AMessage::postReply(const sp &replyToken)
386 status_t AMessage::postReply(const sp &replyToken) {
387 if (replyToken == NULL) {
388 ALOGW("failed to post reply to a NULL token");
389 return -ENOENT;
390 }
391 sp 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 *replyToken) {
400 sp tmp;
401 bool found = findObject("replyID", &tmp);
402
403 if (!found) {
404 return false;
405 }
406
407 *replyToken = static_cast(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으로 바꾸자.
총결산
여기까지 분석했으니 일단락된 셈이다.시간과 수준에 한계가 있기 때문에 해설에 실수와 착오가 있을 수 있으니 여러분의 비평과 시정을 바랍니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.