AMessage 간략 분석

17396 단어
AMessage/ALooper/AHandler 중 가장 복잡한 일환으로서 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);
}

보시다시피 두 개의 구조 함수가 있습니다.
  • 파라미터가 없는 구조 함수 세 필드의 전체 값은 0
  • 매개 변수를 가진 구조 함수는 발송된 what값과 발송된 어떤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);
    }
    

    이 함수는 두 가지 일을 했다
  • mNameLength 필드에 설정된len을 주고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, 이름은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 &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();
    }
    

    이 방법도 매우 기초적인 것으로 간단하게 말하면
  • Item 객체에 메모리를 할당하고 type 필드에 값을 부여합니다
  • .
  • 전송된 바늘obj가 비어 있지 않으면 강한 바늘로 변하고 이 바늘(refValue)
  • 을 획득합니다
    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;
    }
    
  • 키 값 대 Items에서name에 따라 item을 찾기;
  • 찾으면 ABuff 형식의 바늘을 이전에 setBuffer가 설정한 buffer
  • 를 가리킨다
    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}
    
  • 먼저 이전 처리자handler를 연결한다.
  • handler의 deliverMessage 방법 사용하기;
  • 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}
    
  • 구조 함수에 이미 전송된 메시지 모니터링자Alooper를 먼저 귀속시켰다.
  • looper의post를 호출했습니다.이post의 방법은 1절에서 말한 적이 있으니, 여기서는 더 이상 서술하지 않겠다.

  • 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    }
    
  • 귀속된 구조 함수에서 Alooper가 전송되었습니다.
  • AreplyToken(Alooper에서 말했듯이)을 창설한다.
  • name'replyID'와 이token을 연결하여 키 값 쌍을 형성한다.
  • 즉시 이 소식을 전하기;
  • post라는 메시지를 반환한 후 수신자가 반환한 메시지;

  • 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으로 바꾸자.
    총결산
    여기까지 분석했으니 일단락된 셈이다.시간과 수준에 한계가 있기 때문에 해설에 실수와 착오가 있을 수 있으니 여러분의 비평과 시정을 바랍니다.

    좋은 웹페이지 즐겨찾기