AMessageの概要

17301 ワード

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);
}

2つの構造関数が見られる.
  • パラメータを持たない構造関数の3つのフィールドは、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のIDやhandler自身やhandlerのいるLooperを手に入れたのです.

    set/findシリーズ関連メソッド


    様々なsetXXXとfindXXXの方法を理解する前に、Itemに関する2つの方法があって、私たちが見る価値があります.

    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つのことをしました
  • は、設定された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 &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


    1) AMessage::setBuffer

    void AMessage::setBuffer(const char *name, const sp &buffer) {
        setObjectInternal(name, sp(buffer), kTypeBuffer);
    }
    
    setObjectInternalが呼び出され、nameとこのbufferを指すポインタが対応した(作成された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の方法は、一節で見たことがありますが、MessageのonMessageReceivedに置いて処理することです.興味のある子供靴は戻って見てもいいです.ここでは説明しません.

    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の方法は一節で述べたが,ここではもう述べない.

  • 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します.
  • 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    }
    

    前の2つの方法の洗礼を経て、ここはたぶんみんな本を一目で見ることができて、ここはreplayTokenを交換することでしょう

    まとめ


    ここまで分析すると、一段落したでしょう.時間とレベルが限られているため、説明の漏れや間違いは避けられない.