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

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

Merge "DO NOT MERGE Bring Metrics summarizers over from master" into oc-dev

parents a387a6cc 845eb1e4
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ class MediaAnalyticsItem {
    friend class MediaAnalyticsService;
    friend class IMediaAnalyticsService;
    friend class MediaMetricsJNI;
    friend class MetricsSummarizer;

    public:

@@ -231,7 +232,6 @@ class MediaAnalyticsItem {
        size_t mPropCount;
        size_t mPropSize;
        Prop *mProps;

};

} // namespace android
+6 −1
Original line number Diff line number Diff line
@@ -6,6 +6,11 @@ include $(CLEAR_VARS)

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

LOCAL_SHARED_LIBRARIES := \
+227 −89
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 * 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.
@@ -20,6 +20,7 @@
#define LOG_TAG "MediaAnalyticsService"
#include <utils/Log.h>

#include <stdint.h>
#include <inttypes.h>
#include <sys/types.h>
#include <sys/stat.h>
@@ -70,11 +71,28 @@

#include "MediaAnalyticsService.h"

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


namespace android {


#define DEBUG_QUEUE     0

// summarized records
// up to 48 sets, each covering an hour -- at least 2 days of coverage
// (will be longer if there are hours without any media action)
static const nsecs_t kNewSetIntervalNs = 3600*(1000*1000*1000ll);
static const int kMaxRecordSets = 48;
// individual records kept in memory
static const int kMaxRecords    = 100;


static const char *kServiceName = "media.metrics";


//using android::status_t;
//using android::OK;
@@ -85,18 +103,67 @@ namespace android {

void MediaAnalyticsService::instantiate() {
    defaultServiceManager()->addService(
            String16("media.metrics"), new MediaAnalyticsService());
            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++;
        }
    }
}

// XXX: add dynamic controls for mMaxRecords
MediaAnalyticsService::MediaAnalyticsService()
        : mMaxRecords(100) {
        : mMaxRecords(kMaxRecords),
          mMaxRecordSets(kMaxRecordSets),
          mNewSetInterval(kNewSetIntervalNs) {

    ALOGD("MediaAnalyticsService created");
    // clear our queues
    mOpen = new List<MediaAnalyticsItem *>();
    mFinalized = new List<MediaAnalyticsItem *>();

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

    mItemsSubmitted = 0;
    mItemsFinalized = 0;
    mItemsDiscarded = 0;
@@ -109,7 +176,13 @@ MediaAnalyticsService::MediaAnalyticsService()
MediaAnalyticsService::~MediaAnalyticsService() {
        ALOGD("MediaAnalyticsService destroyed");

    // XXX: clean out mOpen and mFinalized
    // clean out mOpen and mFinalized
    delete mOpen;
    mOpen = NULL;
    delete mFinalized;
    mFinalized = NULL;

    // XXX: clean out the summaries
}


@@ -197,10 +270,12 @@ 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...
            if (finalizing) {
                summarize(item);
                saveItem(mFinalized, item, 0);
                mItemsFinalized++;
            } else {
@@ -211,6 +286,7 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
            // combine the records, send it to finalized if appropriate
            oitem->merge(item);
            if (finalizing) {
                summarize(oitem);
                saveItem(mFinalized, oitem, 0);
                mItemsFinalized++;
            }
@@ -229,6 +305,7 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
                delete item;
                item = NULL;
            } else {
                summarize(item);
                saveItem(mFinalized, item, 0);
                mItemsFinalized++;
            }
@@ -239,26 +316,6 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem
    return id;
}

List<MediaAnalyticsItem *> *MediaAnalyticsService::getMediaAnalyticsItemList(bool finished, nsecs_t ts) {
    // this might never get called; the binder interface maps to the full parm list
    // on the client side before making the binder call.
    // but this lets us be sure...
    List<MediaAnalyticsItem*> *list;
    list = getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny);
    return list;
}

List<MediaAnalyticsItem *> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) {

    // XXX: implement the get-item-list semantics

    List<MediaAnalyticsItem *> *list = NULL;
    // set up our query on the persistent data
    // slurp in all of the pieces
    // return that
    return list;
}

status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
{
    const size_t SIZE = 512;
@@ -277,15 +334,21 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)

    // crack any parameters
    bool clear = false;
    bool summary = false;
    nsecs_t ts_since = 0;
    String16 summaryOption("-summary");
    String16 clearOption("-clear");
    String16 sinceOption("-since");
    String16 helpOption("-help");
    String16 onlyOption("-only");
    const char *only = NULL;
    int n = args.size();
    for (int i = 0; i < n; i++) {
        String8 myarg(args[i]);
        if (args[i] == clearOption) {
            clear = true;
        } else if (args[i] == summaryOption) {
            summary = true;
        } else if (args[i] == sinceOption) {
            i++;
            if (i < n) {
@@ -301,12 +364,27 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
            }
            // command line is milliseconds; internal units are nano-seconds
            ts_since *= 1000*1000;
        } else if (args[i] == onlyOption) {
            i++;
            if (i < n) {
                String8 value(args[i]);
                const char *p = value.string();
                char *q = strdup(p);
                if (q != NULL) {
                    if (only != NULL) {
                        free((void*)only);
                    }
                only = q;
                }
            }
        } else if (args[i] == helpOption) {
            result.append("Recognized parameters:\n");
            result.append("-help        this help message\n");
            result.append("-summary     show summary info\n");
            result.append("-clear       clears out saved records\n");
            result.append("-since XXX   include records since XXX\n");
            result.append("             (XXX is milliseconds since the UNIX epoch)\n");
            result.append("-only X      process records for component X\n");
            result.append("-since X     include records since X\n");
            result.append("             (X is milliseconds since the UNIX epoch)\n");
            write(fd, result.string(), result.size());
            return NO_ERROR;
        }
@@ -314,9 +392,42 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)

    Mutex::Autolock _l(mLock);

    snprintf(buffer, SIZE, "Dump of the mediametrics process:\n");
    // we ALWAYS dump this piece
    snprintf(buffer, SIZE, "Dump of the %s process:\n", kServiceName);
    result.append(buffer);

    dumpHeaders(result, ts_since);

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


    if (clear) {
        // remove everything from the finalized queue
        while (mFinalized->size() > 0) {
            MediaAnalyticsItem * oitem = *(mFinalized->begin());
            mFinalized->erase(mFinalized->begin());
            delete oitem;
            mItemsDiscarded++;
        }

        // shall we clear the summary data too?

    }

    write(fd, result.string(), result.size());
    return NO_ERROR;
}

// dump headers
void MediaAnalyticsService::dumpHeaders(String8 &result, nsecs_t ts_since) {
    const size_t SIZE = 512;
    char buffer[SIZE];

    int enabled = MediaAnalyticsItem::isEnabled();
    if (enabled) {
        snprintf(buffer, SIZE, "Metrics gathering: enabled\n");
@@ -331,50 +442,71 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args)
        " Discarded: %" PRId64 "\n",
        mItemsSubmitted, mItemsFinalized, mItemsDiscarded);
    result.append(buffer);
    snprintf(buffer, SIZE,
        "Summary Sets Discarded: %" PRId64 "\n", mSetsDiscarded);
    result.append(buffer);
    if (ts_since != 0) {
        snprintf(buffer, SIZE,
            "Dumping Queue entries more recent than: %" PRId64 "\n",
            (int64_t) ts_since);
        result.append(buffer);
    }
}

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

    // 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());
                }
                AString 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;
    char buffer[SIZE];

    // show the recently recorded records
    snprintf(buffer, sizeof(buffer), "\nFinalized Metrics (oldest first):\n");
    result.append(buffer);
    result.append(this->dumpQueue(mFinalized, ts_since));
    result.append(this->dumpQueue(mFinalized, ts_since, only));

    snprintf(buffer, sizeof(buffer), "\nIn-Progress Metrics (newest first):\n");
    result.append(buffer);
    result.append(this->dumpQueue(mOpen, ts_since));
    result.append(this->dumpQueue(mOpen, ts_since, only));

    // show who is connected and injecting records?
    // talk about # records fed to the 'readers'
    // talk about # records we discarded, perhaps "discarded w/o reading" too

    if (clear) {
        // remove everything from the finalized queue
        while (mFinalized->size() > 0) {
            MediaAnalyticsItem * oitem = *(mFinalized->begin());
            if (DEBUG_QUEUE) {
                ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
                    oitem->getKey().c_str(), oitem->getSessionID(),
                    oitem->getTimestamp());
            }
            mFinalized->erase(mFinalized->begin());
            mItemsDiscarded++;
        }
}

    write(fd, result.string(), result.size());
    return NO_ERROR;
}

// caller has locked mLock...
String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) {
    return dumpQueue(theList, (nsecs_t) 0);
    return dumpQueue(theList, (nsecs_t) 0, NULL);
}

String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since) {
String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since, const char * only) {
    String8 result;
    int slot = 0;

@@ -387,6 +519,11 @@ String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, ns
            if (when < ts_since) {
                continue;
            }
            if (only != NULL &&
                strcmp(only, (*it)->getKey().c_str()) != 0) {
                ALOGV("Omit '%s', it's not '%s'", (*it)->getKey().c_str(), only);
                continue;
            }
            AString entry = (*it)->toString();
            result.appendFormat("%5d: %s\n", slot, entry.c_str());
            slot++;
@@ -405,13 +542,6 @@ void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyti

    Mutex::Autolock _l(mLock);

    if (DEBUG_QUEUE) {
        ALOGD("Inject a record: session %" PRId64 " ts %" PRId64 "",
            item->getSessionID(), item->getTimestamp());
        String8 before = dumpQueue(l);
        ALOGD("Q before insert: %s", before.string());
    }

    // adding at back of queue (fifo order)
    if (front)  {
        l->push_front(item);
@@ -419,30 +549,15 @@ void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyti
        l->push_back(item);
    }

    if (DEBUG_QUEUE) {
        String8 after = dumpQueue(l);
        ALOGD("Q after insert: %s", after.string());
    }

    // keep removing old records the front until we're in-bounds
    if (mMaxRecords > 0) {
        while (l->size() > (size_t) mMaxRecords) {
            MediaAnalyticsItem * oitem = *(l->begin());
            if (DEBUG_QUEUE) {
                ALOGD("zap old record: key %s sessionID %" PRId64 " ts %" PRId64 "",
                    oitem->getKey().c_str(), oitem->getSessionID(),
                    oitem->getTimestamp());
            }
            l->erase(l->begin());
            delete oitem;
            mItemsDiscarded++;
        }
    }

    if (DEBUG_QUEUE) {
        String8 after = dumpQueue(l);
        ALOGD("Q after cleanup: %s", after.string());
    }
}

// are they alike enough that nitem can be folded into oitem?
@@ -515,29 +630,14 @@ void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnaly

    Mutex::Autolock _l(mLock);

    if(DEBUG_QUEUE) {
        String8 before = dumpQueue(l);
        ALOGD("Q before delete: %s", before.string());
    }

    for (List<MediaAnalyticsItem *>::iterator it = l->begin();
        it != l->end(); it++) {
        if ((*it)->getSessionID() != item->getSessionID())
            continue;

        if (DEBUG_QUEUE) {
            ALOGD(" --- removing record for SessionID %" PRId64 "", item->getSessionID());
            ALOGD("drop record at %s:%d", __FILE__, __LINE__);
        }
        delete *it;
        l->erase(it);
        break;
    }

    if (DEBUG_QUEUE) {
        String8 after = dumpQueue(l);
        ALOGD("Q after delete: %s", after.string());
    }
}

static AString allowedKeys[] =
@@ -579,5 +679,43 @@ 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);

}

} // namespace android
+44 −8
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 * 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.
@@ -28,6 +28,8 @@

#include <media/IMediaAnalyticsService.h>

#include "MetricsSummarizer.h"


namespace android {

@@ -39,12 +41,6 @@ class MediaAnalyticsService : public BnMediaAnalyticsService
    // on this side, caller surrenders ownership
    virtual int64_t submit(MediaAnalyticsItem *item, bool forcenew);

    virtual List<MediaAnalyticsItem *>
            *getMediaAnalyticsItemList(bool finished, int64_t ts);
    virtual List<MediaAnalyticsItem *>
            *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key);


    static  void            instantiate();
    virtual status_t        dump(int fd, const Vector<String16>& args);

@@ -58,6 +54,7 @@ class MediaAnalyticsService : public BnMediaAnalyticsService
    int64_t mItemsSubmitted;
    int64_t mItemsFinalized;
    int64_t mItemsDiscarded;
    int64_t mSetsDiscarded;
    MediaAnalyticsItem::SessionID_t mLastSessionID;

    // partitioned a bit so we don't over serialize
@@ -67,6 +64,10 @@ class MediaAnalyticsService : public BnMediaAnalyticsService
    // the most we hold in memory
    // up to this many in each queue (open, finalized)
    int32_t mMaxRecords;
    // # of sets of summaries
    int32_t mMaxRecordSets;
    // nsecs until we start a new record set
    nsecs_t mNewSetInterval;

    // input validation after arrival from client
    bool contentValid(MediaAnalyticsItem *item, bool isTrusted);
@@ -82,12 +83,47 @@ 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 *);

    // support for generating output
    String8 dumpQueue(List<MediaAnalyticsItem*> *);
    String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t);
    String8 dumpQueue(List<MediaAnalyticsItem*> *, nsecs_t, const char *only);

    void dumpHeaders(String8 &result, nsecs_t ts_since);
    void dumpSummaries(String8 &result, nsecs_t ts_since, const char * only);
    void dumpRecent(String8 &result, nsecs_t ts_since, const char * only);

};

+281 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading