Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8814904b authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "MediaMetrics: Update Item serialization code"

parents f90425de 3253f2d6
Loading
Loading
Loading
Loading
+15 −8
Original line number Diff line number Diff line
@@ -55,13 +55,17 @@ public:

        Parcel data;
        data.writeInterfaceToken(IMediaAnalyticsService::getInterfaceDescriptor());
        item->writeToParcel(&data);

        status_t err = remote()->transact(
        status_t status = item->writeToParcel(&data);
        if (status != NO_ERROR) { // assume failure logged in item
            return status;
        }

        status = remote()->transact(
                SUBMIT_ITEM_ONEWAY, data, nullptr /* reply */, IBinder::FLAG_ONEWAY);
        ALOGW_IF(err != NO_ERROR, "%s: bad response from service for submit, err=%d",
                __func__, err);
        return err;
        ALOGW_IF(status != NO_ERROR, "%s: bad response from service for submit, status=%d",
                __func__, status);
        return status;
    }
};

@@ -79,11 +83,14 @@ status_t BnMediaAnalyticsService::onTransact(
        CHECK_INTERFACE(IMediaAnalyticsService, data, reply);

        MediaAnalyticsItem * const item = MediaAnalyticsItem::create();
        if (item->readFromParcel(data) < 0) {
            return BAD_VALUE;
        status_t status = item->readFromParcel(data);
        if (status != NO_ERROR) { // assume failure logged in item
            return status;
        }
        // TODO: remove this setPid.
        item->setPid(clientPid);
        const status_t status __unused = submitInternal(item, true /* release */);
        status = submitInternal(item, true /* release */);
        // assume failure logged by submitInternal
        return NO_ERROR;
    } break;

+515 −325

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -195,6 +195,6 @@ bool mediametrics_isEnabled() {
bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length) {
    android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
    if (item == NULL) return false;
    return item->dumpAttributes(buffer, length);
    return item->writeToByteString(buffer, length) == android::NO_ERROR;

}
+230 −89
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@

#include "MediaMetrics.h"

#include <algorithm>
#include <string>
#include <sys/types.h>

@@ -34,8 +35,44 @@ namespace android {
class IMediaAnalyticsService;
class Parcel;

// the class interface
//
/*
 * Media Metrics
 * Byte String format for communication of MediaAnalyticsItem.
 *
 * .... begin of item
 * .... begin of header
 * (uint32) length: including the length field itself
 * (uint32) header length, including header_length and length fields.
 * (uint16) version: 0
 * (uint16) key length, including zero termination
 * (int8)+ key string, including 0 termination
 * (int32) pid
 * (int32) uid
 * (int64) timestamp
 * .... end of header
 * .... begin body
 * (uint32) properties
 * #properties of the following:
 *     (uint16) property_length, including property_length field itself
 *     (uint8) type of property
 *     (int8)+ key string, including 0 termination
 *      based on type of property (above), one of:
 *       (int32)
 *       (int64)
 *       (double)
 *       (int8)+ for cstring, including 0 termination
 *       (int64, int64) for rate
 * .... end body
 * .... end of item
 */

/**
 * Media Metrics MediaAnalyticsItem
 *
 * A mutable item representing an event or record that will be
 * logged with the Media Metrics service.
 *
 */

class MediaAnalyticsItem {
    friend class MediaMetricsJNI;           // TODO: remove this access
@@ -52,21 +89,9 @@ public:
                kTypeRate = 5,
            };

    // Key: the record descriminator
    // values for the record discriminator
    // values can be "component/component"
    // basic values: "video", "audio", "drm"
    // XXX: need to better define the format
    using Key = std::string;
    static constexpr const char * const kKeyNone = "none";
    static constexpr const char * const kKeyAny = "any";

        // Attr: names for attributes within a record
        // format "prop1" or "prop/subprop"
        // XXX: need to better define the format
        typedef const char *Attr;


        enum {
            PROTO_V0 = 0,
            PROTO_FIRST = PROTO_V0,
@@ -78,11 +103,36 @@ public:
    template <typename T>
    explicit MediaAnalyticsItem(T key)
        : mKey(key) { }
    MediaAnalyticsItem() = default;

    MediaAnalyticsItem(const MediaAnalyticsItem&) = delete;
    MediaAnalyticsItem &operator=(const MediaAnalyticsItem&) = delete;

        static MediaAnalyticsItem* create(Key key);
        static MediaAnalyticsItem* create();
    bool operator==(const MediaAnalyticsItem& other) const {
        if (mPropCount != other.mPropCount
            || mPid != other.mPid
            || mUid != other.mUid
            || mPkgName != other.mPkgName
            || mPkgVersionCode != other.mPkgVersionCode
            || mKey != other.mKey
            || mTimestamp != other.mTimestamp) return false;
         for (size_t i = 0; i < mPropCount; ++i) {
             Prop *p = other.findProp(mProps[i].getName());
             if (p == nullptr || mProps[i] != *p) return false;
         }
         return true;
    }
    bool operator!=(const MediaAnalyticsItem& other) const {
        return !(*this == other);
    }

    template <typename T>
    static MediaAnalyticsItem* create(T key) {
        return new MediaAnalyticsItem(key);
    }
    static MediaAnalyticsItem* create() {
        return new MediaAnalyticsItem();
    }

        static MediaAnalyticsItem* convert(mediametrics_handle_t);
        static mediametrics_handle_t convert(MediaAnalyticsItem *);
@@ -94,13 +144,14 @@ public:
        void clear();
        MediaAnalyticsItem *dup();

        // set the key discriminator for the record.
        // most often initialized as part of the constructor
        MediaAnalyticsItem &setKey(MediaAnalyticsItem::Key);
        const MediaAnalyticsItem::Key& getKey() const { return mKey; }
    MediaAnalyticsItem &setKey(const char *key) {
        mKey = key;
        return *this;
    }
    const std::string& getKey() const { return mKey; }

        // # of attributes in the record
        int32_t count() const;
    // # of properties in the record
    size_t count() const { return mPropCount; }

    template<typename S, typename T>
    MediaAnalyticsItem &set(S key, T value) {
@@ -109,19 +160,19 @@ public:
    }

    // set values appropriately
    MediaAnalyticsItem &setInt32(Attr key, int32_t value) {
    MediaAnalyticsItem &setInt32(const char *key, int32_t value) {
        return set(key, value);
    }
    MediaAnalyticsItem &setInt64(Attr key, int64_t value) {
    MediaAnalyticsItem &setInt64(const char *key, int64_t value) {
        return set(key, value);
    }
    MediaAnalyticsItem &setDouble(Attr key, double value) {
    MediaAnalyticsItem &setDouble(const char *key, double value) {
        return set(key, value);
    }
    MediaAnalyticsItem &setRate(Attr key, int64_t count, int64_t duration) {
    MediaAnalyticsItem &setRate(const char *key, int64_t count, int64_t duration) {
        return set(key, std::make_pair(count, duration));
    }
    MediaAnalyticsItem &setCString(Attr key, const char *value) {
    MediaAnalyticsItem &setCString(const char *key, const char *value) {
        return set(key, value);
    }

@@ -133,16 +184,16 @@ public:
        return *this;
    }

    MediaAnalyticsItem &addInt32(Attr key, int32_t value) {
    MediaAnalyticsItem &addInt32(const char *key, int32_t value) {
        return add(key, value);
    }
    MediaAnalyticsItem &addInt64(Attr key, int64_t value) {
    MediaAnalyticsItem &addInt64(const char *key, int64_t value) {
        return add(key, value);
    }
    MediaAnalyticsItem &addDouble(Attr key, double value) {
    MediaAnalyticsItem &addDouble(const char *key, double value) {
        return add(key, value);
    }
    MediaAnalyticsItem &addRate(Attr key, int64_t count, int64_t duration) {
    MediaAnalyticsItem &addRate(const char *key, int64_t count, int64_t duration) {
        return add(key, std::make_pair(count, duration));
    }

@@ -155,16 +206,16 @@ public:
        return prop != nullptr && prop->get(value);
    }

    bool getInt32(Attr key, int32_t *value) const {
    bool getInt32(const char *key, int32_t *value) const {
        return get(key, value);
    }
    bool getInt64(Attr key, int64_t *value) const {
    bool getInt64(const char *key, int64_t *value) const {
        return get(key, value);
    }
    bool getDouble(Attr key, double *value) const {
    bool getDouble(const char *key, double *value) const {
        return get(key, value);
    }
    bool getRate(Attr key, int64_t *count, int64_t *duration, double *rate) const {
    bool getRate(const char *key, int64_t *count, int64_t *duration, double *rate) const {
        std::pair<int64_t, int64_t> value;
        if (!get(key, &value)) return false;
        if (count != nullptr) *count = value.first;
@@ -179,10 +230,15 @@ public:
        return true;
    }
    // Caller owns the returned string
    bool getCString(Attr key, char **value) const {
        return get(key, value);
    bool getCString(const char *key, char **value) const {
        const char *cs;
        if (get(key, &cs)) {
            *value = cs != nullptr ? strdup(cs) : nullptr;
            return true;
        }
    bool getString(Attr key, std::string *value) const {
        return false;
    }
    bool getString(const char *key, std::string *value) const {
        return get(key, value);
    }

@@ -194,9 +250,9 @@ public:
    // return value is # attributes removed
    // XXX: perhaps 'remove' instead of 'filter'
    // XXX: filterNot would become 'keep'
        int32_t filter(int count, Attr attrs[]);
        int32_t filterNot(int count, Attr attrs[]);
        int32_t filter(Attr attr);
    size_t filter(size_t count, const char *attrs[]);
    size_t filterNot(size_t count, const char *attrs[]);
    size_t filter(const char *attr) { return filter(1, &attr); }

        // below here are used on server side or to talk to server
        // clients need not worry about these.
@@ -219,11 +275,25 @@ public:
        int64_t getPkgVersionCode() const;

    // our serialization code for binder calls
        int32_t writeToParcel(Parcel *);
        int32_t readFromParcel(const Parcel&);

        // supports the stable interface
        bool dumpAttributes(char **pbuffer, size_t *plength);
    status_t writeToParcel(Parcel *) const;
    status_t readFromParcel(const Parcel&);

    status_t writeToByteString(char **bufferptr, size_t *length) const;
    status_t readFromByteString(const char *bufferptr, size_t length);

    static status_t writeToByteString(
            const char *name, int32_t value, char **bufferpptr, char *bufferptrmax);
    static status_t writeToByteString(
            const char *name, int64_t value, char **bufferpptr, char *bufferptrmax);
    static status_t writeToByteString(
            const char *name, double value, char **bufferpptr, char *bufferptrmax);
    static status_t writeToByteString(
            const char *name, const std::pair<int64_t, int64_t> &value, char **bufferpptr, char *bufferptrmax);
    static status_t writeToByteString(
            const char *name, char * const &value, char **bufferpptr, char *bufferptrmax);
    struct none_t {}; // for kTypeNone
    static status_t writeToByteString(
            const char *name, const none_t &, char **bufferpptr, char *bufferptrmax);

        std::string toString() const;
        std::string toString(int version) const;
@@ -233,11 +303,6 @@ public:
        // are we collecting analytics data
        static bool isEnabled();

    private:
        // handle Parcel version 0
        int32_t writeToParcel0(Parcel *);
        int32_t readFromParcel0(const Parcel&);

    protected:

        // merge fields from arg into this
@@ -246,18 +311,32 @@ public:
        // caller continues to own 'incoming'
        bool merge(MediaAnalyticsItem *incoming);

private:
    // handle Parcel version 0
    int32_t writeToParcel0(Parcel *) const;
    int32_t readFromParcel0(const Parcel&);

    // enabled 1, disabled 0
    static constexpr const char * const EnabledProperty = "media.metrics.enabled";
    static constexpr const char * const EnabledPropertyPersist = "persist.media.metrics.enabled";
    static const int EnabledProperty_default = 1;

    private:

    // let's reuse a binder connection
    static sp<IMediaAnalyticsService> sAnalyticsService;
    static sp<IMediaAnalyticsService> getInstance();
    static void dropInstance();

    // checks equality even with nullptr.
    static bool stringEquals(const char *a, const char *b) {
        if (a == nullptr) {
            return b == nullptr;
        } else {
            return b != nullptr && strcmp(a, b) == 0;
        }
    }

public:

    class Prop {
    friend class MediaMetricsJNI;           // TODO: remove this access
    public:
@@ -271,7 +350,6 @@ public:
            } else {
                mName = nullptr;
            }
            mNameLen = other.mNameLen;
            mType = other.mType;
            switch (mType) {
            case kTypeInt32:
@@ -287,7 +365,7 @@ public:
                u.CStringValue = strdup(other.u.CStringValue);
                break;
            case kTypeRate:
                u.rate = {other.u.rate.count, other.u.rate.duration};
                u.rate = other.u.rate;
                break;
            case kTypeNone:
                break;
@@ -297,11 +375,32 @@ public:
            }
            return *this;
        }
        bool operator==(const Prop& other) const {
            if (!stringEquals(mName, other.mName)
                    || mType != other.mType) return false;
            switch (mType) {
            case kTypeInt32:
                return u.int32Value == other.u.int32Value;
            case kTypeInt64:
                return u.int64Value == other.u.int64Value;
            case kTypeDouble:
                return u.doubleValue == other.u.doubleValue;
            case kTypeCString:
                return stringEquals(u.CStringValue, other.u.CStringValue);
            case kTypeRate:
                return u.rate == other.u.rate;
            case kTypeNone:
            default:
                return true;
            }
        }
        bool operator!=(const Prop& other) const {
            return !(*this == other);
        }

        void clear() {
            free(mName);
            mName = nullptr;
            mNameLen = 0;
            clearValue();
        }
        void clearValue() {
@@ -322,29 +421,19 @@ public:

        void swap(Prop& other) {
            std::swap(mName, other.mName);
            std::swap(mNameLen, other.mNameLen);
            std::swap(mType, other.mType);
            std::swap(u, other.u);
        }

        void setName(const char *name, size_t len) {
        void setName(const char *name) {
            free(mName);
            if (name != nullptr) {
                mName = (char *)malloc(len + 1);
                mNameLen = len;
                strncpy(mName, name, len);
                mName[len] = 0;
                mName = strdup(name);
            } else {
                mName = nullptr;
                mNameLen = 0;
            }
        }

        bool isNamed(const char *name, size_t len) const {
            return len == mNameLen && memcmp(name, mName, len) == 0;
        }

        // TODO: remove duplicate but different definition
        bool isNamed(const char *name) const {
            return strcmp(name, mName) == 0;
        }
@@ -369,9 +458,9 @@ public:
           return true;
        }
        template <>
        bool get(char** value) const {
        bool get(const char** value) const {
            if (mType != kTypeCString) return false;
            if (value != nullptr) *value = strdup(u.CStringValue);
            if (value != nullptr) *value = u.CStringValue;
            return true;
        }
        template <>
@@ -384,8 +473,7 @@ public:
        bool get(std::pair<int64_t, int64_t> *value) const {
           if (mType != kTypeRate) return false;
           if (value != nullptr) {
               value->first = u.rate.count;
               value->second = u.rate.duration;
               *value = u.rate;
           }
           return true;
        }
@@ -416,7 +504,13 @@ public:
            if (value == nullptr) {
                u.CStringValue = nullptr;
            } else {
                u.CStringValue = strdup(value);
                size_t len = strlen(value);
                if (len > UINT16_MAX - 1) {
                    len = UINT16_MAX - 1;
                }
                u.CStringValue = (char *)malloc(len + 1);
                strncpy(u.CStringValue, value, len);
                u.CStringValue[len] = 0;
            }
        }
        template <>
@@ -456,33 +550,79 @@ public:
        template <>
        void add(const std::pair<int64_t, int64_t>& value) {
            if (mType == kTypeRate) {
                u.rate.count += value.first;
                u.rate.duration += value.second;
                u.rate.first += value.first;
                u.rate.second += value.second;
            } else {
                mType = kTypeRate;
                u.rate = {value.first, value.second};
                u.rate = value;
            }
        }

        void writeToParcel(Parcel *data) const;
        status_t writeToParcel(Parcel *data) const;
        status_t readFromParcel(const Parcel& data);
        void toString(char *buffer, size_t length) const;
        size_t getByteStringSize() const;
        status_t writeToByteString(char **bufferpptr, char *bufferptrmax) const;
        status_t readFromByteString(const char **bufferpptr, const char *bufferptrmax);

    // TODO: make private
    // TODO: make private (and consider converting to std::variant)
    // private:
        char *mName = nullptr;
        size_t mNameLen = 0;    // the strlen(), doesn't include the null
        Type mType = kTypeNone;
        union {
        union u__ {
            u__() { zero(); }
            u__(u__ &&other) {
                *this = std::move(other);
            }
            u__& operator=(u__ &&other) {
                memcpy(this, &other, sizeof(*this));
                other.zero();
                return *this;
            }
            void zero() { memset(this, 0, sizeof(*this)); }

            int32_t int32Value;
            int64_t int64Value;
            double doubleValue;
            char *CStringValue;
            struct { int64_t count, duration; } rate;
            std::pair<int64_t, int64_t> rate;
        } u;
    };

    size_t findPropIndex(const char *name, size_t len) const;
    class iterator {
    public:
       iterator(size_t pos, const MediaAnalyticsItem &_item)
           : i(std::min(pos, _item.count()))
           , item(_item) { }
       iterator &operator++() {
           i = std::min(i + 1, item.count());
           return *this;
       }
       bool operator!=(iterator &other) const {
           return i != other.i;
       }
       Prop &operator*() const {
           return item.mProps[i];
       }

    private:
      size_t i;
      const MediaAnalyticsItem &item;
    };

    iterator begin() const {
        return iterator(0, *this);
    }
    iterator end() const {
        return iterator(SIZE_MAX, *this);
    }

private:

    // TODO: make prop management class
    size_t findPropIndex(const char *name) const;
    Prop *findProp(const char *name) const;
    Prop *allocateProp();

        enum {
            kGrowProps = 10
@@ -490,6 +630,7 @@ public:
        bool growProps(int increment = kGrowProps);
        Prop *allocateProp(const char *name);
        bool removeProp(const char *name);
    Prop *allocateProp(const std::string& name) { return allocateProp(name.c_str()); }

        size_t mPropCount = 0;
        size_t mPropSize = 0;
@@ -499,7 +640,7 @@ public:
    uid_t         mUid = -1;
    std::string   mPkgName;
    int64_t       mPkgVersionCode = 0;
    Key           mKey{kKeyNone};
    std::string   mKey{kKeyNone};
    nsecs_t       mTimestamp = 0;
};

+1 −1
Original line number Diff line number Diff line
@@ -641,7 +641,7 @@ void NuPlayerDriver::logMetrics(const char *where) {
            mAnalyticsItem->setUid(mClientUid);
        }
    } else {
        ALOGV("nothing to record (only %d fields)", mAnalyticsItem->count());
        ALOGV("nothing to record (only %zu fields)", mAnalyticsItem->count());
    }
}

Loading