Refine MediaAnalytics framework
Rework some interfaces to avoid unnecessary sp<> mechanisms;
document which side of caller/callee owns pointers afterwards.
Rework internal attribute representation, add support routines.
Bug: 33547720
Test: Boot, ran subset of CTS media tests
Change-Id: Id0d65bd6a847704dc98d38be9aa5e1ce63c20e1c
diff --git a/media/libmedia/MediaAnalyticsItem.cpp b/media/libmedia/MediaAnalyticsItem.cpp
index 5f05d5a..76397c7 100644
--- a/media/libmedia/MediaAnalyticsItem.cpp
+++ b/media/libmedia/MediaAnalyticsItem.cpp
@@ -17,14 +17,15 @@
#undef LOG_TAG
#define LOG_TAG "MediaAnalyticsItem"
-#include <sys/types.h>
#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
#include <binder/Parcel.h>
#include <utils/Errors.h>
#include <utils/Log.h>
#include <utils/Mutex.h>
-#include <utils/RefBase.h>
#include <utils/SortedVector.h>
#include <utils/threads.h>
@@ -37,6 +38,12 @@
namespace android {
#define DEBUG_SERVICEACCESS 0
+#define DEBUG_API 0
+#define DEBUG_ALLOCATIONS 0
+
+// after this many failed attempts, we stop trying [from this process] and just say that
+// the service is off.
+#define SVC_TRIES 2
// the few universal keys we have
const MediaAnalyticsItem::Key MediaAnalyticsItem::kKeyAny = "any";
@@ -49,29 +56,81 @@
// access functions for the class
MediaAnalyticsItem::MediaAnalyticsItem()
- : RefBase(),
- mPid(0),
+ : mPid(0),
mUid(0),
mSessionID(MediaAnalyticsItem::SessionIDNone),
mTimestamp(0),
- mFinalized(0) {
+ mFinalized(0),
+ mPropCount(0), mPropSize(0), mProps(NULL)
+{
mKey = MediaAnalyticsItem::kKeyNone;
}
MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
- : RefBase(),
- mPid(0),
+ : mPid(0),
mUid(0),
mSessionID(MediaAnalyticsItem::SessionIDNone),
mTimestamp(0),
- mFinalized(0) {
+ mFinalized(0),
+ mPropCount(0), mPropSize(0), mProps(NULL)
+{
+ if (DEBUG_ALLOCATIONS) {
+ ALOGD("Allocate MediaAnalyticsItem @ %p", this);
+ }
mKey = key;
}
MediaAnalyticsItem::~MediaAnalyticsItem() {
+ if (DEBUG_ALLOCATIONS) {
+ ALOGD("Destroy MediaAnalyticsItem @ %p", this);
+ }
clear();
}
+void MediaAnalyticsItem::clear() {
+
+ // clean allocated storage from key
+ mKey.clear();
+
+ // clean attributes
+ // contents of the attributes
+ for (size_t i = 0 ; i < mPropSize; i++ ) {
+ clearProp(&mProps[i]);
+ }
+ // the attribute records themselves
+ if (mProps != NULL) {
+ free(mProps);
+ mProps = NULL;
+ }
+ mPropSize = 0;
+ mPropCount = 0;
+
+ return;
+}
+
+// make a deep copy of myself
+MediaAnalyticsItem *MediaAnalyticsItem::dup() {
+ MediaAnalyticsItem *dst = new MediaAnalyticsItem(this->mKey);
+
+ if (dst != NULL) {
+ // key as part of constructor
+ dst->mPid = this->mPid;
+ dst->mUid = this->mUid;
+ dst->mSessionID = this->mSessionID;
+ dst->mTimestamp = this->mTimestamp;
+ dst->mFinalized = this->mFinalized;
+
+ // properties aka attributes
+ dst->growProps(this->mPropCount);
+ for(size_t i=0;i<mPropCount;i++) {
+ copyProp(&dst->mProps[i], &this->mProps[i]);
+ }
+ dst->mPropCount = this->mPropCount;
+ }
+
+ return dst;
+}
+
// so clients can send intermediate values to be overlaid later
MediaAnalyticsItem &MediaAnalyticsItem::setFinalized(bool value) {
mFinalized = value;
@@ -92,11 +151,10 @@
}
MediaAnalyticsItem::SessionID_t MediaAnalyticsItem::generateSessionID() {
- MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
- ALOGD("generateSessionID()");
if (mSessionID == SessionIDNone) {
// get one from the server
+ MediaAnalyticsItem::SessionID_t newid = SessionIDNone;
sp<IMediaAnalyticsService> svc = getInstance();
if (svc != NULL) {
newid = svc->generateUniqueSessionID();
@@ -139,31 +197,8 @@
return mUid;
}
-void MediaAnalyticsItem::clear() {
-
- mKey.clear();
-
-#if 0
- // not sure that I need to (or should) be doing this...
- // seeing some strangeness in some records
- int count = mItems.size();
- for (int i = 0 ; i < count; i++ ) {
- MediaAnalyticsItem::Attr attr = mItems.keyAt(i);
- const sp<Item> value = mItems.valueAt(i);
- value->clear();
- attr.clear();
- }
- mItems.clear();
-#endif
-
- return;
-}
-
-// this key is for the overall record -- "vid" or "aud"
-// assuming for the moment we use int32_t like the
-// media frameworks MetaData.cpp
+// this key is for the overall record -- "codec", "player", "drm", etc
MediaAnalyticsItem &MediaAnalyticsItem::setKey(MediaAnalyticsItem::Key key) {
- // XXX: possible validation of legal keys.
mKey = key;
return *this;
}
@@ -172,179 +207,221 @@
return mKey;
}
-// number of keys we have in our dictionary
-// we won't upload empty records
+// number of attributes we have in this record
int32_t MediaAnalyticsItem::count() const {
- return mItems.size();
+ return mPropCount;
+}
+
+// find the proper entry in the list
+size_t MediaAnalyticsItem::findPropIndex(const char *name, size_t len)
+{
+ size_t i = 0;
+ for (; i < mPropCount; i++) {
+ Prop *prop = &mProps[i];
+ if (prop->mNameLen != len) {
+ continue;
+ }
+ if (memcmp(name, prop->mName, len) == 0) {
+ break;
+ }
+ }
+ return i;
+}
+
+MediaAnalyticsItem::Prop *MediaAnalyticsItem::findProp(const char *name) {
+ size_t len = strlen(name);
+ size_t i = findPropIndex(name, len);
+ if (i < mPropCount) {
+ return &mProps[i];
+ }
+ return NULL;
+}
+
+void MediaAnalyticsItem::Prop::setName(const char *name, size_t len) {
+ mNameLen = len;
+ mName = (const char *) malloc(len+1);
+ memcpy ((void *)mName, name, len+1);
+}
+
+// used only as part of a storing operation
+MediaAnalyticsItem::Prop *MediaAnalyticsItem::allocateProp(const char *name) {
+ size_t len = strlen(name);
+ size_t i = findPropIndex(name, len);
+ Prop *prop;
+
+ if (i < mPropCount) {
+ prop = &mProps[i];
+ } else {
+ if (i == mPropSize) {
+ growProps();
+ // XXX: verify success
+ }
+ i = mPropCount++;
+ prop = &mProps[i];
+ prop->setName(name, len);
+ }
+
+ return prop;
}
// set the values
-bool MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr attr, int32_t value) {
- ssize_t i = mItems.indexOfKey(attr);
- bool overwrote = true;
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
- }
- sp<Item> &item = mItems.editValueAt(i);
- item->mType = MediaAnalyticsItem::Item::kTypeInt32;
- item->u.int32Value = value;
- return overwrote;
+void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
+ Prop *prop = allocateProp(name);
+ prop->mType = kTypeInt32;
+ prop->u.int32Value = value;
}
-bool MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr attr, int64_t value) {
- ssize_t i = mItems.indexOfKey(attr);
- bool overwrote = true;
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
- }
- sp<Item> &item = mItems.editValueAt(i);
- item->mType = MediaAnalyticsItem::Item::kTypeInt64;
- item->u.int64Value = value;
- return overwrote;
+void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
+ Prop *prop = allocateProp(name);
+ prop->mType = kTypeInt64;
+ prop->u.int64Value = value;
}
-bool MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr attr, double value) {
- ssize_t i = mItems.indexOfKey(attr);
- bool overwrote = true;
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
- }
- sp<Item> &item = mItems.editValueAt(i);
- item->mType = MediaAnalyticsItem::Item::kTypeDouble;
- item->u.doubleValue = value;
- return overwrote;
+void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
+ Prop *prop = allocateProp(name);
+ prop->mType = kTypeDouble;
+ prop->u.doubleValue = value;
}
-bool MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr attr, const char *value) {
- bool overwrote = true;
- if (value == NULL) return false;
- // we store our own copy of the supplied string
- char *nvalue = strdup(value);
- if (nvalue == NULL) {
- return false;
- }
- ssize_t i = mItems.indexOfKey(attr);
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
- }
- sp<Item> &item = mItems.editValueAt(i);
- if (item->mType == MediaAnalyticsItem::Item::kTypeCString
- && item->u.CStringValue != NULL) {
- free(item->u.CStringValue);
- item->u.CStringValue = NULL;
- }
- item->mType = MediaAnalyticsItem::Item::kTypeCString;
- item->u.CStringValue = nvalue;
- return true;
+void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
+
+ Prop *prop = allocateProp(name);
+ // any old value will be gone
+ prop->mType = kTypeCString;
+ prop->u.CStringValue = strdup(value);
}
+void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
+ Prop *prop = allocateProp(name);
+ prop->mType = kTypeRate;
+ prop->u.rate.count = count;
+ prop->u.rate.duration = duration;
+}
+
+
// find/add/set fused into a single operation
-bool MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr attr, int32_t value) {
- ssize_t i = mItems.indexOfKey(attr);
- bool overwrote = true;
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
+void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
+ Prop *prop = allocateProp(name);
+ switch (prop->mType) {
+ case kTypeInt32:
+ prop->u.int32Value += value;
+ break;
+ default:
+ clearPropValue(prop);
+ prop->mType = kTypeInt32;
+ prop->u.int32Value = value;
+ break;
}
- sp<Item> &item = mItems.editValueAt(i);
- if (overwrote
- && item->mType == MediaAnalyticsItem::Item::kTypeInt32) {
- item->u.int32Value += value;
- } else {
- // start clean if there was a type mismatch
- item->u.int32Value = value;
- }
- item->mType = MediaAnalyticsItem::Item::kTypeInt32;
- return overwrote;
}
-bool MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr attr, int64_t value) {
- ssize_t i = mItems.indexOfKey(attr);
- bool overwrote = true;
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
+void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
+ Prop *prop = allocateProp(name);
+ switch (prop->mType) {
+ case kTypeInt64:
+ prop->u.int64Value += value;
+ break;
+ default:
+ clearPropValue(prop);
+ prop->mType = kTypeInt64;
+ prop->u.int64Value = value;
+ break;
}
- sp<Item> &item = mItems.editValueAt(i);
- if (overwrote
- && item->mType == MediaAnalyticsItem::Item::kTypeInt64) {
- item->u.int64Value += value;
- } else {
- // start clean if there was a type mismatch
- item->u.int64Value = value;
- }
- item->mType = MediaAnalyticsItem::Item::kTypeInt64;
- return overwrote;
}
-bool MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr attr, double value) {
- ssize_t i = mItems.indexOfKey(attr);
- bool overwrote = true;
- if (i<0) {
- sp<Item> item = new Item();
- i = mItems.add(attr, item);
- overwrote = false;
+void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
+ Prop *prop = allocateProp(name);
+ switch (prop->mType) {
+ case kTypeRate:
+ prop->u.rate.count += count;
+ prop->u.rate.duration += duration;
+ break;
+ default:
+ clearPropValue(prop);
+ prop->mType = kTypeRate;
+ prop->u.rate.count = count;
+ prop->u.rate.duration = duration;
+ break;
}
- sp<Item> &item = mItems.editValueAt(i);
- if (overwrote
- && item->mType == MediaAnalyticsItem::Item::kTypeDouble) {
- item->u.doubleValue += value;
- } else {
- // start clean if there was a type mismatch
- item->u.doubleValue = value;
+}
+
+void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
+ Prop *prop = allocateProp(name);
+ switch (prop->mType) {
+ case kTypeDouble:
+ prop->u.doubleValue += value;
+ break;
+ default:
+ clearPropValue(prop);
+ prop->mType = kTypeDouble;
+ prop->u.doubleValue = value;
+ break;
}
- item->mType = MediaAnalyticsItem::Item::kTypeDouble;
- return overwrote;
}
// find & extract values
-bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr attr, int32_t *value) {
- ssize_t i = mItems.indexOfKey(attr);
- if (i < 0) {
+bool MediaAnalyticsItem::getInt32(MediaAnalyticsItem::Attr name, int32_t *value) {
+ Prop *prop = findProp(name);
+ if (prop == NULL || prop->mType != kTypeInt32) {
return false;
}
- sp<Item> &item = mItems.editValueAt(i);
- *value = item->u.int32Value;
+ if (value != NULL) {
+ *value = prop->u.int32Value;
+ }
return true;
}
-bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr attr, int64_t *value) {
- ssize_t i = mItems.indexOfKey(attr);
- if (i < 0) {
+
+bool MediaAnalyticsItem::getInt64(MediaAnalyticsItem::Attr name, int64_t *value) {
+ Prop *prop = findProp(name);
+ if (prop == NULL || prop->mType != kTypeInt64) {
return false;
}
- sp<Item> &item = mItems.editValueAt(i);
- *value = item->u.int64Value;
+ if (value != NULL) {
+ *value = prop->u.int64Value;
+ }
return true;
}
-bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr attr, double *value) {
- ssize_t i = mItems.indexOfKey(attr);
- if (i < 0) {
+
+bool MediaAnalyticsItem::getRate(MediaAnalyticsItem::Attr name, int64_t *count, int64_t *duration, double *rate) {
+ Prop *prop = findProp(name);
+ if (prop == NULL || prop->mType != kTypeRate) {
return false;
}
- sp<Item> &item = mItems.editValueAt(i);
- *value = item->u.doubleValue;
+ if (count != NULL) {
+ *count = prop->u.rate.count;
+ }
+ if (duration != NULL) {
+ *duration = prop->u.rate.duration;
+ }
+ if (rate != NULL) {
+ double r = 0.0;
+ if (prop->u.rate.duration != 0) {
+ r = prop->u.rate.count / (double) prop->u.rate.duration;
+ }
+ *rate = r;
+ }
+ return true;
+}
+
+bool MediaAnalyticsItem::getDouble(MediaAnalyticsItem::Attr name, double *value) {
+ Prop *prop = findProp(name);
+ if (prop == NULL || prop->mType != kTypeDouble) {
+ return false;
+ }
+ if (value != NULL) {
+ *value = prop->u.doubleValue;
+ }
return true;
}
// caller responsible for the returned string
-bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr attr, char **value) {
- ssize_t i = mItems.indexOfKey(attr);
- if (i < 0) {
+bool MediaAnalyticsItem::getCString(MediaAnalyticsItem::Attr name, char **value) {
+ Prop *prop = findProp(name);
+ if (prop == NULL || prop->mType != kTypeDouble) {
return false;
}
- sp<Item> &item = mItems.editValueAt(i);
- char *p = strdup(item->u.CStringValue);
- *value = p;
+ if (value != NULL) {
+ *value = strdup(prop->u.CStringValue);
+ }
return true;
}
@@ -352,17 +429,27 @@
// return value is # keys removed
int32_t MediaAnalyticsItem::filter(int n, MediaAnalyticsItem::Attr attrs[]) {
int zapped = 0;
- if (attrs == NULL) {
- return -1;
- }
- if (n <= 0) {
+ if (attrs == NULL || n <= 0) {
return -1;
}
for (ssize_t i = 0 ; i < n ; i++) {
- ssize_t j = mItems.indexOfKey(attrs[i]);
- if (j >= 0) {
- mItems.removeItemsAt(j);
+ const char *name = attrs[i];
+ size_t len = strlen(name);
+ size_t j = findPropIndex(name, len);
+ if (j >= mPropCount) {
+ // not there
+ continue;
+ } else if (j+1 == mPropCount) {
+ // last one, shorten
zapped++;
+ clearProp(&mProps[j]);
+ mPropCount--;
+ } else {
+ // in the middle, bring last one down and shorten
+ zapped++;
+ clearProp(&mProps[j]);
+ mProps[j] = mProps[mPropCount-1];
+ mPropCount--;
}
}
return zapped;
@@ -372,19 +459,20 @@
// return value is # keys removed
int32_t MediaAnalyticsItem::filterNot(int n, MediaAnalyticsItem::Attr attrs[]) {
int zapped = 0;
- if (attrs == NULL) {
+ if (attrs == NULL || n <= 0) {
return -1;
}
- if (n <= 0) {
- return -1;
- }
- for (ssize_t i = mItems.size()-1 ; i >=0 ; i--) {
- const MediaAnalyticsItem::Attr& lattr = mItems.keyAt(i);
- ssize_t j;
- for (j= 0; j < n ; j++) {
- if (lattr == attrs[j]) {
- mItems.removeItemsAt(i);
+ for (ssize_t i = mPropCount-1 ; i >=0 ; i--) {
+ Prop *prop = &mProps[i];
+ for (ssize_t j = 0; j < n ; j++) {
+ if (strcmp(prop->mName, attrs[j]) == 0) {
+ clearProp(prop);
zapped++;
+ if (i != (ssize_t)(mPropCount-1)) {
+ *prop = mProps[mPropCount-1];
+ }
+ initProp(&mProps[mPropCount-1]);
+ mPropCount--;
break;
}
}
@@ -394,36 +482,79 @@
// remove a single key
// return value is 0 (not found) or 1 (found and removed)
-int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr attr) {
- if (attr == 0) return -1;
- ssize_t i = mItems.indexOfKey(attr);
- if (i < 0) {
- return 0;
- }
- mItems.removeItemsAt(i);
- return 1;
+int32_t MediaAnalyticsItem::filter(MediaAnalyticsItem::Attr name) {
+ return filter(1, &name);
}
-
// handle individual items/properties stored within the class
//
-MediaAnalyticsItem::Item::Item()
- : mType(kTypeNone)
-{
-}
-MediaAnalyticsItem::Item::~Item()
-{
- clear();
-}
+void MediaAnalyticsItem::initProp(Prop *prop) {
+ if (prop != NULL) {
+ prop->mName = NULL;
+ prop->mNameLen = 0;
-void MediaAnalyticsItem::Item::clear()
-{
- if (mType == kTypeCString && u.CStringValue != NULL) {
- free(u.CStringValue);
- u.CStringValue = NULL;
+ prop->mType = kTypeNone;
}
- mType = kTypeNone;
+}
+
+void MediaAnalyticsItem::clearProp(Prop *prop)
+{
+ if (prop != NULL) {
+ if (prop->mName != NULL) {
+ free((void *)prop->mName);
+ prop->mName = NULL;
+ prop->mNameLen = 0;
+ }
+
+ clearPropValue(prop);
+ }
+}
+
+void MediaAnalyticsItem::clearPropValue(Prop *prop)
+{
+ if (prop != NULL) {
+ if (prop->mType == kTypeCString && prop->u.CStringValue != NULL) {
+ free(prop->u.CStringValue);
+ prop->u.CStringValue = NULL;
+ }
+ prop->mType = kTypeNone;
+ }
+}
+
+void MediaAnalyticsItem::copyProp(Prop *dst, const Prop *src)
+{
+ // get rid of any pointers in the dst
+ clearProp(dst);
+
+ *dst = *src;
+
+ // fix any pointers that we blindly copied, so we have our own copies
+ if (dst->mName) {
+ void *p = malloc(dst->mNameLen + 1);
+ memcpy (p, src->mName, dst->mNameLen + 1);
+ dst->mName = (const char *) p;
+ }
+ if (dst->mType == kTypeCString) {
+ dst->u.CStringValue = strdup(src->u.CStringValue);
+ }
+}
+
+void MediaAnalyticsItem::growProps(int increment)
+{
+ if (increment <= 0) {
+ increment = kGrowProps;
+ }
+ int nsize = mPropSize + increment;
+ Prop *ni = (Prop *)realloc(mProps, sizeof(Prop) * nsize);
+
+ if (ni != NULL) {
+ for (int i = mPropSize; i < nsize; i++) {
+ initProp(&ni[i]);
+ }
+ mProps = ni;
+ mPropSize = nsize;
+ }
}
// Parcel / serialize things for binder calls
@@ -442,18 +573,25 @@
MediaAnalyticsItem::Attr attr = data.readCString();
int32_t ztype = data.readInt32();
switch (ztype) {
- case MediaAnalyticsItem::Item::kTypeInt32:
+ case MediaAnalyticsItem::kTypeInt32:
setInt32(attr, data.readInt32());
break;
- case MediaAnalyticsItem::Item::kTypeInt64:
+ case MediaAnalyticsItem::kTypeInt64:
setInt64(attr, data.readInt64());
break;
- case MediaAnalyticsItem::Item::kTypeDouble:
+ case MediaAnalyticsItem::kTypeDouble:
setDouble(attr, data.readDouble());
break;
- case MediaAnalyticsItem::Item::kTypeCString:
+ case MediaAnalyticsItem::kTypeCString:
setCString(attr, data.readCString());
break;
+ case MediaAnalyticsItem::kTypeRate:
+ {
+ int64_t count = data.readInt64();
+ int64_t duration = data.readInt64();
+ setRate(attr, count, duration);
+ }
+ break;
default:
ALOGE("reading bad item type: %d, idx %d",
ztype, i);
@@ -474,32 +612,33 @@
data->writeInt64(mTimestamp);
// set of items
- int count = mItems.size();
+ int count = mPropCount;
data->writeInt32(count);
for (int i = 0 ; i < count; i++ ) {
- MediaAnalyticsItem::Attr attr = mItems.keyAt(i);
- sp<Item> value = mItems.valueAt(i);
- {
- data->writeCString(attr.c_str());
- data->writeInt32(value->mType);
- switch (value->mType) {
- case MediaAnalyticsItem::Item::kTypeInt32:
- data->writeInt32(value->u.int32Value);
- break;
- case MediaAnalyticsItem::Item::kTypeInt64:
- data->writeInt64(value->u.int64Value);
- break;
- case MediaAnalyticsItem::Item::kTypeDouble:
- data->writeDouble(value->u.doubleValue);
- break;
- case MediaAnalyticsItem::Item::kTypeCString:
- data->writeCString(value->u.CStringValue);
- break;
- default:
- ALOGE("found bad item type: %d, idx %d",
- value->mType, i);
- break;
- }
+ Prop *prop = &mProps[i];
+ data->writeCString(prop->mName);
+ data->writeInt32(prop->mType);
+ switch (prop->mType) {
+ case MediaAnalyticsItem::kTypeInt32:
+ data->writeInt32(prop->u.int32Value);
+ break;
+ case MediaAnalyticsItem::kTypeInt64:
+ data->writeInt64(prop->u.int64Value);
+ break;
+ case MediaAnalyticsItem::kTypeDouble:
+ data->writeDouble(prop->u.doubleValue);
+ break;
+ case MediaAnalyticsItem::kTypeRate:
+ data->writeInt64(prop->u.rate.count);
+ data->writeInt64(prop->u.rate.duration);
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ data->writeCString(prop->u.CStringValue);
+ break;
+ default:
+ ALOGE("found bad Prop type: %d, idx %d, name %s",
+ prop->mType, i, prop->mName);
+ break;
}
}
@@ -511,11 +650,13 @@
AString MediaAnalyticsItem::toString() {
AString result = "(";
- char buffer[256];
+ char buffer[512];
// same order as we spill into the parcel, although not required
// key+session are our primary matching criteria
+ //RBE ALOGD("mKey.c_str");
result.append(mKey.c_str());
+ //RBE ALOGD("post-mKey.c_str");
result.append(":");
snprintf(buffer, sizeof(buffer), "%" PRId64 ":", mSessionID);
result.append(buffer);
@@ -530,37 +671,40 @@
result.append(buffer);
// set of items
- int count = mItems.size();
+ int count = mPropCount;
snprintf(buffer, sizeof(buffer), "%d:", count);
result.append(buffer);
for (int i = 0 ; i < count; i++ ) {
- const MediaAnalyticsItem::Attr attr = mItems.keyAt(i);
- const sp<Item> value = mItems.valueAt(i);
- switch (value->mType) {
- case MediaAnalyticsItem::Item::kTypeInt32:
+ Prop *prop = &mProps[i];
+ switch (prop->mType) {
+ case MediaAnalyticsItem::kTypeInt32:
snprintf(buffer,sizeof(buffer),
- "%s=%d:", attr.c_str(), value->u.int32Value);
+ "%s=%d:", prop->mName, prop->u.int32Value);
break;
- case MediaAnalyticsItem::Item::kTypeInt64:
+ case MediaAnalyticsItem::kTypeInt64:
snprintf(buffer,sizeof(buffer),
- "%s=%" PRId64 ":", attr.c_str(), value->u.int64Value);
+ "%s=%" PRId64 ":", prop->mName, prop->u.int64Value);
break;
- case MediaAnalyticsItem::Item::kTypeDouble:
+ case MediaAnalyticsItem::kTypeDouble:
snprintf(buffer,sizeof(buffer),
- "%s=%e:", attr.c_str(), value->u.doubleValue);
+ "%s=%e:", prop->mName, prop->u.doubleValue);
break;
- case MediaAnalyticsItem::Item::kTypeCString:
- // XXX: worry about escape chars
- // XXX: worry about overflowing buffer
- snprintf(buffer,sizeof(buffer), "%s=", attr.c_str());
+ case MediaAnalyticsItem::kTypeRate:
+ snprintf(buffer,sizeof(buffer),
+ "%s=%" PRId64 "/%" PRId64 ":", prop->mName,
+ prop->u.rate.count, prop->u.rate.duration);
+ break;
+ case MediaAnalyticsItem::kTypeCString:
+ snprintf(buffer,sizeof(buffer), "%s=", prop->mName);
result.append(buffer);
- result.append(value->u.CStringValue);
+ // XXX: sanitize string for ':' '='
+ result.append(prop->u.CStringValue);
buffer[0] = ':';
buffer[1] = '\0';
break;
default:
- ALOGE("to_String bad item type: %d",
- value->mType);
+ ALOGE("to_String bad item type: %d for %s",
+ prop->mType, prop->mName);
break;
}
result.append(buffer);
@@ -579,8 +723,10 @@
bool MediaAnalyticsItem::selfrecord(bool forcenew) {
- AString p = this->toString();
- ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
+ if (DEBUG_API) {
+ AString p = this->toString();
+ ALOGD("selfrecord of: %s [forcenew=%d]", p.c_str(), forcenew);
+ }
sp<IMediaAnalyticsService> svc = getInstance();
@@ -588,6 +734,8 @@
svc->submit(this, forcenew);
return true;
} else {
+ AString p = this->toString();
+ ALOGD("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
return false;
}
}
@@ -616,6 +764,7 @@
//static
sp<IMediaAnalyticsService> MediaAnalyticsItem::getInstance() {
static const char *servicename = "media.analytics";
+ static int tries_remaining = SVC_TRIES;
int enabled = isEnabled();
if (enabled == false) {
@@ -629,8 +778,10 @@
Mutex::Autolock _l(sInitMutex);
const char *badness = "";
-
- if (sAnalyticsService == NULL) {
+ // think of tries_remaining as telling us whether service==NULL because
+ // (1) we haven't tried to initialize it yet
+ // (2) we've tried to initialize it, but failed.
+ if (sAnalyticsService == NULL && tries_remaining > 0) {
sp<IServiceManager> sm = defaultServiceManager();
if (sm != NULL) {
sp<IBinder> binder = sm->getService(String16(servicename));
@@ -642,13 +793,17 @@
} else {
badness = "No Service Manager access";
}
- // always
- if (1 || DEBUG_SERVICEACCESS) {
- if (sAnalyticsService == NULL) {
+
+ if (sAnalyticsService == NULL) {
+ if (tries_remaining > 0) {
+ tries_remaining--;
+ }
+ if (DEBUG_SERVICEACCESS) {
ALOGD("Unable to bind to service %s: %s", servicename, badness);
}
}
}
+
return sAnalyticsService;
}
}
@@ -656,7 +811,7 @@
// merge the info from 'incoming' into this record.
// we finish with a union of this+incoming and special handling for collisions
-bool MediaAnalyticsItem::merge(sp<MediaAnalyticsItem> incoming) {
+bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
// if I don't have key or session id, take them from incoming
// 'this' should never be missing both of them...
@@ -670,28 +825,35 @@
setFinalized(incoming->getFinalized());
// for each attribute from 'incoming', resolve appropriately
- int nattr = incoming->mItems.size();
+ int nattr = incoming->mPropCount;
for (int i = 0 ; i < nattr; i++ ) {
- const MediaAnalyticsItem::Attr attr = incoming->mItems.keyAt(i);
- const sp<Item> value = incoming->mItems.valueAt(i);
+ Prop *iprop = &incoming->mProps[i];
+ Prop *oprop = findProp(iprop->mName);
+ const char *p = iprop->mName;
+ size_t len = strlen(p);
+ char semantic = p[len-1];
- const char *p = attr.c_str();
- char semantic = p[strlen(p)-1];
+ if (oprop == NULL) {
+ // no oprop, so we insert the new one
+ oprop = allocateProp(p);
+ copyProp(oprop, iprop);
+ } else {
+ // merge iprop into oprop
+ switch (semantic) {
+ case '<': // first aka keep old)
+ /* nop */
+ break;
- switch (semantic) {
- default: // default operation is keep new
- case '>': // last aka keep new
- mItems.replaceValueFor(attr, value);
- break;
+ default: // default is 'last'
+ case '>': // last (aka keep new)
+ copyProp(oprop, iprop);
+ break;
- case '<': /* first aka keep first*/
- /* nop */
- break;
+ case '+': /* sum */
+ // XXX validate numeric types, sum in place
+ break;
- case '+': /* sum */
- // XXX validate numeric types, sum in place
- break;
-
+ }
}
}