AMessage简析

作者: TankWitch | 来源:发表于2017-08-15 23:59 被阅读0次

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

    可以看到, 有两个构造函数.

    1. 不带参数的构造函数三个字段直接全部赋值为0
    2. 带参数的构造函数, 将发送的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);
    }
    

    这个函数做了两件事情

    1. 将设置的len给了mNameLength字段, 标明name的长度;
    2. 分配空间, 将设置的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的情况.

    1. 首先看到一个for循环, 其实就是在这个循环中, 找到我们设置的len长度相匹配的名字(长度为len, 名字为name的项)
    2. 返回这个项的下标

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

    很简单, 说明一下

    1. 获取到要设置的name的len, 并根据这个len和name在Items中找找看有没有设置过;
    2. 如果有, 那就删除该位置的值(stringValue或者是refValue的情况); 否则, 给mNumItems数组的下一个空的元素赋值
    3. 返回这个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;
    }
    
    1. 首先在Items中寻找看有木有对应的上name和type的Item
    2. 如果有, 再看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();
    }
    

    这个方法也是很基础的, 简单来说

    1. 为一个Item对象分配了内存, 并且对type字段赋值
    2. 如果传入的指针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;
    }
    
    1. 在键值对Items中, 根据name找到item;
    2. 如果找到了, 将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}
    
    1. 首先绑定上一个处理者handler;
    2. 使用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}
    
    1. 首先绑定了在构造函数中就已传入的消息监测者ALooper;
    2. 调用了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    }
    
    1. 绑定上构造函数中就传入了ALooper;
    2. 创建一个AReplyToken(在ALooper中讲过);
    3. 将name"replyID"和这个token绑定在一起形成键值对;
    4. 立即post这个消息;
    5. 返回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吧

    总结

    分析到这里, 算是告一段落了吧. 因为时间和水平有限, 讲解的难免会有纰漏和错误, 还请各位看官批评指正.

    相关文章

      网友评论

        本文标题:AMessage简析

        本文链接:https://www.haomeiwen.com/subject/praerxtx.html