Loading media/libmediametrics/MediaMetricsItem.cpp +96 −286 Original line number Diff line number Diff line Loading @@ -63,51 +63,6 @@ mediametrics::Item::~Item() { if (DEBUG_ALLOCATIONS) { ALOGD("Destroy mediametrics::Item @ %p", this); } clear(); } void mediametrics::Item::clear() { // clean allocated storage from key mKey.clear(); // clean attributes // contents of the attributes for (size_t i = 0 ; i < mPropCount; i++ ) { mProps[i].clear(); } // the attribute records themselves if (mProps != NULL) { free(mProps); mProps = NULL; } mPropSize = 0; mPropCount = 0; return; } // make a deep copy of myself mediametrics::Item *mediametrics::Item::dup() { mediametrics::Item *dst = new mediametrics::Item(this->mKey); if (dst != NULL) { // key as part of constructor dst->mPid = this->mPid; dst->mUid = this->mUid; dst->mPkgName = this->mPkgName; dst->mPkgVersionCode = this->mPkgVersionCode; dst->mTimestamp = this->mTimestamp; // properties aka attributes dst->growProps(this->mPropCount); for(size_t i=0;i<mPropCount;i++) { dst->mProps[i] = this->mProps[i]; } dst->mPropCount = this->mPropCount; } return dst; } mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) { Loading Loading @@ -151,84 +106,12 @@ int64_t mediametrics::Item::getPkgVersionCode() const { return mPkgVersionCode; } // find the proper entry in the list size_t mediametrics::Item::findPropIndex(const char *name) const { size_t i = 0; for (; i < mPropCount; i++) { if (mProps[i].isNamed(name)) break; } return i; } mediametrics::Item::Prop *mediametrics::Item::findProp(const char *name) const { const size_t i = findPropIndex(name); if (i < mPropCount) { return &mProps[i]; } return nullptr; } // consider this "find-or-allocate". // caller validates type and uses clearPropValue() accordingly mediametrics::Item::Prop *mediametrics::Item::allocateProp(const char *name) { const size_t i = findPropIndex(name); if (i < mPropCount) { return &mProps[i]; // already have it, return } Prop *prop = allocateProp(); // get a new prop if (prop == nullptr) return nullptr; prop->setName(name); return prop; } mediametrics::Item::Prop *mediametrics::Item::allocateProp() { if (mPropCount == mPropSize && growProps() == false) { ALOGE("%s: failed allocation for new properties", __func__); return nullptr; } return &mProps[mPropCount++]; } // used within the summarizers; return whether property existed bool mediametrics::Item::removeProp(const char *name) { const size_t i = findPropIndex(name); if (i < mPropCount) { mProps[i].clear(); if (i != mPropCount-1) { // in the middle, bring last one down to fill gap mProps[i].swap(mProps[mPropCount-1]); } mPropCount--; return true; } return false; } // remove indicated keys and their values // return value is # keys removed size_t mediametrics::Item::filter(size_t n, const char *attrs[]) { size_t zapped = 0; for (size_t i = 0; i < n; ++i) { const char *name = attrs[i]; size_t j = findPropIndex(name); if (j >= mPropCount) { // not there continue; } else if (j + 1 == mPropCount) { // last one, shorten zapped++; mProps[j].clear(); mPropCount--; } else { // in the middle, bring last one down and shorten zapped++; mProps[j].clear(); mProps[j] = mProps[mPropCount-1]; mPropCount--; } zapped += mProps.erase(attrs[i]); } return zapped; } Loading @@ -238,49 +121,17 @@ size_t mediametrics::Item::filter(size_t n, const char *attrs[]) { size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) { std::set<std::string> check(attrs, attrs + n); size_t zapped = 0; for (size_t j = 0; j < mPropCount;) { if (check.find(mProps[j].getName()) != check.end()) { ++j; continue; } if (j + 1 == mPropCount) { // last one, shorten zapped++; mProps[j].clear(); mPropCount--; break; for (auto it = mProps.begin(); it != mProps.end();) { if (check.find(it->first) != check.end()) { ++it; } else { // in the middle, bring last one down and shorten zapped++; mProps[j].clear(); mProps[j] = mProps[mPropCount-1]; mPropCount--; it = mProps.erase(it); ++zapped; } } return zapped; } bool mediametrics::Item::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++) { new (&ni[i]) Prop(); // placement new } mProps = ni; mPropSize = nsize; return true; } else { ALOGW("mediametrics::Item::growProps fails"); return false; } } // Parcel / serialize things for binder calls // Loading Loading @@ -316,9 +167,10 @@ status_t mediametrics::Item::readFromParcel0(const Parcel& data) { mPkgVersionCode = version; mTimestamp = timestamp; for (int i = 0; i < count; i++) { Prop *prop = allocateProp(); status_t status = prop->readFromParcel(data); Prop prop; status_t status = prop.readFromParcel(data); if (status != NO_ERROR) return status; mProps[prop.getName()] = std::move(prop); } return NO_ERROR; } Loading Loading @@ -349,9 +201,9 @@ status_t mediametrics::Item::writeToParcel0(Parcel *data) const { ?: data->writeInt64(mTimestamp); if (status != NO_ERROR) return status; data->writeInt32((int32_t)mPropCount); for (size_t i = 0 ; i < mPropCount; ++i) { status = mProps[i].writeToParcel(data); data->writeInt32((int32_t)mProps.size()); for (auto &prop : *this) { status = prop.writeToParcel(data); if (status != NO_ERROR) return status; } return NO_ERROR; Loading @@ -376,10 +228,10 @@ std::string mediametrics::Item::toString(int version) const { snprintf(buffer, sizeof(buffer), "[%d:%s:%d:%d:%lld:%s:%zu:", version, mKey.c_str(), mPid, mUid, (long long)mTimestamp, mPkgName.c_str(), mPropCount); mPkgName.c_str(), mProps.size()); result.append(buffer); for (size_t i = 0 ; i < mPropCount; ++i) { mProps[i].toString(buffer, sizeof(buffer)); for (auto &prop : *this) { prop.toString(buffer, sizeof(buffer)); result.append(buffer); } result.append("]"); Loading @@ -390,7 +242,7 @@ std::string mediametrics::Item::toString(int version) const { // calls the appropriate daemon bool mediametrics::Item::selfrecord() { ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str()); sp<IMediaMetricsService> svc = getInstance(); sp<IMediaMetricsService> svc = getService(); if (svc != NULL) { status_t status = svc->submit(this); if (status != NO_ERROR) { Loading Loading @@ -460,7 +312,7 @@ bool BaseItem::submitBuffer(const char *buffer, size_t size) { */ ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size); sp<IMediaMetricsService> svc = getInstance(); sp<IMediaMetricsService> svc = getService(); if (svc != nullptr) { const status_t status = svc->submitBuffer(buffer, size); if (status != NO_ERROR) { Loading @@ -473,7 +325,7 @@ bool BaseItem::submitBuffer(const char *buffer, size_t size) { } //static sp<IMediaMetricsService> BaseItem::getInstance() { sp<IMediaMetricsService> BaseItem::getService() { static const char *servicename = "media.metrics"; static const bool enabled = isEnabled(); // singleton initialized Loading Loading @@ -512,47 +364,6 @@ sp<IMediaMetricsService> BaseItem::getInstance() { } // merge the info from 'incoming' into this record. // we finish with a union of this+incoming and special handling for collisions bool mediametrics::Item::merge(mediametrics::Item *incoming) { // if I don't have key or session id, take them from incoming // 'this' should never be missing both of them... if (mKey.empty()) { mKey = incoming->mKey; } // for each attribute from 'incoming', resolve appropriately int nattr = incoming->mPropCount; for (int i = 0 ; i < nattr; i++ ) { Prop *iprop = &incoming->mProps[i]; const char *p = iprop->mName; size_t len = strlen(p); // should ignore a zero length name... if (len == 0) { continue; } Prop *oprop = findProp(iprop->mName); if (oprop == NULL) { // no oprop, so we insert the new one oprop = allocateProp(p); if (oprop != NULL) { *oprop = *iprop; } else { ALOGW("dropped property '%s'", iprop->mName); } } else { *oprop = *iprop; } } // not sure when we'd return false... return true; } namespace { template <typename T> Loading Loading @@ -647,14 +458,14 @@ status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) uint32_t size = header_size + sizeof(uint32_t) // # properties ; for (size_t i = 0 ; i < mPropCount; ++i) { const size_t propSize = mProps[i].getByteStringSize(); for (auto &prop : *this) { const size_t propSize = prop.getByteStringSize(); if (propSize > UINT16_MAX) { ALOGW("%s: prop %zu size %zu too large", __func__, i, propSize); ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize); return INVALID_OPERATION; } if (__builtin_add_overflow(size, propSize, &size)) { ALOGW("%s: item size overflow at property %zu", __func__, i); ALOGW("%s: item size overflow at property %s", __func__, prop.getName()); return INVALID_OPERATION; } } Loading @@ -674,16 +485,16 @@ status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) { || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) { ALOGE("%s:could not write header", __func__); // shouldn't happen free(build); return INVALID_OPERATION; } for (size_t i = 0 ; i < mPropCount; ++i) { if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) { for (auto &prop : *this) { if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) { free(build); // shouldn't happen ALOGE("%s:could not write prop %zu of %zu", __func__, i, mPropCount); ALOGE("%s:could not write prop %s", __func__, prop.getName()); return INVALID_OPERATION; } } Loading Loading @@ -750,11 +561,12 @@ status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t le mUid = uid; mTimestamp = timestamp; for (size_t i = 0; i < propCount; ++i) { Prop *prop = allocateProp(); if (prop->readFromByteString(&read, readend) != NO_ERROR) { Prop prop; if (prop.readFromByteString(&read, readend) != NO_ERROR) { ALOGW("%s: cannot read prop %zu", __func__, i); return INVALID_OPERATION; } mProps[prop.getName()] = std::move(prop); } return NO_ERROR; } Loading @@ -762,29 +574,29 @@ status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t le status_t mediametrics::Item::Prop::writeToParcel(Parcel *data) const { switch (mType) { case kTypeInt32: return data->writeCString(mName) case mediametrics::kTypeInt32: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeInt32(u.int32Value); case kTypeInt64: return data->writeCString(mName) case mediametrics::kTypeInt64: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeInt64(u.int64Value); case kTypeDouble: return data->writeCString(mName) case mediametrics::kTypeDouble: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeDouble(u.doubleValue); case kTypeRate: return data->writeCString(mName) case mediametrics::kTypeRate: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeInt64(u.rate.first) ?: data->writeInt64(u.rate.second); case kTypeCString: return data->writeCString(mName) case mediametrics::kTypeCString: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeCString(u.CStringValue); default: ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName); ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName.c_str()); return BAD_VALUE; } } Loading @@ -797,22 +609,22 @@ status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data) status_t status = data.readInt32(&type); if (status != NO_ERROR) return status; switch (type) { case kTypeInt32: case mediametrics::kTypeInt32: status = data.readInt32(&u.int32Value); break; case kTypeInt64: case mediametrics::kTypeInt64: status = data.readInt64(&u.int64Value); break; case kTypeDouble: case mediametrics::kTypeDouble: status = data.readDouble(&u.doubleValue); break; case kTypeCString: { case mediametrics::kTypeCString: { const char *s = data.readCString(); if (s == nullptr) return BAD_VALUE; set(s); break; } case kTypeRate: { case mediametrics::kTypeRate: { std::pair<int64_t, int64_t> rate; status = data.readInt64(&rate.first) ?: data.readInt64(&rate.second); Loading @@ -827,7 +639,7 @@ status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data) } if (status == NO_ERROR) { setName(key); mType = (Type)type; mType = (mediametrics::Type)type; } return status; } Loading @@ -835,25 +647,25 @@ status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data) void mediametrics::Item::Prop::toString(char *buffer, size_t length) const { switch (mType) { case kTypeInt32: snprintf(buffer, length, "%s=%d:", mName, u.int32Value); case mediametrics::kTypeInt32: snprintf(buffer, length, "%s=%d:", mName.c_str(), u.int32Value); break; case mediametrics::Item::kTypeInt64: snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value); case mediametrics::kTypeInt64: snprintf(buffer, length, "%s=%lld:", mName.c_str(), (long long)u.int64Value); break; case mediametrics::Item::kTypeDouble: snprintf(buffer, length, "%s=%e:", mName, u.doubleValue); case mediametrics::kTypeDouble: snprintf(buffer, length, "%s=%e:", mName.c_str(), u.doubleValue); break; case mediametrics::Item::kTypeRate: case mediametrics::kTypeRate: snprintf(buffer, length, "%s=%lld/%lld:", mName, (long long)u.rate.first, (long long)u.rate.second); mName.c_str(), (long long)u.rate.first, (long long)u.rate.second); break; case mediametrics::Item::kTypeCString: case mediametrics::kTypeCString: // TODO sanitize string for ':' '=' snprintf(buffer, length, "%s=%s:", mName, u.CStringValue); snprintf(buffer, length, "%s=%s:", mName.c_str(), u.CStringValue); break; default: ALOGE("%s: bad item type: %d for %s", __func__, mType, mName); ALOGE("%s: bad item type: %d for %s", __func__, mType, mName.c_str()); if (length > 0) buffer[0] = 0; break; } Loading @@ -864,27 +676,27 @@ size_t mediametrics::Item::Prop::getByteStringSize() const const size_t header = sizeof(uint16_t) // length + sizeof(uint8_t) // type + strlen(mName) + 1; // mName + 0 termination + mName.size() + 1; // mName + 0 termination size_t payload = 0; switch (mType) { case mediametrics::Item::kTypeInt32: case mediametrics::kTypeInt32: payload = sizeof(u.int32Value); break; case mediametrics::Item::kTypeInt64: case mediametrics::kTypeInt64: payload = sizeof(u.int64Value); break; case mediametrics::Item::kTypeDouble: case mediametrics::kTypeDouble: payload = sizeof(u.doubleValue); break; case mediametrics::Item::kTypeRate: case mediametrics::kTypeRate: payload = sizeof(u.rate.first) + sizeof(u.rate.second); break; case mediametrics::Item::kTypeCString: case mediametrics::kTypeCString: payload = strlen(u.CStringValue) + 1; break; default: ALOGE("%s: found bad prop type: %d, name %s", __func__, mType, mName); // no payload computed __func__, mType, mName.c_str()); // no payload computed break; } return header + payload; Loading @@ -898,7 +710,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value); if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeInt32, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -909,7 +721,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value); if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeInt64, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -920,7 +732,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value); if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeDouble, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -931,7 +743,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8; if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeRate, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value.first, bufferpptr, bufferptrmax) ?: insert(value.second, bufferpptr, bufferptrmax); Loading @@ -949,7 +761,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1; if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeCString, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -961,7 +773,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1; if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeCString, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax); } Loading @@ -970,21 +782,22 @@ status_t mediametrics::Item::Prop::writeToByteString( char **bufferpptr, char *bufferptrmax) const { switch (mType) { case kTypeInt32: return BaseItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax); case kTypeInt64: return BaseItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax); case kTypeDouble: return BaseItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax); case kTypeRate: return BaseItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax); case kTypeCString: return BaseItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax); case kTypeNone: return BaseItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax); case mediametrics::kTypeInt32: return BaseItem::writeToByteString(mName.c_str(), u.int32Value, bufferpptr, bufferptrmax); case mediametrics::kTypeInt64: return BaseItem::writeToByteString(mName.c_str(), u.int64Value, bufferpptr, bufferptrmax); case mediametrics::kTypeDouble: return BaseItem::writeToByteString(mName.c_str(), u.doubleValue, bufferpptr, bufferptrmax); case mediametrics::kTypeRate: return BaseItem::writeToByteString(mName.c_str(), u.rate, bufferpptr, bufferptrmax); case mediametrics::kTypeCString: return BaseItem::writeToByteString( mName.c_str(), u.CStringValue, bufferpptr, bufferptrmax); case mediametrics::kTypeNone: return BaseItem::writeToByteString(mName.c_str(), none_t{}, bufferpptr, bufferptrmax); default: ALOGE("%s: found bad prop type: %d, name %s", __func__, mType, mName); // no payload sent __func__, mType, mName.c_str()); // no payload sent return BAD_VALUE; } } Loading @@ -999,35 +812,32 @@ status_t mediametrics::Item::Prop::readFromByteString( ?: extract(&type, bufferpptr, bufferptrmax) ?: extract(&name, bufferpptr, bufferptrmax); if (status != NO_ERROR) return status; if (mName != nullptr) { free(mName); } mName = name; if (mType == kTypeCString) { if (mType == mediametrics::kTypeCString) { free(u.CStringValue); u.CStringValue = nullptr; } mType = (Type)type; mType = (mediametrics::Type)type; switch (mType) { case kTypeInt32: case mediametrics::kTypeInt32: return extract(&u.int32Value, bufferpptr, bufferptrmax); case kTypeInt64: case mediametrics::kTypeInt64: return extract(&u.int64Value, bufferpptr, bufferptrmax); case kTypeDouble: case mediametrics::kTypeDouble: return extract(&u.doubleValue, bufferpptr, bufferptrmax); case kTypeRate: case mediametrics::kTypeRate: return extract(&u.rate.first, bufferpptr, bufferptrmax) ?: extract(&u.rate.second, bufferpptr, bufferptrmax); case kTypeCString: case mediametrics::kTypeCString: status = extract(&u.CStringValue, bufferpptr, bufferptrmax); if (status != NO_ERROR) mType = kTypeNone; if (status != NO_ERROR) mType = mediametrics::kTypeNone; return status; case kTypeNone: case mediametrics::kTypeNone: return NO_ERROR; default: mType = kTypeNone; mType = mediametrics::kTypeNone; ALOGE("%s: found bad prop type: %d, name %s", __func__, mType, mName); // no payload sent __func__, mType, mName.c_str()); // no payload sent return BAD_VALUE; } } Loading media/libmediametrics/include/MediaMetricsItem.h +138 −144 File changed.Preview size limit exceeded, changes collapsed. Show changes services/mediametrics/tests/build_and_run_all_unit_tests.sh +1 −1 Original line number Diff line number Diff line Loading @@ -20,5 +20,5 @@ adb root && adb wait-for-device remount echo "========================================" echo "testing mediametrics" adb push $OUT/data/nativetest/mediametrics_tests/mediametrics_tests /system/bin adb push $OUT/data/nativetest64/mediametrics_tests/mediametrics_tests /system/bin adb shell /system/bin/mediametrics_tests Loading
media/libmediametrics/MediaMetricsItem.cpp +96 −286 Original line number Diff line number Diff line Loading @@ -63,51 +63,6 @@ mediametrics::Item::~Item() { if (DEBUG_ALLOCATIONS) { ALOGD("Destroy mediametrics::Item @ %p", this); } clear(); } void mediametrics::Item::clear() { // clean allocated storage from key mKey.clear(); // clean attributes // contents of the attributes for (size_t i = 0 ; i < mPropCount; i++ ) { mProps[i].clear(); } // the attribute records themselves if (mProps != NULL) { free(mProps); mProps = NULL; } mPropSize = 0; mPropCount = 0; return; } // make a deep copy of myself mediametrics::Item *mediametrics::Item::dup() { mediametrics::Item *dst = new mediametrics::Item(this->mKey); if (dst != NULL) { // key as part of constructor dst->mPid = this->mPid; dst->mUid = this->mUid; dst->mPkgName = this->mPkgName; dst->mPkgVersionCode = this->mPkgVersionCode; dst->mTimestamp = this->mTimestamp; // properties aka attributes dst->growProps(this->mPropCount); for(size_t i=0;i<mPropCount;i++) { dst->mProps[i] = this->mProps[i]; } dst->mPropCount = this->mPropCount; } return dst; } mediametrics::Item &mediametrics::Item::setTimestamp(nsecs_t ts) { Loading Loading @@ -151,84 +106,12 @@ int64_t mediametrics::Item::getPkgVersionCode() const { return mPkgVersionCode; } // find the proper entry in the list size_t mediametrics::Item::findPropIndex(const char *name) const { size_t i = 0; for (; i < mPropCount; i++) { if (mProps[i].isNamed(name)) break; } return i; } mediametrics::Item::Prop *mediametrics::Item::findProp(const char *name) const { const size_t i = findPropIndex(name); if (i < mPropCount) { return &mProps[i]; } return nullptr; } // consider this "find-or-allocate". // caller validates type and uses clearPropValue() accordingly mediametrics::Item::Prop *mediametrics::Item::allocateProp(const char *name) { const size_t i = findPropIndex(name); if (i < mPropCount) { return &mProps[i]; // already have it, return } Prop *prop = allocateProp(); // get a new prop if (prop == nullptr) return nullptr; prop->setName(name); return prop; } mediametrics::Item::Prop *mediametrics::Item::allocateProp() { if (mPropCount == mPropSize && growProps() == false) { ALOGE("%s: failed allocation for new properties", __func__); return nullptr; } return &mProps[mPropCount++]; } // used within the summarizers; return whether property existed bool mediametrics::Item::removeProp(const char *name) { const size_t i = findPropIndex(name); if (i < mPropCount) { mProps[i].clear(); if (i != mPropCount-1) { // in the middle, bring last one down to fill gap mProps[i].swap(mProps[mPropCount-1]); } mPropCount--; return true; } return false; } // remove indicated keys and their values // return value is # keys removed size_t mediametrics::Item::filter(size_t n, const char *attrs[]) { size_t zapped = 0; for (size_t i = 0; i < n; ++i) { const char *name = attrs[i]; size_t j = findPropIndex(name); if (j >= mPropCount) { // not there continue; } else if (j + 1 == mPropCount) { // last one, shorten zapped++; mProps[j].clear(); mPropCount--; } else { // in the middle, bring last one down and shorten zapped++; mProps[j].clear(); mProps[j] = mProps[mPropCount-1]; mPropCount--; } zapped += mProps.erase(attrs[i]); } return zapped; } Loading @@ -238,49 +121,17 @@ size_t mediametrics::Item::filter(size_t n, const char *attrs[]) { size_t mediametrics::Item::filterNot(size_t n, const char *attrs[]) { std::set<std::string> check(attrs, attrs + n); size_t zapped = 0; for (size_t j = 0; j < mPropCount;) { if (check.find(mProps[j].getName()) != check.end()) { ++j; continue; } if (j + 1 == mPropCount) { // last one, shorten zapped++; mProps[j].clear(); mPropCount--; break; for (auto it = mProps.begin(); it != mProps.end();) { if (check.find(it->first) != check.end()) { ++it; } else { // in the middle, bring last one down and shorten zapped++; mProps[j].clear(); mProps[j] = mProps[mPropCount-1]; mPropCount--; it = mProps.erase(it); ++zapped; } } return zapped; } bool mediametrics::Item::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++) { new (&ni[i]) Prop(); // placement new } mProps = ni; mPropSize = nsize; return true; } else { ALOGW("mediametrics::Item::growProps fails"); return false; } } // Parcel / serialize things for binder calls // Loading Loading @@ -316,9 +167,10 @@ status_t mediametrics::Item::readFromParcel0(const Parcel& data) { mPkgVersionCode = version; mTimestamp = timestamp; for (int i = 0; i < count; i++) { Prop *prop = allocateProp(); status_t status = prop->readFromParcel(data); Prop prop; status_t status = prop.readFromParcel(data); if (status != NO_ERROR) return status; mProps[prop.getName()] = std::move(prop); } return NO_ERROR; } Loading Loading @@ -349,9 +201,9 @@ status_t mediametrics::Item::writeToParcel0(Parcel *data) const { ?: data->writeInt64(mTimestamp); if (status != NO_ERROR) return status; data->writeInt32((int32_t)mPropCount); for (size_t i = 0 ; i < mPropCount; ++i) { status = mProps[i].writeToParcel(data); data->writeInt32((int32_t)mProps.size()); for (auto &prop : *this) { status = prop.writeToParcel(data); if (status != NO_ERROR) return status; } return NO_ERROR; Loading @@ -376,10 +228,10 @@ std::string mediametrics::Item::toString(int version) const { snprintf(buffer, sizeof(buffer), "[%d:%s:%d:%d:%lld:%s:%zu:", version, mKey.c_str(), mPid, mUid, (long long)mTimestamp, mPkgName.c_str(), mPropCount); mPkgName.c_str(), mProps.size()); result.append(buffer); for (size_t i = 0 ; i < mPropCount; ++i) { mProps[i].toString(buffer, sizeof(buffer)); for (auto &prop : *this) { prop.toString(buffer, sizeof(buffer)); result.append(buffer); } result.append("]"); Loading @@ -390,7 +242,7 @@ std::string mediametrics::Item::toString(int version) const { // calls the appropriate daemon bool mediametrics::Item::selfrecord() { ALOGD_IF(DEBUG_API, "%s: delivering %s", __func__, this->toString().c_str()); sp<IMediaMetricsService> svc = getInstance(); sp<IMediaMetricsService> svc = getService(); if (svc != NULL) { status_t status = svc->submit(this); if (status != NO_ERROR) { Loading Loading @@ -460,7 +312,7 @@ bool BaseItem::submitBuffer(const char *buffer, size_t size) { */ ALOGD_IF(DEBUG_API, "%s: delivering %zu bytes", __func__, size); sp<IMediaMetricsService> svc = getInstance(); sp<IMediaMetricsService> svc = getService(); if (svc != nullptr) { const status_t status = svc->submitBuffer(buffer, size); if (status != NO_ERROR) { Loading @@ -473,7 +325,7 @@ bool BaseItem::submitBuffer(const char *buffer, size_t size) { } //static sp<IMediaMetricsService> BaseItem::getInstance() { sp<IMediaMetricsService> BaseItem::getService() { static const char *servicename = "media.metrics"; static const bool enabled = isEnabled(); // singleton initialized Loading Loading @@ -512,47 +364,6 @@ sp<IMediaMetricsService> BaseItem::getInstance() { } // merge the info from 'incoming' into this record. // we finish with a union of this+incoming and special handling for collisions bool mediametrics::Item::merge(mediametrics::Item *incoming) { // if I don't have key or session id, take them from incoming // 'this' should never be missing both of them... if (mKey.empty()) { mKey = incoming->mKey; } // for each attribute from 'incoming', resolve appropriately int nattr = incoming->mPropCount; for (int i = 0 ; i < nattr; i++ ) { Prop *iprop = &incoming->mProps[i]; const char *p = iprop->mName; size_t len = strlen(p); // should ignore a zero length name... if (len == 0) { continue; } Prop *oprop = findProp(iprop->mName); if (oprop == NULL) { // no oprop, so we insert the new one oprop = allocateProp(p); if (oprop != NULL) { *oprop = *iprop; } else { ALOGW("dropped property '%s'", iprop->mName); } } else { *oprop = *iprop; } } // not sure when we'd return false... return true; } namespace { template <typename T> Loading Loading @@ -647,14 +458,14 @@ status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) uint32_t size = header_size + sizeof(uint32_t) // # properties ; for (size_t i = 0 ; i < mPropCount; ++i) { const size_t propSize = mProps[i].getByteStringSize(); for (auto &prop : *this) { const size_t propSize = prop.getByteStringSize(); if (propSize > UINT16_MAX) { ALOGW("%s: prop %zu size %zu too large", __func__, i, propSize); ALOGW("%s: prop %s size %zu too large", __func__, prop.getName(), propSize); return INVALID_OPERATION; } if (__builtin_add_overflow(size, propSize, &size)) { ALOGW("%s: item size overflow at property %zu", __func__, i); ALOGW("%s: item size overflow at property %s", __func__, prop.getName()); return INVALID_OPERATION; } } Loading @@ -674,16 +485,16 @@ status_t mediametrics::Item::writeToByteString(char **pbuffer, size_t *plength) || insert((int32_t)mPid, &filling, buildmax) != NO_ERROR || insert((int32_t)mUid, &filling, buildmax) != NO_ERROR || insert((int64_t)mTimestamp, &filling, buildmax) != NO_ERROR || insert((uint32_t)mPropCount, &filling, buildmax) != NO_ERROR) { || insert((uint32_t)mProps.size(), &filling, buildmax) != NO_ERROR) { ALOGE("%s:could not write header", __func__); // shouldn't happen free(build); return INVALID_OPERATION; } for (size_t i = 0 ; i < mPropCount; ++i) { if (mProps[i].writeToByteString(&filling, buildmax) != NO_ERROR) { for (auto &prop : *this) { if (prop.writeToByteString(&filling, buildmax) != NO_ERROR) { free(build); // shouldn't happen ALOGE("%s:could not write prop %zu of %zu", __func__, i, mPropCount); ALOGE("%s:could not write prop %s", __func__, prop.getName()); return INVALID_OPERATION; } } Loading Loading @@ -750,11 +561,12 @@ status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t le mUid = uid; mTimestamp = timestamp; for (size_t i = 0; i < propCount; ++i) { Prop *prop = allocateProp(); if (prop->readFromByteString(&read, readend) != NO_ERROR) { Prop prop; if (prop.readFromByteString(&read, readend) != NO_ERROR) { ALOGW("%s: cannot read prop %zu", __func__, i); return INVALID_OPERATION; } mProps[prop.getName()] = std::move(prop); } return NO_ERROR; } Loading @@ -762,29 +574,29 @@ status_t mediametrics::Item::readFromByteString(const char *bufferptr, size_t le status_t mediametrics::Item::Prop::writeToParcel(Parcel *data) const { switch (mType) { case kTypeInt32: return data->writeCString(mName) case mediametrics::kTypeInt32: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeInt32(u.int32Value); case kTypeInt64: return data->writeCString(mName) case mediametrics::kTypeInt64: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeInt64(u.int64Value); case kTypeDouble: return data->writeCString(mName) case mediametrics::kTypeDouble: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeDouble(u.doubleValue); case kTypeRate: return data->writeCString(mName) case mediametrics::kTypeRate: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeInt64(u.rate.first) ?: data->writeInt64(u.rate.second); case kTypeCString: return data->writeCString(mName) case mediametrics::kTypeCString: return data->writeCString(mName.c_str()) ?: data->writeInt32(mType) ?: data->writeCString(u.CStringValue); default: ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName); ALOGE("%s: found bad type: %d, name %s", __func__, mType, mName.c_str()); return BAD_VALUE; } } Loading @@ -797,22 +609,22 @@ status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data) status_t status = data.readInt32(&type); if (status != NO_ERROR) return status; switch (type) { case kTypeInt32: case mediametrics::kTypeInt32: status = data.readInt32(&u.int32Value); break; case kTypeInt64: case mediametrics::kTypeInt64: status = data.readInt64(&u.int64Value); break; case kTypeDouble: case mediametrics::kTypeDouble: status = data.readDouble(&u.doubleValue); break; case kTypeCString: { case mediametrics::kTypeCString: { const char *s = data.readCString(); if (s == nullptr) return BAD_VALUE; set(s); break; } case kTypeRate: { case mediametrics::kTypeRate: { std::pair<int64_t, int64_t> rate; status = data.readInt64(&rate.first) ?: data.readInt64(&rate.second); Loading @@ -827,7 +639,7 @@ status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data) } if (status == NO_ERROR) { setName(key); mType = (Type)type; mType = (mediametrics::Type)type; } return status; } Loading @@ -835,25 +647,25 @@ status_t mediametrics::Item::Prop::readFromParcel(const Parcel& data) void mediametrics::Item::Prop::toString(char *buffer, size_t length) const { switch (mType) { case kTypeInt32: snprintf(buffer, length, "%s=%d:", mName, u.int32Value); case mediametrics::kTypeInt32: snprintf(buffer, length, "%s=%d:", mName.c_str(), u.int32Value); break; case mediametrics::Item::kTypeInt64: snprintf(buffer, length, "%s=%lld:", mName, (long long)u.int64Value); case mediametrics::kTypeInt64: snprintf(buffer, length, "%s=%lld:", mName.c_str(), (long long)u.int64Value); break; case mediametrics::Item::kTypeDouble: snprintf(buffer, length, "%s=%e:", mName, u.doubleValue); case mediametrics::kTypeDouble: snprintf(buffer, length, "%s=%e:", mName.c_str(), u.doubleValue); break; case mediametrics::Item::kTypeRate: case mediametrics::kTypeRate: snprintf(buffer, length, "%s=%lld/%lld:", mName, (long long)u.rate.first, (long long)u.rate.second); mName.c_str(), (long long)u.rate.first, (long long)u.rate.second); break; case mediametrics::Item::kTypeCString: case mediametrics::kTypeCString: // TODO sanitize string for ':' '=' snprintf(buffer, length, "%s=%s:", mName, u.CStringValue); snprintf(buffer, length, "%s=%s:", mName.c_str(), u.CStringValue); break; default: ALOGE("%s: bad item type: %d for %s", __func__, mType, mName); ALOGE("%s: bad item type: %d for %s", __func__, mType, mName.c_str()); if (length > 0) buffer[0] = 0; break; } Loading @@ -864,27 +676,27 @@ size_t mediametrics::Item::Prop::getByteStringSize() const const size_t header = sizeof(uint16_t) // length + sizeof(uint8_t) // type + strlen(mName) + 1; // mName + 0 termination + mName.size() + 1; // mName + 0 termination size_t payload = 0; switch (mType) { case mediametrics::Item::kTypeInt32: case mediametrics::kTypeInt32: payload = sizeof(u.int32Value); break; case mediametrics::Item::kTypeInt64: case mediametrics::kTypeInt64: payload = sizeof(u.int64Value); break; case mediametrics::Item::kTypeDouble: case mediametrics::kTypeDouble: payload = sizeof(u.doubleValue); break; case mediametrics::Item::kTypeRate: case mediametrics::kTypeRate: payload = sizeof(u.rate.first) + sizeof(u.rate.second); break; case mediametrics::Item::kTypeCString: case mediametrics::kTypeCString: payload = strlen(u.CStringValue) + 1; break; default: ALOGE("%s: found bad prop type: %d, name %s", __func__, mType, mName); // no payload computed __func__, mType, mName.c_str()); // no payload computed break; } return header + payload; Loading @@ -898,7 +710,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value); if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeInt32, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeInt32, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -909,7 +721,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value); if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeInt64, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeInt64, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -920,7 +732,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + sizeof(value); if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeDouble, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeDouble, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -931,7 +743,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + 8 + 8; if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeRate, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeRate, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value.first, bufferpptr, bufferptrmax) ?: insert(value.second, bufferpptr, bufferptrmax); Loading @@ -949,7 +761,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1 + strlen(value) + 1; if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeCString, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax) ?: insert(value, bufferpptr, bufferptrmax); } Loading @@ -961,7 +773,7 @@ status_t BaseItem::writeToByteString( const size_t len = 2 + 1 + strlen(name) + 1; if (len > UINT16_MAX) return BAD_VALUE; return insert((uint16_t)len, bufferpptr, bufferptrmax) ?: insert((uint8_t)kTypeCString, bufferpptr, bufferptrmax) ?: insert((uint8_t)mediametrics::kTypeCString, bufferpptr, bufferptrmax) ?: insert(name, bufferpptr, bufferptrmax); } Loading @@ -970,21 +782,22 @@ status_t mediametrics::Item::Prop::writeToByteString( char **bufferpptr, char *bufferptrmax) const { switch (mType) { case kTypeInt32: return BaseItem::writeToByteString(mName, u.int32Value, bufferpptr, bufferptrmax); case kTypeInt64: return BaseItem::writeToByteString(mName, u.int64Value, bufferpptr, bufferptrmax); case kTypeDouble: return BaseItem::writeToByteString(mName, u.doubleValue, bufferpptr, bufferptrmax); case kTypeRate: return BaseItem::writeToByteString(mName, u.rate, bufferpptr, bufferptrmax); case kTypeCString: return BaseItem::writeToByteString(mName, u.CStringValue, bufferpptr, bufferptrmax); case kTypeNone: return BaseItem::writeToByteString(mName, none_t{}, bufferpptr, bufferptrmax); case mediametrics::kTypeInt32: return BaseItem::writeToByteString(mName.c_str(), u.int32Value, bufferpptr, bufferptrmax); case mediametrics::kTypeInt64: return BaseItem::writeToByteString(mName.c_str(), u.int64Value, bufferpptr, bufferptrmax); case mediametrics::kTypeDouble: return BaseItem::writeToByteString(mName.c_str(), u.doubleValue, bufferpptr, bufferptrmax); case mediametrics::kTypeRate: return BaseItem::writeToByteString(mName.c_str(), u.rate, bufferpptr, bufferptrmax); case mediametrics::kTypeCString: return BaseItem::writeToByteString( mName.c_str(), u.CStringValue, bufferpptr, bufferptrmax); case mediametrics::kTypeNone: return BaseItem::writeToByteString(mName.c_str(), none_t{}, bufferpptr, bufferptrmax); default: ALOGE("%s: found bad prop type: %d, name %s", __func__, mType, mName); // no payload sent __func__, mType, mName.c_str()); // no payload sent return BAD_VALUE; } } Loading @@ -999,35 +812,32 @@ status_t mediametrics::Item::Prop::readFromByteString( ?: extract(&type, bufferpptr, bufferptrmax) ?: extract(&name, bufferpptr, bufferptrmax); if (status != NO_ERROR) return status; if (mName != nullptr) { free(mName); } mName = name; if (mType == kTypeCString) { if (mType == mediametrics::kTypeCString) { free(u.CStringValue); u.CStringValue = nullptr; } mType = (Type)type; mType = (mediametrics::Type)type; switch (mType) { case kTypeInt32: case mediametrics::kTypeInt32: return extract(&u.int32Value, bufferpptr, bufferptrmax); case kTypeInt64: case mediametrics::kTypeInt64: return extract(&u.int64Value, bufferpptr, bufferptrmax); case kTypeDouble: case mediametrics::kTypeDouble: return extract(&u.doubleValue, bufferpptr, bufferptrmax); case kTypeRate: case mediametrics::kTypeRate: return extract(&u.rate.first, bufferpptr, bufferptrmax) ?: extract(&u.rate.second, bufferpptr, bufferptrmax); case kTypeCString: case mediametrics::kTypeCString: status = extract(&u.CStringValue, bufferpptr, bufferptrmax); if (status != NO_ERROR) mType = kTypeNone; if (status != NO_ERROR) mType = mediametrics::kTypeNone; return status; case kTypeNone: case mediametrics::kTypeNone: return NO_ERROR; default: mType = kTypeNone; mType = mediametrics::kTypeNone; ALOGE("%s: found bad prop type: %d, name %s", __func__, mType, mName); // no payload sent __func__, mType, mName.c_str()); // no payload sent return BAD_VALUE; } } Loading
media/libmediametrics/include/MediaMetricsItem.h +138 −144 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/mediametrics/tests/build_and_run_all_unit_tests.sh +1 −1 Original line number Diff line number Diff line Loading @@ -20,5 +20,5 @@ adb root && adb wait-for-device remount echo "========================================" echo "testing mediametrics" adb push $OUT/data/nativetest/mediametrics_tests/mediametrics_tests /system/bin adb push $OUT/data/nativetest64/mediametrics_tests/mediametrics_tests /system/bin adb shell /system/bin/mediametrics_tests