Loading include/media/IMediaAnalyticsService.h +5 −3 Original line number Diff line number Diff line Loading @@ -49,14 +49,16 @@ public: // 'forcenew' marks any matching incomplete record as complete before // inserting this new record. // returns the sessionID associated with that item. virtual MediaAnalyticsItem::SessionID_t submit(sp<MediaAnalyticsItem> item, bool forcenew) = 0; // caller continues to own the passed item virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) = 0; // return lists of records that match the supplied parameters. // finished [or not] records since time 'ts' with key 'key' // timestamp 'ts' is nanoseconds, unix time. virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, int64_t ts) = 0; virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key) = 0; // caller responsible for deallocating returned data structures virtual List<MediaAnalyticsItem *> *getMediaAnalyticsItemList(bool finished, int64_t ts) = 0; virtual List<MediaAnalyticsItem *> *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key) = 0; }; Loading include/media/MediaAnalyticsItem.h +49 −29 Original line number Diff line number Diff line Loading @@ -36,13 +36,22 @@ class IMediaAnalyticsService; // the class interface // class MediaAnalyticsItem : public RefBase { class MediaAnalyticsItem { friend class MediaAnalyticsService; friend class IMediaAnalyticsService; public: enum Type { kTypeNone = 0, kTypeInt32 = 1, kTypeInt64 = 2, kTypeDouble = 3, kTypeCString = 4, kTypeRate = 5, }; // sessionid // unique within device, within boot, typedef int64_t SessionID_t; Loading @@ -61,7 +70,7 @@ class MediaAnalyticsItem : public RefBase { // Attr: names for attributes within a record // format "prop1" or "prop/subprop" // XXX: need to better define the format typedef AString Attr; typedef const char *Attr; public: Loading @@ -87,6 +96,7 @@ class MediaAnalyticsItem : public RefBase { // reset all contents, discarding any extra data void clear(); MediaAnalyticsItem *dup(); // set the key discriminator for the record. // most often initialized as part of the constructor Loading @@ -97,28 +107,32 @@ class MediaAnalyticsItem : public RefBase { int32_t count() const; // set values appropriately // return values tell us whether we overwrote an existing value bool setInt32(Attr, int32_t value); bool setInt64(Attr, int64_t value); bool setDouble(Attr, double value); bool setCString(Attr, const char *value); void setInt32(Attr, int32_t value); void setInt64(Attr, int64_t value); void setDouble(Attr, double value); void setRate(Attr, int64_t count, int64_t duration); void setCString(Attr, const char *value); // fused get/add/set; if attr wasn't there, it's a simple set. // type-mismatch counts as "wasn't there". // return value tells us whether we overwrote an existing value bool addInt32(Attr, int32_t value); bool addInt64(Attr, int64_t value); bool addDouble(Attr, double value); void addInt32(Attr, int32_t value); void addInt64(Attr, int64_t value); void addDouble(Attr, double value); void addRate(Attr, int64_t count, int64_t duration); // find & extract values // return indicates whether attr exists (and thus value filled in) // NULL parameter value suppresses storage of value. bool getInt32(Attr, int32_t *value); bool getInt64(Attr, int64_t *value); bool getDouble(Attr, double *value); bool getRate(Attr, int64_t *count, int64_t *duration, double *rate); // Caller owns the returned string bool getCString(Attr, char **value); // parameter indicates whether to close any existing open // record with same key before establishing a new record // caller retains ownership of 'this'. bool selfrecord(bool); bool selfrecord(); Loading Loading @@ -159,7 +173,8 @@ class MediaAnalyticsItem : public RefBase { // merge fields from arg into this // with rules for first/last/add, etc // XXX: document semantics and how they are indicated bool merge(sp<MediaAnalyticsItem> ); // caller continues to own 'incoming' bool merge(MediaAnalyticsItem *incoming); // enabled 1, disabled 0 static const char * const EnabledProperty; Loading @@ -185,31 +200,36 @@ class MediaAnalyticsItem : public RefBase { Key mKey; class Item : public RefBase { public: enum Type { kTypeNone = 0, kTypeInt32 = 1, kTypeInt64 = 2, kTypeDouble = 3, kTypeCString = 4, }; Item(); ~Item(); void clear(); struct Prop { Type mType; const char *mName; size_t mNameLen; // the strlen(), doesn't include the null union { int32_t int32Value; int64_t int64Value; double doubleValue; char *CStringValue; struct { int64_t count, duration; } rate; } u; void setName(const char *name, size_t len); }; void initProp(Prop *item); void clearProp(Prop *item); void clearPropValue(Prop *item); void copyProp(Prop *dst, const Prop *src); enum { kGrowProps = 10 }; KeyedVector<Attr, sp<Item>> mItems; void growProps(int increment = kGrowProps); size_t findPropIndex(const char *name, size_t len); Prop *findProp(const char *name); Prop *allocateProp(const char *name); size_t mPropCount; size_t mPropSize; Prop *mProps; }; Loading media/libmedia/IMediaAnalyticsService.cpp +13 −13 Original line number Diff line number Diff line Loading @@ -80,7 +80,7 @@ public: return sessionid; } virtual MediaAnalyticsItem::SessionID_t submit(sp<MediaAnalyticsItem> item, bool forcenew) virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) { // have this record submit itself // this will be a binder call with appropriate timing Loading Loading @@ -115,12 +115,12 @@ public: return sessionid; } virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, nsecs_t ts) virtual List<MediaAnalyticsItem*> *getMediaAnalyticsItemList(bool finished, nsecs_t ts) { return getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny); } virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, nsecs_t ts, MediaAnalyticsItem::Key key) virtual List<MediaAnalyticsItem*> *getMediaAnalyticsItemList(bool finished, nsecs_t ts, MediaAnalyticsItem::Key key) { Parcel data, reply; status_t err; Loading @@ -140,12 +140,12 @@ public: // read a count int32_t count = reply.readInt32(); List<sp<MediaAnalyticsItem>> *list = NULL; List<MediaAnalyticsItem*> *list = NULL; if (count > 0) { list = new List<sp<MediaAnalyticsItem>>(); list = new List<MediaAnalyticsItem*>(); for (int i=0;i<count;i++) { sp<MediaAnalyticsItem> item = new MediaAnalyticsItem; MediaAnalyticsItem *item = new MediaAnalyticsItem(); // XXX: watch for failures here item->readFromParcel(reply); list->push_back(item); Loading Loading @@ -190,14 +190,14 @@ status_t BnMediaAnalyticsService::onTransact( CHECK_INTERFACE(IMediaAnalyticsService, data, reply); bool forcenew; sp<MediaAnalyticsItem> item = new MediaAnalyticsItem; MediaAnalyticsItem *item = new MediaAnalyticsItem; data.readBool(&forcenew); item->readFromParcel(data); item->setPid(clientPid); // submit() takes ownership of / responsibility for the item // submit() takes over ownership of 'item' MediaAnalyticsItem::SessionID_t sessionid = submit(item, forcenew); reply->writeInt64(sessionid); Loading @@ -212,11 +212,11 @@ status_t BnMediaAnalyticsService::onTransact( MediaAnalyticsItem::Key key = data.readCString(); // find the (0 or more) items List<sp<MediaAnalyticsItem>> *list = getMediaAnalyticsItemList(finished, ts, key); List<MediaAnalyticsItem*> *list = getMediaAnalyticsItemList(finished, ts, key); // encapsulate/serialize them reply->writeInt32(list->size()); if (list->size() > 0) { for (List<sp<MediaAnalyticsItem>>::iterator it = list->begin(); for (List<MediaAnalyticsItem*>::iterator it = list->begin(); it != list->end(); it++) { (*it)->writeToParcel(reply); } Loading media/libmedia/MediaAnalyticsItem.cpp +446 −284 File changed.Preview size limit exceeded, changes collapsed. Show changes media/libmediaanalyticsservice/MediaAnalyticsService.cpp +150 −80 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ namespace android { static int trackqueue = 0; #define DEBUG_QUEUE 0 //using android::status_t; //using android::OK; Loading @@ -94,8 +94,8 @@ MediaAnalyticsService::MediaAnalyticsService() ALOGD("MediaAnalyticsService created"); // clear our queues mOpen = new List<sp<MediaAnalyticsItem>>(); mFinalized = new List<sp<MediaAnalyticsItem>>(); mOpen = new List<MediaAnalyticsItem *>(); mFinalized = new List<MediaAnalyticsItem *>(); mItemsSubmitted = 0; mItemsFinalized = 0; Loading @@ -120,7 +120,8 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() return (++mLastSessionID); } MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsItem> item, bool forcenew) { // caller surrenders ownership of 'item' MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) { MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid; Loading @@ -136,6 +137,7 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsI // validate the record; we discard if we don't like it if (contentValid(item) == false) { delete item; return MediaAnalyticsItem::SessionIDInvalid; } Loading @@ -155,13 +157,17 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsI bool finalizing = item->getFinalized(); // if finalizing, we'll remove it sp<MediaAnalyticsItem> oitem = findItem(mOpen, item, finalizing | forcenew); MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew); if (oitem != NULL) { if (forcenew) { // old one gets finalized, then we insert the new one // so we'll have 2 records at the end of this. // but don't finalize an empty record if (oitem->count() != 0) { if (oitem->count() == 0) { // we're responsible for disposing of the dead record delete oitem; oitem = NULL; } else { oitem->setFinalized(true); saveItem(mFinalized, oitem, 0); } Loading @@ -181,50 +187,53 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsI mItemsFinalized++; } id = oitem->getSessionID(); // we're responsible for disposing of the dead record delete item; item = NULL; } } else { // nothing to merge, save the new record id = item->getSessionID(); if (finalizing) { if (item->count() != 0) { if (item->count() == 0) { // drop empty records delete item; item = NULL; } else { saveItem(mFinalized, item, 0); mItemsFinalized++; } } else { saveItem(mOpen, item, 1); } id = item->getSessionID(); } return id; } List<sp<MediaAnalyticsItem>> *MediaAnalyticsService::getMediaAnalyticsItemList(bool finished, nsecs_t ts) { 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<sp<MediaAnalyticsItem>> *list; List<MediaAnalyticsItem*> *list; list = getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny); return list; } List<sp<MediaAnalyticsItem>> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) { List<MediaAnalyticsItem *> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) { // XXX: implement the get-item-list semantics List<sp<MediaAnalyticsItem>> *list = NULL; List<MediaAnalyticsItem *> *list = NULL; // set up our query on the persistent data // slurp in all of the pieces // return that return list; } // ignoring 2nd argument, name removed to keep compiler happy // XXX: arguments to parse: // -- a timestamp (either since X or last X seconds) to bound search status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&) status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 256; const size_t SIZE = 512; char buffer[SIZE]; String8 result; Loading @@ -234,10 +243,35 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&) IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); result.append(buffer); } else { // crack parameters write(fd, result.string(), result.size()); return NO_ERROR; } // crack any parameters bool clear = false; nsecs_t ts_since = 0; String16 clearOption("-clear"); String16 sinceOption("-since"); 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] == sinceOption) { i++; if (i < n) { String8 value(args[i]); char *endp; const char *p = value.string(); ts_since = strtoll(p, &endp, 10); if (endp == p || *endp != '\0') { ts_since = 0; } } else { ts_since = 0; } } } Mutex::Autolock _l(mLock); Loading @@ -258,28 +292,51 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&) " Discarded: %" PRId64 "\n", mItemsSubmitted, mItemsFinalized, mItemsDiscarded); 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); } // show the recently recorded records snprintf(buffer, sizeof(buffer), "\nFinalized Analytics (oldest first):\n"); result.append(buffer); result.append(this->dumpQueue(mFinalized)); result.append(this->dumpQueue(mFinalized, ts_since)); snprintf(buffer, sizeof(buffer), "\nIn-Progress Analytics (newest first):\n"); result.append(buffer); result.append(this->dumpQueue(mOpen)); result.append(this->dumpQueue(mOpen, ts_since)); // 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<sp<MediaAnalyticsItem>> *theList) { const size_t SIZE = 256; String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) { return dumpQueue(theList, (nsecs_t) 0); } String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since) { const size_t SIZE = 512; char buffer[SIZE]; String8 result; int slot = 0; Loading @@ -287,12 +344,20 @@ String8 MediaAnalyticsService::dumpQueue(List<sp<MediaAnalyticsItem>> *theList) if (theList->empty()) { result.append("empty\n"); } else { List<sp<MediaAnalyticsItem>>::iterator it = theList->begin(); for (; it != theList->end(); it++, slot++) { List<MediaAnalyticsItem *>::iterator it = theList->begin(); for (; it != theList->end(); it++) { nsecs_t when = (*it)->getTimestamp(); if (when < ts_since) { continue; } AString entry = (*it)->toString(); snprintf(buffer, sizeof(buffer), "%4d: %s\n", snprintf(buffer, sizeof(buffer), "%4d: %s", slot, entry.c_str()); result.append(buffer); buffer[0] = '\n'; buffer[1] = '\0'; result.append(buffer); slot++; } } Loading @@ -304,15 +369,13 @@ String8 MediaAnalyticsService::dumpQueue(List<sp<MediaAnalyticsItem>> *theList) // XXX: rewrite this to manage persistence, etc. // insert appropriately into queue void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAnalyticsItem> item, int front) { void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) { Mutex::Autolock _l(mLock); if (false) if (DEBUG_QUEUE) { ALOGD("Inject a record: session %" PRId64 " ts %" PRId64 "", item->getSessionID(), item->getTimestamp()); if (trackqueue) { String8 before = dumpQueue(l); ALOGD("Q before insert: %s", before.string()); } Loading @@ -324,7 +387,7 @@ void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAn l->push_back(item); } if (trackqueue) { if (DEBUG_QUEUE) { String8 after = dumpQueue(l); ALOGD("Q after insert: %s", after.string()); } Loading @@ -332,25 +395,28 @@ void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAn // keep removing old records the front until we're in-bounds if (mMaxRecords > 0) { while (l->size() > (size_t) mMaxRecords) { sp<MediaAnalyticsItem> oitem = *(l->begin()); if (trackqueue) { 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()); ALOGD("drop record at %s:%d", __FILE__, __LINE__); delete oitem; ALOGD("[done] drop record at %s:%d", __FILE__, __LINE__); mItemsDiscarded++; } } if (trackqueue) { 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? static bool compatibleItems(sp<MediaAnalyticsItem> oitem, sp<MediaAnalyticsItem> nitem) { static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) { if (0) { ALOGD("Compare: o %s n %s", Loading Loading @@ -386,18 +452,18 @@ static bool compatibleItems(sp<MediaAnalyticsItem> oitem, sp<MediaAnalyticsItem> } // find the incomplete record that this will overlay sp<MediaAnalyticsItem> MediaAnalyticsService::findItem(List<sp<MediaAnalyticsItem>> *theList, sp<MediaAnalyticsItem> nitem, bool removeit) { sp<MediaAnalyticsItem> item; MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) { if (nitem == NULL) { return NULL; } MediaAnalyticsItem *item = NULL; Mutex::Autolock _l(mLock); for (List<sp<MediaAnalyticsItem>>::iterator it = theList->begin(); for (List<MediaAnalyticsItem *>::iterator it = theList->begin(); it != theList->end(); it++) { sp<MediaAnalyticsItem> tmp = (*it); MediaAnalyticsItem *tmp = (*it); if (!compatibleItems(tmp, nitem)) { continue; Loading @@ -415,33 +481,37 @@ sp<MediaAnalyticsItem> MediaAnalyticsService::findItem(List<sp<MediaAnalyticsIte // delete the indicated record void MediaAnalyticsService::deleteItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAnalyticsItem> item) { void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) { Mutex::Autolock _l(mLock); if(trackqueue) { if(DEBUG_QUEUE) { String8 before = dumpQueue(l); ALOGD("Q before delete: %s", before.string()); } for (List<sp<MediaAnalyticsItem>>::iterator it = l->begin(); 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 (trackqueue) { if (DEBUG_QUEUE) { String8 after = dumpQueue(l); ALOGD("Q after delete: %s", after.string()); } } // are the contents good bool MediaAnalyticsService::contentValid(sp<MediaAnalyticsItem>) { bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *) { // certain keys require certain uids // internal consistency Loading @@ -450,7 +520,7 @@ bool MediaAnalyticsService::contentValid(sp<MediaAnalyticsItem>) { } // are we rate limited, normally false bool MediaAnalyticsService::rateLimited(sp<MediaAnalyticsItem>) { bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) { return false; } Loading Loading
include/media/IMediaAnalyticsService.h +5 −3 Original line number Diff line number Diff line Loading @@ -49,14 +49,16 @@ public: // 'forcenew' marks any matching incomplete record as complete before // inserting this new record. // returns the sessionID associated with that item. virtual MediaAnalyticsItem::SessionID_t submit(sp<MediaAnalyticsItem> item, bool forcenew) = 0; // caller continues to own the passed item virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) = 0; // return lists of records that match the supplied parameters. // finished [or not] records since time 'ts' with key 'key' // timestamp 'ts' is nanoseconds, unix time. virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, int64_t ts) = 0; virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key) = 0; // caller responsible for deallocating returned data structures virtual List<MediaAnalyticsItem *> *getMediaAnalyticsItemList(bool finished, int64_t ts) = 0; virtual List<MediaAnalyticsItem *> *getMediaAnalyticsItemList(bool finished, int64_t ts, MediaAnalyticsItem::Key key) = 0; }; Loading
include/media/MediaAnalyticsItem.h +49 −29 Original line number Diff line number Diff line Loading @@ -36,13 +36,22 @@ class IMediaAnalyticsService; // the class interface // class MediaAnalyticsItem : public RefBase { class MediaAnalyticsItem { friend class MediaAnalyticsService; friend class IMediaAnalyticsService; public: enum Type { kTypeNone = 0, kTypeInt32 = 1, kTypeInt64 = 2, kTypeDouble = 3, kTypeCString = 4, kTypeRate = 5, }; // sessionid // unique within device, within boot, typedef int64_t SessionID_t; Loading @@ -61,7 +70,7 @@ class MediaAnalyticsItem : public RefBase { // Attr: names for attributes within a record // format "prop1" or "prop/subprop" // XXX: need to better define the format typedef AString Attr; typedef const char *Attr; public: Loading @@ -87,6 +96,7 @@ class MediaAnalyticsItem : public RefBase { // reset all contents, discarding any extra data void clear(); MediaAnalyticsItem *dup(); // set the key discriminator for the record. // most often initialized as part of the constructor Loading @@ -97,28 +107,32 @@ class MediaAnalyticsItem : public RefBase { int32_t count() const; // set values appropriately // return values tell us whether we overwrote an existing value bool setInt32(Attr, int32_t value); bool setInt64(Attr, int64_t value); bool setDouble(Attr, double value); bool setCString(Attr, const char *value); void setInt32(Attr, int32_t value); void setInt64(Attr, int64_t value); void setDouble(Attr, double value); void setRate(Attr, int64_t count, int64_t duration); void setCString(Attr, const char *value); // fused get/add/set; if attr wasn't there, it's a simple set. // type-mismatch counts as "wasn't there". // return value tells us whether we overwrote an existing value bool addInt32(Attr, int32_t value); bool addInt64(Attr, int64_t value); bool addDouble(Attr, double value); void addInt32(Attr, int32_t value); void addInt64(Attr, int64_t value); void addDouble(Attr, double value); void addRate(Attr, int64_t count, int64_t duration); // find & extract values // return indicates whether attr exists (and thus value filled in) // NULL parameter value suppresses storage of value. bool getInt32(Attr, int32_t *value); bool getInt64(Attr, int64_t *value); bool getDouble(Attr, double *value); bool getRate(Attr, int64_t *count, int64_t *duration, double *rate); // Caller owns the returned string bool getCString(Attr, char **value); // parameter indicates whether to close any existing open // record with same key before establishing a new record // caller retains ownership of 'this'. bool selfrecord(bool); bool selfrecord(); Loading Loading @@ -159,7 +173,8 @@ class MediaAnalyticsItem : public RefBase { // merge fields from arg into this // with rules for first/last/add, etc // XXX: document semantics and how they are indicated bool merge(sp<MediaAnalyticsItem> ); // caller continues to own 'incoming' bool merge(MediaAnalyticsItem *incoming); // enabled 1, disabled 0 static const char * const EnabledProperty; Loading @@ -185,31 +200,36 @@ class MediaAnalyticsItem : public RefBase { Key mKey; class Item : public RefBase { public: enum Type { kTypeNone = 0, kTypeInt32 = 1, kTypeInt64 = 2, kTypeDouble = 3, kTypeCString = 4, }; Item(); ~Item(); void clear(); struct Prop { Type mType; const char *mName; size_t mNameLen; // the strlen(), doesn't include the null union { int32_t int32Value; int64_t int64Value; double doubleValue; char *CStringValue; struct { int64_t count, duration; } rate; } u; void setName(const char *name, size_t len); }; void initProp(Prop *item); void clearProp(Prop *item); void clearPropValue(Prop *item); void copyProp(Prop *dst, const Prop *src); enum { kGrowProps = 10 }; KeyedVector<Attr, sp<Item>> mItems; void growProps(int increment = kGrowProps); size_t findPropIndex(const char *name, size_t len); Prop *findProp(const char *name); Prop *allocateProp(const char *name); size_t mPropCount; size_t mPropSize; Prop *mProps; }; Loading
media/libmedia/IMediaAnalyticsService.cpp +13 −13 Original line number Diff line number Diff line Loading @@ -80,7 +80,7 @@ public: return sessionid; } virtual MediaAnalyticsItem::SessionID_t submit(sp<MediaAnalyticsItem> item, bool forcenew) virtual MediaAnalyticsItem::SessionID_t submit(MediaAnalyticsItem *item, bool forcenew) { // have this record submit itself // this will be a binder call with appropriate timing Loading Loading @@ -115,12 +115,12 @@ public: return sessionid; } virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, nsecs_t ts) virtual List<MediaAnalyticsItem*> *getMediaAnalyticsItemList(bool finished, nsecs_t ts) { return getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny); } virtual List<sp<MediaAnalyticsItem>> *getMediaAnalyticsItemList(bool finished, nsecs_t ts, MediaAnalyticsItem::Key key) virtual List<MediaAnalyticsItem*> *getMediaAnalyticsItemList(bool finished, nsecs_t ts, MediaAnalyticsItem::Key key) { Parcel data, reply; status_t err; Loading @@ -140,12 +140,12 @@ public: // read a count int32_t count = reply.readInt32(); List<sp<MediaAnalyticsItem>> *list = NULL; List<MediaAnalyticsItem*> *list = NULL; if (count > 0) { list = new List<sp<MediaAnalyticsItem>>(); list = new List<MediaAnalyticsItem*>(); for (int i=0;i<count;i++) { sp<MediaAnalyticsItem> item = new MediaAnalyticsItem; MediaAnalyticsItem *item = new MediaAnalyticsItem(); // XXX: watch for failures here item->readFromParcel(reply); list->push_back(item); Loading Loading @@ -190,14 +190,14 @@ status_t BnMediaAnalyticsService::onTransact( CHECK_INTERFACE(IMediaAnalyticsService, data, reply); bool forcenew; sp<MediaAnalyticsItem> item = new MediaAnalyticsItem; MediaAnalyticsItem *item = new MediaAnalyticsItem; data.readBool(&forcenew); item->readFromParcel(data); item->setPid(clientPid); // submit() takes ownership of / responsibility for the item // submit() takes over ownership of 'item' MediaAnalyticsItem::SessionID_t sessionid = submit(item, forcenew); reply->writeInt64(sessionid); Loading @@ -212,11 +212,11 @@ status_t BnMediaAnalyticsService::onTransact( MediaAnalyticsItem::Key key = data.readCString(); // find the (0 or more) items List<sp<MediaAnalyticsItem>> *list = getMediaAnalyticsItemList(finished, ts, key); List<MediaAnalyticsItem*> *list = getMediaAnalyticsItemList(finished, ts, key); // encapsulate/serialize them reply->writeInt32(list->size()); if (list->size() > 0) { for (List<sp<MediaAnalyticsItem>>::iterator it = list->begin(); for (List<MediaAnalyticsItem*>::iterator it = list->begin(); it != list->end(); it++) { (*it)->writeToParcel(reply); } Loading
media/libmedia/MediaAnalyticsItem.cpp +446 −284 File changed.Preview size limit exceeded, changes collapsed. Show changes
media/libmediaanalyticsservice/MediaAnalyticsService.cpp +150 −80 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ namespace android { static int trackqueue = 0; #define DEBUG_QUEUE 0 //using android::status_t; //using android::OK; Loading @@ -94,8 +94,8 @@ MediaAnalyticsService::MediaAnalyticsService() ALOGD("MediaAnalyticsService created"); // clear our queues mOpen = new List<sp<MediaAnalyticsItem>>(); mFinalized = new List<sp<MediaAnalyticsItem>>(); mOpen = new List<MediaAnalyticsItem *>(); mFinalized = new List<MediaAnalyticsItem *>(); mItemsSubmitted = 0; mItemsFinalized = 0; Loading @@ -120,7 +120,8 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::generateUniqueSessionID() return (++mLastSessionID); } MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsItem> item, bool forcenew) { // caller surrenders ownership of 'item' MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(MediaAnalyticsItem *item, bool forcenew) { MediaAnalyticsItem::SessionID_t id = MediaAnalyticsItem::SessionIDInvalid; Loading @@ -136,6 +137,7 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsI // validate the record; we discard if we don't like it if (contentValid(item) == false) { delete item; return MediaAnalyticsItem::SessionIDInvalid; } Loading @@ -155,13 +157,17 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsI bool finalizing = item->getFinalized(); // if finalizing, we'll remove it sp<MediaAnalyticsItem> oitem = findItem(mOpen, item, finalizing | forcenew); MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew); if (oitem != NULL) { if (forcenew) { // old one gets finalized, then we insert the new one // so we'll have 2 records at the end of this. // but don't finalize an empty record if (oitem->count() != 0) { if (oitem->count() == 0) { // we're responsible for disposing of the dead record delete oitem; oitem = NULL; } else { oitem->setFinalized(true); saveItem(mFinalized, oitem, 0); } Loading @@ -181,50 +187,53 @@ MediaAnalyticsItem::SessionID_t MediaAnalyticsService::submit(sp<MediaAnalyticsI mItemsFinalized++; } id = oitem->getSessionID(); // we're responsible for disposing of the dead record delete item; item = NULL; } } else { // nothing to merge, save the new record id = item->getSessionID(); if (finalizing) { if (item->count() != 0) { if (item->count() == 0) { // drop empty records delete item; item = NULL; } else { saveItem(mFinalized, item, 0); mItemsFinalized++; } } else { saveItem(mOpen, item, 1); } id = item->getSessionID(); } return id; } List<sp<MediaAnalyticsItem>> *MediaAnalyticsService::getMediaAnalyticsItemList(bool finished, nsecs_t ts) { 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<sp<MediaAnalyticsItem>> *list; List<MediaAnalyticsItem*> *list; list = getMediaAnalyticsItemList(finished, ts, MediaAnalyticsItem::kKeyAny); return list; } List<sp<MediaAnalyticsItem>> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) { List<MediaAnalyticsItem *> *MediaAnalyticsService::getMediaAnalyticsItemList(bool , nsecs_t , MediaAnalyticsItem::Key ) { // XXX: implement the get-item-list semantics List<sp<MediaAnalyticsItem>> *list = NULL; List<MediaAnalyticsItem *> *list = NULL; // set up our query on the persistent data // slurp in all of the pieces // return that return list; } // ignoring 2nd argument, name removed to keep compiler happy // XXX: arguments to parse: // -- a timestamp (either since X or last X seconds) to bound search status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&) status_t MediaAnalyticsService::dump(int fd, const Vector<String16>& args) { const size_t SIZE = 256; const size_t SIZE = 512; char buffer[SIZE]; String8 result; Loading @@ -234,10 +243,35 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&) IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); result.append(buffer); } else { // crack parameters write(fd, result.string(), result.size()); return NO_ERROR; } // crack any parameters bool clear = false; nsecs_t ts_since = 0; String16 clearOption("-clear"); String16 sinceOption("-since"); 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] == sinceOption) { i++; if (i < n) { String8 value(args[i]); char *endp; const char *p = value.string(); ts_since = strtoll(p, &endp, 10); if (endp == p || *endp != '\0') { ts_since = 0; } } else { ts_since = 0; } } } Mutex::Autolock _l(mLock); Loading @@ -258,28 +292,51 @@ status_t MediaAnalyticsService::dump(int fd, const Vector<String16>&) " Discarded: %" PRId64 "\n", mItemsSubmitted, mItemsFinalized, mItemsDiscarded); 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); } // show the recently recorded records snprintf(buffer, sizeof(buffer), "\nFinalized Analytics (oldest first):\n"); result.append(buffer); result.append(this->dumpQueue(mFinalized)); result.append(this->dumpQueue(mFinalized, ts_since)); snprintf(buffer, sizeof(buffer), "\nIn-Progress Analytics (newest first):\n"); result.append(buffer); result.append(this->dumpQueue(mOpen)); result.append(this->dumpQueue(mOpen, ts_since)); // 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<sp<MediaAnalyticsItem>> *theList) { const size_t SIZE = 256; String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList) { return dumpQueue(theList, (nsecs_t) 0); } String8 MediaAnalyticsService::dumpQueue(List<MediaAnalyticsItem *> *theList, nsecs_t ts_since) { const size_t SIZE = 512; char buffer[SIZE]; String8 result; int slot = 0; Loading @@ -287,12 +344,20 @@ String8 MediaAnalyticsService::dumpQueue(List<sp<MediaAnalyticsItem>> *theList) if (theList->empty()) { result.append("empty\n"); } else { List<sp<MediaAnalyticsItem>>::iterator it = theList->begin(); for (; it != theList->end(); it++, slot++) { List<MediaAnalyticsItem *>::iterator it = theList->begin(); for (; it != theList->end(); it++) { nsecs_t when = (*it)->getTimestamp(); if (when < ts_since) { continue; } AString entry = (*it)->toString(); snprintf(buffer, sizeof(buffer), "%4d: %s\n", snprintf(buffer, sizeof(buffer), "%4d: %s", slot, entry.c_str()); result.append(buffer); buffer[0] = '\n'; buffer[1] = '\0'; result.append(buffer); slot++; } } Loading @@ -304,15 +369,13 @@ String8 MediaAnalyticsService::dumpQueue(List<sp<MediaAnalyticsItem>> *theList) // XXX: rewrite this to manage persistence, etc. // insert appropriately into queue void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAnalyticsItem> item, int front) { void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) { Mutex::Autolock _l(mLock); if (false) if (DEBUG_QUEUE) { ALOGD("Inject a record: session %" PRId64 " ts %" PRId64 "", item->getSessionID(), item->getTimestamp()); if (trackqueue) { String8 before = dumpQueue(l); ALOGD("Q before insert: %s", before.string()); } Loading @@ -324,7 +387,7 @@ void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAn l->push_back(item); } if (trackqueue) { if (DEBUG_QUEUE) { String8 after = dumpQueue(l); ALOGD("Q after insert: %s", after.string()); } Loading @@ -332,25 +395,28 @@ void MediaAnalyticsService::saveItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAn // keep removing old records the front until we're in-bounds if (mMaxRecords > 0) { while (l->size() > (size_t) mMaxRecords) { sp<MediaAnalyticsItem> oitem = *(l->begin()); if (trackqueue) { 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()); ALOGD("drop record at %s:%d", __FILE__, __LINE__); delete oitem; ALOGD("[done] drop record at %s:%d", __FILE__, __LINE__); mItemsDiscarded++; } } if (trackqueue) { 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? static bool compatibleItems(sp<MediaAnalyticsItem> oitem, sp<MediaAnalyticsItem> nitem) { static bool compatibleItems(MediaAnalyticsItem * oitem, MediaAnalyticsItem * nitem) { if (0) { ALOGD("Compare: o %s n %s", Loading Loading @@ -386,18 +452,18 @@ static bool compatibleItems(sp<MediaAnalyticsItem> oitem, sp<MediaAnalyticsItem> } // find the incomplete record that this will overlay sp<MediaAnalyticsItem> MediaAnalyticsService::findItem(List<sp<MediaAnalyticsItem>> *theList, sp<MediaAnalyticsItem> nitem, bool removeit) { sp<MediaAnalyticsItem> item; MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) { if (nitem == NULL) { return NULL; } MediaAnalyticsItem *item = NULL; Mutex::Autolock _l(mLock); for (List<sp<MediaAnalyticsItem>>::iterator it = theList->begin(); for (List<MediaAnalyticsItem *>::iterator it = theList->begin(); it != theList->end(); it++) { sp<MediaAnalyticsItem> tmp = (*it); MediaAnalyticsItem *tmp = (*it); if (!compatibleItems(tmp, nitem)) { continue; Loading @@ -415,33 +481,37 @@ sp<MediaAnalyticsItem> MediaAnalyticsService::findItem(List<sp<MediaAnalyticsIte // delete the indicated record void MediaAnalyticsService::deleteItem(List<sp<MediaAnalyticsItem>> *l, sp<MediaAnalyticsItem> item) { void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) { Mutex::Autolock _l(mLock); if(trackqueue) { if(DEBUG_QUEUE) { String8 before = dumpQueue(l); ALOGD("Q before delete: %s", before.string()); } for (List<sp<MediaAnalyticsItem>>::iterator it = l->begin(); 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 (trackqueue) { if (DEBUG_QUEUE) { String8 after = dumpQueue(l); ALOGD("Q after delete: %s", after.string()); } } // are the contents good bool MediaAnalyticsService::contentValid(sp<MediaAnalyticsItem>) { bool MediaAnalyticsService::contentValid(MediaAnalyticsItem *) { // certain keys require certain uids // internal consistency Loading @@ -450,7 +520,7 @@ bool MediaAnalyticsService::contentValid(sp<MediaAnalyticsItem>) { } // are we rate limited, normally false bool MediaAnalyticsService::rateLimited(sp<MediaAnalyticsItem>) { bool MediaAnalyticsService::rateLimited(MediaAnalyticsItem *) { return false; } Loading