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

Commit c01a25e1 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove media metrics' unused 'summarizer' concept"

parents ab7429b4 813b1b8e
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -6,11 +6,6 @@ include $(CLEAR_VARS)

LOCAL_SRC_FILES:= \
    main_mediametrics.cpp              \
    MetricsSummarizerCodec.cpp         \
    MetricsSummarizerExtractor.cpp     \
    MetricsSummarizerPlayer.cpp        \
    MetricsSummarizerRecorder.cpp      \
    MetricsSummarizer.cpp              \
    MediaAnalyticsService.cpp

LOCAL_SHARED_LIBRARIES := \
+1 −156
Original line number Diff line number Diff line
@@ -74,26 +74,11 @@

#include "MediaAnalyticsService.h"

#include "MetricsSummarizer.h"
#include "MetricsSummarizerCodec.h"
#include "MetricsSummarizerExtractor.h"
#include "MetricsSummarizerPlayer.h"
#include "MetricsSummarizerRecorder.h"


namespace android {

    using namespace android::base;
    using namespace android::content::pm;



// summarized records
// up to 36 sets, each covering an hour -- so at least 1.5 days
// (will be longer if there are hours without any media action)
static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
static const int kMaxRecordSets = 36;

// individual records kept in memory: age or count
// age: <= 36 hours (1.5 days)
// count: hard limit of # records
@@ -108,57 +93,9 @@ void MediaAnalyticsService::instantiate() {
            String16(kServiceName), new MediaAnalyticsService());
}

// handle sets of summarizers
MediaAnalyticsService::SummarizerSet::SummarizerSet() {
    mSummarizers = new List<MetricsSummarizer *>();
}

MediaAnalyticsService::SummarizerSet::~SummarizerSet() {
    // empty the list
    List<MetricsSummarizer *> *l = mSummarizers;
    while (l->size() > 0) {
        MetricsSummarizer *summarizer = *(l->begin());
        l->erase(l->begin());
        delete summarizer;
    }
}

void MediaAnalyticsService::newSummarizerSet() {
    ALOGD("MediaAnalyticsService::newSummarizerSet");
    MediaAnalyticsService::SummarizerSet *set = new MediaAnalyticsService::SummarizerSet();
    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    set->setStarted(now);

    set->appendSummarizer(new MetricsSummarizerExtractor("extractor"));
    set->appendSummarizer(new MetricsSummarizerCodec("codec"));
    set->appendSummarizer(new MetricsSummarizerPlayer("nuplayer"));
    set->appendSummarizer(new MetricsSummarizerRecorder("recorder"));

    // ALWAYS at the end, since it catches everything
    set->appendSummarizer(new MetricsSummarizer(NULL));

    // inject this set at the BACK of the list.
    mSummarizerSets->push_back(set);
    mCurrentSet = set;

    // limit the # that we have
    if (mMaxRecordSets > 0) {
        List<SummarizerSet *> *l = mSummarizerSets;
        while (l->size() > (size_t) mMaxRecordSets) {
            ALOGD("Deleting oldest record set....");
            MediaAnalyticsService::SummarizerSet *oset = *(l->begin());
            l->erase(l->begin());
            delete oset;
            mSetsDiscarded++;
        }
    }
}

MediaAnalyticsService::MediaAnalyticsService()
        : mMaxRecords(kMaxRecords),
          mMaxRecordAgeNs(kMaxRecordAgeNs),
          mMaxRecordSets(kMaxRecordSets),
          mNewSetInterval(kNewSetIntervalNs),
          mDumpProto(MediaAnalyticsItem::PROTO_V1),
          mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {

@@ -167,9 +104,6 @@ MediaAnalyticsService::MediaAnalyticsService()
    mOpen = new List<MediaAnalyticsItem *>();
    mFinalized = new List<MediaAnalyticsItem *>();

    mSummarizerSets = new List<MediaAnalyticsService::SummarizerSet *>();
    newSummarizerSet();

    mItemsSubmitted = 0;
    mItemsFinalized = 0;
    mItemsDiscarded = 0;
@@ -204,8 +138,6 @@ MediaAnalyticsService::~MediaAnalyticsService() {
    }
    delete mFinalized;
    mFinalized = NULL;

    // XXX: clean out the summaries
}


@@ -315,13 +247,11 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
                oitem = NULL;
            } else {
                oitem->setFinalized(true);
                summarize(oitem);
                saveItem(mFinalized, oitem, 0);
            }
            // new record could itself be marked finalized...
            id = item->getSessionID();
            if (finalizing) {
                summarize(item);
                saveItem(mFinalized, item, 0);
                mItemsFinalized++;
            } else {
@@ -332,7 +262,6 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
            oitem->merge(item);
            id = oitem->getSessionID();
            if (finalizing) {
                summarize(oitem);
                saveItem(mFinalized, oitem, 0);
                mItemsFinalized++;
            }
@@ -350,7 +279,6 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
                delete item;
                item = NULL;
            } else {
                summarize(item);
                saveItem(mFinalized, item, 0);
                mItemsFinalized++;
            }
@@ -379,8 +307,6 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
    }

    // crack any parameters
    String16 summaryOption("-summary");
    bool summary = false;
    String16 protoOption("-proto");
    int chosenProto = mDumpProtoDefault;
    String16 clearOption("-clear");
@@ -396,8 +322,6 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
        String8 myarg(args[i]);
        if (args[i] == clearOption) {
            clear = true;
        } else if (args[i] == summaryOption) {
            summary = true;
        } else if (args[i] == protoOption) {
            i++;
            if (i < n) {
@@ -444,7 +368,6 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
            result.append("Recognized parameters:\n");
            result.append("-help        this help message\n");
            result.append("-proto #     dump using protocol #");
            result.append("-summary     show summary info\n");
            result.append("-clear       clears out saved records\n");
            result.append("-only X      process records for component X\n");
            result.append("-since X     include records since X\n");
@@ -464,12 +387,7 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)

    dumpHeaders(result, ts_since);

    // want exactly 1, to avoid confusing folks that parse the output
    if (summary) {
        dumpSummaries(result, ts_since, only.c_str());
    } else {
    dumpRecent(result, ts_since, only.c_str());
    }


    if (clear) {
@@ -526,40 +444,6 @@ void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
    }
}

// dump summary info
void MediaAnalyticsService::dumpSummaries(String8 &result, nsecs_t ts_since, const char *only) {
    const size_t SIZE = 512;
    char buffer[SIZE];
    int slot = 0;

    snprintf(buffer, SIZE, "\nSummarized Metrics:\n");
    result.append(buffer);

    if (only != NULL && *only == '\0') {
        only = NULL;
    }

    // have each of the distillers dump records
    if (mSummarizerSets != NULL) {
        List<SummarizerSet *>::iterator itSet = mSummarizerSets->begin();
        for (; itSet != mSummarizerSets->end(); itSet++) {
            nsecs_t when = (*itSet)->getStarted();
            if (when < ts_since) {
                continue;
            }
            List<MetricsSummarizer *> *list = (*itSet)->getSummarizers();
            List<MetricsSummarizer *>::iterator it = list->begin();
            for (; it != list->end(); it++) {
                if (only != NULL && strcmp(only, (*it)->getKey()) != 0) {
                    ALOGV("Told to omit '%s'", (*it)->getKey());
                }
                std::string distilled = (*it)->dumpSummary(slot, only);
                result.append(distilled.c_str());
            }
        }
    }
}

// the recent, detailed queues
void MediaAnalyticsService::dumpRecent(String8 &result, nsecs_t ts_since, const char * only) {
    const size_t SIZE = 512;
@@ -785,45 +669,6 @@ bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) {
    return false;
}

// insert into the appropriate summarizer.
// we make our own copy to save/summarize
void MediaAnalyticsService::summarize(MediaAnalyticsItem *item) {

    ALOGV("MediaAnalyticsService::summarize()");

    if (item == NULL) {
        return;
    }

    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
    if (mCurrentSet == NULL
        || (mCurrentSet->getStarted() + mNewSetInterval < now)) {
        newSummarizerSet();
    }

    if (mCurrentSet == NULL) {
        return;
    }

    List<MetricsSummarizer *> *summarizers = mCurrentSet->getSummarizers();
    List<MetricsSummarizer *>::iterator it = summarizers->begin();
    for (; it != summarizers->end(); it++) {
        if ((*it)->isMine(*item)) {
            break;
        }
    }
    if (it == summarizers->end()) {
        ALOGD("no handler for type %s", item->getKey().c_str());
        return;               // no handler
    }

    // invoke the summarizer. summarizer will make whatever copies
    // it wants; the caller retains ownership of item.

    (*it)->handleRecord(item);

}

// how long we hold package info before we re-fetch it
#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs

+0 −33
Original line number Diff line number Diff line
@@ -28,9 +28,6 @@

#include <media/IMediaAnalyticsService.h>

#include "MetricsSummarizer.h"


namespace android {

class MediaAnalyticsService : public BnMediaAnalyticsService
@@ -89,36 +86,6 @@ class MediaAnalyticsService : public BnMediaAnalyticsService
    MediaAnalyticsItem *findItem(List<MediaAnalyticsItem *> *,
                                     MediaAnalyticsItem *, bool removeit);

    // summarizers
    void summarize(MediaAnalyticsItem *item);
    class SummarizerSet {
        nsecs_t mStarted;
        List<MetricsSummarizer *> *mSummarizers;

      public:
        void appendSummarizer(MetricsSummarizer *s) {
            if (s) {
                mSummarizers->push_back(s);
            }
        };
        nsecs_t getStarted() { return mStarted;}
        void setStarted(nsecs_t started) {mStarted = started;}
        List<MetricsSummarizer *> *getSummarizers() { return mSummarizers;}

        SummarizerSet();
        ~SummarizerSet();
    };
    void newSummarizerSet();
    List<SummarizerSet *> *mSummarizerSets;
    SummarizerSet *mCurrentSet;
    List<MetricsSummarizer *> *getFirstSet() {
        List<SummarizerSet *>::iterator first = mSummarizerSets->begin();
        if (first != mSummarizerSets->end()) {
            return (*first)->getSummarizers();
        }
        return NULL;
    }

    void saveItem(MediaAnalyticsItem);
    void saveItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *, int);
    void deleteItem(List<MediaAnalyticsItem *> *, MediaAnalyticsItem *);
+0 −348
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "MetricsSummarizer"
#include <utils/Log.h>

#include <stdlib.h>
#include <stdint.h>
#include <string>
#include <inttypes.h>

#include <utils/threads.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/String8.h>
#include <utils/List.h>

#include <media/IMediaAnalyticsService.h>

#include "MetricsSummarizer.h"


namespace android {

#define DEBUG_SORT      0
#define DEBUG_QUEUE     0


MetricsSummarizer::MetricsSummarizer(const char *key)
    : mIgnorables(NULL)
{
    ALOGV("MetricsSummarizer::MetricsSummarizer");

    if (key == NULL) {
        mKey = key;
    } else {
        mKey = strdup(key);
    }

    mSummaries = new List<MediaAnalyticsItem *>();
}

MetricsSummarizer::~MetricsSummarizer()
{
    ALOGV("MetricsSummarizer::~MetricsSummarizer");
    if (mKey) {
        free((void *)mKey);
        mKey = NULL;
    }

    // clear the list of items we have saved
    while (mSummaries->size() > 0) {
        MediaAnalyticsItem * oitem = *(mSummaries->begin());
        if (DEBUG_QUEUE) {
            ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
                oitem->getKey().c_str(), oitem->getSessionID(),
                oitem->getTimestamp());
        }
        mSummaries->erase(mSummaries->begin());
        delete oitem;
    }
}

// so we know what summarizer we were using
const char *MetricsSummarizer::getKey() {
    const char *value = mKey;
    if (value == NULL) {
        value = "unknown";
    }
    return value;
}

// should the record be given to this summarizer
bool MetricsSummarizer::isMine(MediaAnalyticsItem &item)
{
    if (mKey == NULL)
        return true;
    std::string itemKey = item.getKey();
    if (strcmp(mKey, itemKey.c_str()) != 0) {
        return false;
    }
    return true;
}

std::string MetricsSummarizer::dumpSummary(int &slot)
{
    return dumpSummary(slot, NULL);
}

std::string MetricsSummarizer::dumpSummary(int &slot, const char *only)
{
    std::string value;

    List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
    if (it != mSummaries->end()) {
        char buf[16];   // enough for "#####: "
        for (; it != mSummaries->end(); it++) {
            if (only != NULL && strcmp(only, (*it)->getKey().c_str()) != 0) {
                continue;
            }
            std::string entry = (*it)->toString();
            snprintf(buf, sizeof(buf), "%5d: ", slot);
            value.append(buf);
            value.append(entry.c_str());
            value.append("\n");
            slot++;
        }
    }
    return value;
}

void MetricsSummarizer::setIgnorables(const char **ignorables) {
    mIgnorables = ignorables;
}

const char **MetricsSummarizer::getIgnorables() {
    return mIgnorables;
}

void MetricsSummarizer::handleRecord(MediaAnalyticsItem *item) {

    ALOGV("MetricsSummarizer::handleRecord() for %s",
                item == NULL ? "<nothing>" : item->toString().c_str());

    if (item == NULL) {
        return;
    }

    List<MediaAnalyticsItem *>::iterator it = mSummaries->begin();
    for (; it != mSummaries->end(); it++) {
        bool good = sameAttributes((*it), item, getIgnorables());
        ALOGV("Match against %s says %d", (*it)->toString().c_str(), good);
        if (good)
            break;
    }
    if (it == mSummaries->end()) {
            ALOGV("save new record");
            MediaAnalyticsItem *nitem = item->dup();
            if (nitem == NULL) {
                ALOGE("unable to save MediaMetrics record");
            }
            sortProps(nitem);
            nitem->setInt32("aggregated",1);
            mergeRecord(*nitem, *item);
            mSummaries->push_back(nitem);
    } else {
            ALOGV("increment existing record");
            (*it)->addInt32("aggregated",1);
            mergeRecord(*(*it), *item);
    }
}

void MetricsSummarizer::mergeRecord(MediaAnalyticsItem &/*have*/, MediaAnalyticsItem &/*item*/) {
    // default is no further massaging.
    ALOGV("MetricsSummarizer::mergeRecord() [default]");
    return;
}

// keep some stats for things: sums, counts, standard deviation
// the integer version -- all of these pieces are in 64 bits
void MetricsSummarizer::minMaxVar64(MediaAnalyticsItem &summation, const char *key, int64_t value) {
    if (key == NULL)
        return;
    int len = strlen(key) + 32;
    char *tmpKey = (char *)malloc(len);

    if (tmpKey == NULL) {
        return;
    }

    // N - count of samples
    snprintf(tmpKey, len, "%s.n", key);
    summation.addInt64(tmpKey, 1);

    // zero - count of samples that are zero
    if (value == 0) {
        snprintf(tmpKey, len, "%s.zero", key);
        int64_t zero = 0;
        (void) summation.getInt64(tmpKey,&zero);
        zero++;
        summation.setInt64(tmpKey, zero);
    }

    // min
    snprintf(tmpKey, len, "%s.min", key);
    int64_t min = value;
    if (summation.getInt64(tmpKey,&min)) {
        if (min > value) {
            summation.setInt64(tmpKey, value);
        }
    } else {
        summation.setInt64(tmpKey, value);
    }

    // max
    snprintf(tmpKey, len, "%s.max", key);
    int64_t max = value;
    if (summation.getInt64(tmpKey,&max)) {
        if (max < value) {
            summation.setInt64(tmpKey, value);
        }
    } else {
        summation.setInt64(tmpKey, value);
    }

    // components for mean, stddev;
    // stddev = sqrt(1/4*(sumx2 - (2*sumx*sumx/n) + ((sumx/n)^2)))
    // sum x
    snprintf(tmpKey, len, "%s.sumX", key);
    summation.addInt64(tmpKey, value);
    // sum x^2
    snprintf(tmpKey, len, "%s.sumX2", key);
    summation.addInt64(tmpKey, value*value);


    // last thing we do -- remove the base key from the summation
    // record so we won't get confused about it having both individual
    // and summary information in there.
    summation.removeProp(key);

    free(tmpKey);
}


//
// Comparators
//

// testing that all of 'single' is in 'summ'
// and that the values match.
// 'summ' may have extra fields.
// 'ignorable' is a set of things that we don't worry about matching up
// (usually time- or count-based values we'll sum elsewhere)
bool MetricsSummarizer::sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignorable) {

    if (single == NULL || summ == NULL) {
        return false;
    }
    ALOGV("MetricsSummarizer::sameAttributes(): summ %s", summ->toString().c_str());
    ALOGV("MetricsSummarizer::sameAttributes(): single %s", single->toString().c_str());

    // keep different sources/users separate
    if (single->mUid != summ->mUid) {
        return false;
    }

    // this can be made better.
    for(size_t i=0;i<single->mPropCount;i++) {
        MediaAnalyticsItem::Prop *prop1 = &(single->mProps[i]);
        const char *attrName = prop1->mName;

        // is it something we should ignore
        if (ignorable != NULL) {
            const char **ig = ignorable;
            for (;*ig; ig++) {
                if (strcmp(*ig, attrName) == 0) {
                    break;
                }
            }
            if (*ig) {
                ALOGV("we don't mind that it has attr '%s'", attrName);
                continue;
            }
        }

        MediaAnalyticsItem::Prop *prop2 = summ->findProp(attrName);
        if (prop2 == NULL) {
            ALOGV("summ doesn't have this attr");
            return false;
        }
        if (prop1->mType != prop2->mType) {
            ALOGV("mismatched attr types");
            return false;
        }
        switch (prop1->mType) {
            case MediaAnalyticsItem::kTypeInt32:
                if (prop1->u.int32Value != prop2->u.int32Value) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeInt64:
                if (prop1->u.int64Value != prop2->u.int64Value) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeDouble:
                // XXX: watch out for floating point comparisons!
                if (prop1->u.doubleValue != prop2->u.doubleValue) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeCString:
                if (strcmp(prop1->u.CStringValue, prop2->u.CStringValue) != 0) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            case MediaAnalyticsItem::kTypeRate:
                if (prop1->u.rate.count != prop2->u.rate.count) {
                    ALOGV("mismatch values");
                    return false;
                }
                if (prop1->u.rate.duration != prop2->u.rate.duration) {
                    ALOGV("mismatch values");
                    return false;
                }
                break;
            default:
                ALOGV("mismatch values in default type");
                return false;
        }
    }

    return true;
}


int MetricsSummarizer::PropSorter(const void *a, const void *b) {
    MediaAnalyticsItem::Prop *ai = (MediaAnalyticsItem::Prop *)a;
    MediaAnalyticsItem::Prop *bi = (MediaAnalyticsItem::Prop *)b;
    return strcmp(ai->mName, bi->mName);
}

// we sort in the summaries so that it looks pretty in the dumpsys
void MetricsSummarizer::sortProps(MediaAnalyticsItem *item) {
    if (item->mPropCount != 0) {
        qsort(item->mProps, item->mPropCount,
              sizeof(MediaAnalyticsItem::Prop), MetricsSummarizer::PropSorter);
    }
}

} // namespace android
+0 −81
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#ifndef ANDROID_METRICSSUMMARIZER_H
#define ANDROID_METRICSSUMMARIZER_H

#include <string>
#include <utils/threads.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/List.h>

#include <media/IMediaAnalyticsService.h>


namespace android {

class MetricsSummarizer
{

 public:

    MetricsSummarizer(const char *key);
    virtual ~MetricsSummarizer();

    // show the key
    const char * getKey();

    // should the record be given to this summarizer
    bool isMine(MediaAnalyticsItem &item);

    // hand the record to this summarizer
    void handleRecord(MediaAnalyticsItem *item);

    virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);

    // dump the summarized records (for dumpsys)
    std::string dumpSummary(int &slot);
    std::string dumpSummary(int &slot, const char *only);

    void setIgnorables(const char **);
    const char **getIgnorables();

 protected:

    // various comparators
    // "do these records have same attributes and values in those attrs"
    bool sameAttributes(MediaAnalyticsItem *summ, MediaAnalyticsItem *single, const char **ignoreables);

    void minMaxVar64(MediaAnalyticsItem &summ, const char *key, int64_t value);

    static int PropSorter(const void *a, const void *b);
    void sortProps(MediaAnalyticsItem *item);

 private:
    const char *mKey;
    const char **mIgnorables;
    List<MediaAnalyticsItem *> *mSummaries;


};

// ----------------------------------------------------------------------------

}; // namespace android

#endif // ANDROID_METRICSSUMMARIZER_H
Loading