Merge changes from topic "mediametrics_stable_0118"

* changes:
  MediaPlayer2 using the new mediametrics stable interface
  Further work on libmediametrics stable API
gugelfrei
Ray Essick 6 years ago committed by Android (Google) Code Review
commit b5a34d6deb

@ -1,6 +1,4 @@
// TODO: change it back to cc_library_shared when there is a way to
// expose media metrics as stable API.
cc_library {
cc_library_shared {
name: "libmediametrics",
srcs: [
@ -32,12 +30,13 @@ cc_library {
cfi: true,
},
// enumerate the stable interface
// this would mean nobody can use the C++ interface. have to rework some things.
// stubs: {
// symbol_file: "libmediametrics.map.txt",
// versions: [
// "1" ,
// ]
// },
// enumerate stable entry points, for apex use
stubs: {
symbol_file: "libmediametrics.map.txt",
versions: [
"1" ,
]
},
}

@ -142,7 +142,7 @@ status_t BnMediaAnalyticsService::onTransact(
CHECK_INTERFACE(IMediaAnalyticsService, data, reply);
bool forcenew;
MediaAnalyticsItem *item = new MediaAnalyticsItem;
MediaAnalyticsItem *item = MediaAnalyticsItem::create();
data.readBool(&forcenew);
item->readFromParcel(data);

@ -52,6 +52,17 @@ const char * const MediaAnalyticsItem::EnabledProperty = "media.metrics.enabled
const char * const MediaAnalyticsItem::EnabledPropertyPersist = "persist.media.metrics.enabled";
const int MediaAnalyticsItem::EnabledProperty_default = 1;
// So caller doesn't need to know size of allocated space
MediaAnalyticsItem *MediaAnalyticsItem::create()
{
return MediaAnalyticsItem::create(kKeyNone);
}
MediaAnalyticsItem *MediaAnalyticsItem::create(MediaAnalyticsItem::Key key)
{
MediaAnalyticsItem *item = new MediaAnalyticsItem(key);
return item;
}
// access functions for the class
MediaAnalyticsItem::MediaAnalyticsItem()
@ -642,6 +653,19 @@ bool MediaAnalyticsItem::growProps(int increment)
//
int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
int32_t version = data.readInt32();
switch(version) {
case 0:
return readFromParcel0(data);
break;
default:
ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
return -1;
}
}
int32_t MediaAnalyticsItem::readFromParcel0(const Parcel& data) {
// into 'this' object
// .. we make a copy of the string to put away.
mKey = data.readCString();
@ -691,8 +715,23 @@ int32_t MediaAnalyticsItem::readFromParcel(const Parcel& data) {
}
int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
if (data == NULL) return -1;
int32_t version = 0;
data->writeInt32(version);
switch(version) {
case 0:
return writeToParcel0(data);
break;
default:
ALOGE("Unsupported MediaAnalyticsItem Parcel version: %d", version);
return -1;
}
}
int32_t MediaAnalyticsItem::writeToParcel0(Parcel *data) {
data->writeCString(mKey.c_str());
data->writeInt32(mPid);
@ -737,7 +776,6 @@ int32_t MediaAnalyticsItem::writeToParcel(Parcel *data) {
return 0;
}
const char *MediaAnalyticsItem::toCString() {
return toCString(PROTO_LAST);
}
@ -876,8 +914,6 @@ bool MediaAnalyticsItem::selfrecord(bool forcenew) {
}
return true;
} else {
std::string p = this->toString();
ALOGW("Unable to record: %s [forcenew=%d]", p.c_str(), forcenew);
return false;
}
}
@ -1035,5 +1071,170 @@ bool MediaAnalyticsItem::merge(MediaAnalyticsItem *incoming) {
return true;
}
// a byte array; contents are
// overall length (uint32) including the length field itself
// encoding version (uint32)
// count of properties (uint32)
// N copies of:
// property name as length(int16), bytes
// the bytes WILL include the null terminator of the name
// type (uint8 -- 1 byte)
// size of value field (int16 -- 2 bytes)
// value (size based on type)
// int32, int64, double -- little endian 4/8/8 bytes respectively
// cstring -- N bytes of value [WITH terminator]
enum { kInt32 = 0, kInt64, kDouble, kRate, kCString};
bool MediaAnalyticsItem::dumpAttributes(char **pbuffer, size_t *plength) {
char *build = NULL;
if (pbuffer == NULL || plength == NULL)
return false;
// consistency for the caller, who owns whatever comes back in this pointer.
*pbuffer = NULL;
// first, let's calculate sizes
int32_t goal = 0;
int32_t version = 0;
goal += sizeof(uint32_t); // overall length, including the length field
goal += sizeof(uint32_t); // encoding version
goal += sizeof(uint32_t); // # properties
int32_t count = mPropCount;
for (int i = 0 ; i < count; i++ ) {
Prop *prop = &mProps[i];
goal += sizeof(uint16_t); // name length
goal += strlen(prop->mName) + 1; // string + null
goal += sizeof(uint8_t); // type
goal += sizeof(uint16_t); // size of value
switch (prop->mType) {
case MediaAnalyticsItem::kTypeInt32:
goal += sizeof(uint32_t);
break;
case MediaAnalyticsItem::kTypeInt64:
goal += sizeof(uint64_t);
break;
case MediaAnalyticsItem::kTypeDouble:
goal += sizeof(double);
break;
case MediaAnalyticsItem::kTypeRate:
goal += 2 * sizeof(uint64_t);
break;
case MediaAnalyticsItem::kTypeCString:
// length + actual string + null
goal += strlen(prop->u.CStringValue) + 1;
break;
default:
ALOGE("found bad Prop type: %d, idx %d, name %s",
prop->mType, i, prop->mName);
return false;
}
}
// now that we have a size... let's allocate and fill
build = (char *)malloc(goal);
if (build == NULL)
return false;
memset(build, 0, goal);
char *filling = build;
#define _INSERT(val, size) \
{ memcpy(filling, &(val), (size)); filling += (size);}
#define _INSERTSTRING(val, size) \
{ memcpy(filling, (val), (size)); filling += (size);}
_INSERT(goal, sizeof(int32_t));
_INSERT(version, sizeof(int32_t));
_INSERT(count, sizeof(int32_t));
for (int i = 0 ; i < count; i++ ) {
Prop *prop = &mProps[i];
int16_t attrNameLen = strlen(prop->mName) + 1;
_INSERT(attrNameLen, sizeof(int16_t));
_INSERTSTRING(prop->mName, attrNameLen); // termination included
int8_t elemtype;
int16_t elemsize;
switch (prop->mType) {
case MediaAnalyticsItem::kTypeInt32:
{
elemtype = kInt32;
_INSERT(elemtype, sizeof(int8_t));
elemsize = sizeof(int32_t);
_INSERT(elemsize, sizeof(int16_t));
_INSERT(prop->u.int32Value, sizeof(int32_t));
break;
}
case MediaAnalyticsItem::kTypeInt64:
{
elemtype = kInt64;
_INSERT(elemtype, sizeof(int8_t));
elemsize = sizeof(int64_t);
_INSERT(elemsize, sizeof(int16_t));
_INSERT(prop->u.int64Value, sizeof(int64_t));
break;
}
case MediaAnalyticsItem::kTypeDouble:
{
elemtype = kDouble;
_INSERT(elemtype, sizeof(int8_t));
elemsize = sizeof(double);
_INSERT(elemsize, sizeof(int16_t));
_INSERT(prop->u.doubleValue, sizeof(double));
break;
}
case MediaAnalyticsItem::kTypeRate:
{
elemtype = kRate;
_INSERT(elemtype, sizeof(int8_t));
elemsize = 2 * sizeof(uint64_t);
_INSERT(elemsize, sizeof(int16_t));
_INSERT(prop->u.rate.count, sizeof(uint64_t));
_INSERT(prop->u.rate.duration, sizeof(uint64_t));
break;
}
case MediaAnalyticsItem::kTypeCString:
{
elemtype = kCString;
_INSERT(elemtype, sizeof(int8_t));
elemsize = strlen(prop->u.CStringValue) + 1;
_INSERT(elemsize, sizeof(int16_t));
_INSERTSTRING(prop->u.CStringValue, elemsize);
break;
}
default:
// error if can't encode; warning if can't decode
ALOGE("found bad Prop type: %d, idx %d, name %s",
prop->mType, i, prop->mName);
goto badness;
}
}
if (build + goal != filling) {
ALOGE("problems populating; wrote=%d planned=%d",
(int)(filling-build), goal);
goto badness;
}
*pbuffer = build;
*plength = goal;
return true;
badness:
free(build);
return false;
}
} // namespace android

@ -34,7 +34,7 @@
// manage the overall record
mediametrics_handle_t mediametrics_create(mediametricskey_t key) {
android::MediaAnalyticsItem *item = new android::MediaAnalyticsItem(key);
android::MediaAnalyticsItem *item = android::MediaAnalyticsItem::create(key);
return (mediametrics_handle_t) item;
}
@ -187,18 +187,9 @@ bool mediametrics_isEnabled() {
return android::MediaAnalyticsItem::isEnabled();
}
#if 0
// do not expose this as is.
// need to revisit (or redefine) how the android::Parcel parameter is handled
// so that it meets the stable-API criteria for updateable components.
//
int32_t mediametrics_writeToParcel(mediametrics_handle_t handle, android::Parcel *parcel) {
bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length) {
android::MediaAnalyticsItem *item = (android::MediaAnalyticsItem *) handle;
if (item == NULL) {
return -1;
}
return item->writeToParcel(parcel);
}
#endif
if (item == NULL) return false;
return item->dumpAttributes(buffer, length);
}

@ -17,9 +17,10 @@
#ifndef ANDROID_MEDIA_MEDIAANALYTICSITEM_H
#define ANDROID_MEDIA_MEDIAANALYTICSITEM_H
#include <cutils/properties.h>
#include <string>
#include <sys/types.h>
#include <cutils/properties.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
@ -84,6 +85,10 @@ class MediaAnalyticsItem {
public:
// so clients do not need to know size details
static MediaAnalyticsItem* create(Key key);
static MediaAnalyticsItem* create();
// access functions for the class
MediaAnalyticsItem();
MediaAnalyticsItem(Key);
@ -175,6 +180,9 @@ class MediaAnalyticsItem {
int32_t writeToParcel(Parcel *);
int32_t readFromParcel(const Parcel&);
// supports the stable interface
bool dumpAttributes(char **pbuffer, size_t *plength);
std::string toString();
std::string toString(int version);
const char *toCString();
@ -183,6 +191,11 @@ class MediaAnalyticsItem {
// are we collecting analytics data
static bool isEnabled();
private:
// handle Parcel version 0
int32_t writeToParcel0(Parcel *);
int32_t readFromParcel0(const Parcel&);
protected:
// merge fields from arg into this

@ -85,13 +85,9 @@ const char *mediametrics_readable(mediametrics_handle_t handle);
void mediametrics_setUid(mediametrics_handle_t handle, uid_t uid);
bool mediametrics_isEnabled();
#if 0
// do not expose this as is.
// need to revisit (or redefine) how the android::Parcel parameter is handled
// so that it meets the stable-API criteria for updateable components.
//
int32_t mediametrics_writeToParcel(mediametrics_handle_t handle, android::Parcel *parcel);
#endif
// serialized copy of the attributes/values, mostly for upstream getMetrics() calls
// caller owns the buffer allocated as part of this call.
bool mediametrics_getAttributes(mediametrics_handle_t handle, char **buffer, size_t *length);
__END_DECLS

@ -0,0 +1,29 @@
LIBMEDIAMETRICS_1 {
global:
mediametrics_addDouble; # apex
mediametrics_addInt32; # apex
mediametrics_addInt64; # apex
mediametrics_addRate; # apex
mediametrics_count; # apex
mediametrics_create; # apex
mediametrics_delete; # apex
mediametrics_freeCString; # apex
mediametrics_getAttributes; # apex
mediametrics_getCString; # apex
mediametrics_getDouble; # apex
mediametrics_getInt32; # apex
mediametrics_getInt64; # apex
mediametrics_getKey; # apex
mediametrics_getRate; # apex
mediametrics_isEnabled; # apex
mediametrics_readable; # apex
mediametrics_selfRecord; # apex
mediametrics_setCString; # apex
mediametrics_setDouble; # apex
mediametrics_setInt32; # apex
mediametrics_setInt64; # apex
mediametrics_setRate; # apex
mediametrics_setUid; # apex
local:
*;
};

@ -214,6 +214,8 @@ public:
virtual status_t setParameter(int key, const Parcel &request) = 0;
virtual status_t getParameter(int key, Parcel *reply) = 0;
virtual status_t getMetrics(char **buffer, size_t *length) = 0;
// Invoke a generic method on the player by using opaque parcels
// for the request and reply.
//

@ -102,6 +102,7 @@ public:
status_t setAudioAttributes(const jobject attributes);
jobject getAudioAttributes();
status_t getParameter(int key, Parcel* reply);
status_t getMetrics(char **buffer, size_t *length);
// Modular DRM
status_t prepareDrm(int64_t srcId,

@ -21,7 +21,6 @@
#include <android/binder_ibinder.h>
#include <media/AudioSystem.h>
#include <media/DataSourceDesc.h>
#include <media/MediaAnalyticsItem.h>
#include <media/MemoryLeakTrackUtil.h>
#include <media/NdkWrapper.h>
#include <media/stagefright/foundation/ADebug.h>
@ -979,6 +978,22 @@ status_t MediaPlayer2::getParameter(int key, Parcel *reply) {
return status;
}
// for mediametrics
status_t MediaPlayer2::getMetrics(char **buffer, size_t *length) {
ALOGD("MediaPlayer2::getMetrics()");
Mutex::Autolock _l(mLock);
if (mPlayer == NULL) {
ALOGV("getMetrics: no active player");
return INVALID_OPERATION;
}
status_t status = mPlayer->getMetrics(buffer, length);
if (status != OK) {
ALOGD("getMetrics returns %d", status);
}
return status;
}
void MediaPlayer2::notify(int64_t srcId, int msg, int ext1, int ext2, const PlayerMessage *obj) {
ALOGV("message received srcId=%lld, msg=%d, ext1=%d, ext2=%d",
(long long)srcId, msg, ext1, ext2);

@ -51,6 +51,7 @@ cc_library_static {
"libui",
"libgui",
"libmedia",
"libmediametrics",
"libmediandk",
"libmediandk_utils",
"libpowermanager",

@ -107,6 +107,8 @@ sp<AMessage> NuPlayer2::Decoder::getStats() const {
mStats->setInt64("frames-total", mNumFramesTotal);
mStats->setInt64("frames-dropped-input", mNumInputFramesDropped);
mStats->setInt64("frames-dropped-output", mNumOutputFramesDropped);
mStats->setFloat("frame-rate-total", mFrameRateTotal);
return mStats;
}

@ -92,6 +92,7 @@ static const char *kPlayerWidth = "android.media.mediaplayer.width";
static const char *kPlayerHeight = "android.media.mediaplayer.height";
static const char *kPlayerFrames = "android.media.mediaplayer.frames";
static const char *kPlayerFramesDropped = "android.media.mediaplayer.dropped";
static const char *kPlayerFrameRate = "android.media.mediaplayer.fps";
static const char *kPlayerAMime = "android.media.mediaplayer.audio.mime";
static const char *kPlayerACodec = "android.media.mediaplayer.audio.codec";
static const char *kPlayerDuration = "android.media.mediaplayer.durationMs";
@ -125,7 +126,7 @@ NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &
mMediaClock(new MediaClock),
mPlayer(new NuPlayer2(pid, uid, mMediaClock, context)),
mPlayerFlags(0),
mAnalyticsItem(NULL),
mMetricsHandle(0),
mClientUid(uid),
mAtEOS(false),
mLooping(false),
@ -136,9 +137,9 @@ NuPlayer2Driver::NuPlayer2Driver(pid_t pid, uid_t uid, const sp<JObjectHolder> &
mMediaClock->init();
// set up an analytics record
mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
mAnalyticsItem->setUid(mClientUid);
// set up media metrics record
mMetricsHandle = mediametrics_create(kKeyPlayer);
mediametrics_setUid(mMetricsHandle, mClientUid);
mNuPlayer2Looper->start(
false, /* runOnCallingThread */
@ -159,10 +160,7 @@ NuPlayer2Driver::~NuPlayer2Driver() {
updateMetrics("destructor");
logMetrics("destructor");
if (mAnalyticsItem != NULL) {
delete mAnalyticsItem;
mAnalyticsItem = NULL;
}
mediametrics_delete(mMetricsHandle);
}
status_t NuPlayer2Driver::initCheck() {
@ -453,15 +451,15 @@ void NuPlayer2Driver::updateMetrics(const char *where) {
if (mime.startsWith("video/")) {
int32_t width, height;
mAnalyticsItem->setCString(kPlayerVMime, mime.c_str());
mediametrics_setCString(mMetricsHandle, kPlayerVMime, mime.c_str());
if (!name.empty()) {
mAnalyticsItem->setCString(kPlayerVCodec, name.c_str());
mediametrics_setCString(mMetricsHandle, kPlayerVCodec, name.c_str());
}
if (stats->findInt32("width", &width)
&& stats->findInt32("height", &height)) {
mAnalyticsItem->setInt32(kPlayerWidth, width);
mAnalyticsItem->setInt32(kPlayerHeight, height);
mediametrics_setInt32(mMetricsHandle, kPlayerWidth, width);
mediametrics_setInt32(mMetricsHandle, kPlayerHeight, height);
}
int64_t numFramesTotal = 0;
@ -469,14 +467,18 @@ void NuPlayer2Driver::updateMetrics(const char *where) {
stats->findInt64("frames-total", &numFramesTotal);
stats->findInt64("frames-dropped-output", &numFramesDropped);
mAnalyticsItem->setInt64(kPlayerFrames, numFramesTotal);
mAnalyticsItem->setInt64(kPlayerFramesDropped, numFramesDropped);
mediametrics_setInt64(mMetricsHandle, kPlayerFrames, numFramesTotal);
mediametrics_setInt64(mMetricsHandle, kPlayerFramesDropped, numFramesDropped);
float frameRate = 0;
if (stats->findFloat("frame-rate-output", &frameRate)) {
mediametrics_setInt64(mMetricsHandle, kPlayerFrameRate, frameRate);
}
} else if (mime.startsWith("audio/")) {
mAnalyticsItem->setCString(kPlayerAMime, mime.c_str());
mediametrics_setCString(mMetricsHandle, kPlayerAMime, mime.c_str());
if (!name.empty()) {
mAnalyticsItem->setCString(kPlayerACodec, name.c_str());
mediametrics_setCString(mMetricsHandle, kPlayerACodec, name.c_str());
}
}
}
@ -487,17 +489,17 @@ void NuPlayer2Driver::updateMetrics(const char *where) {
// getDuration() uses mLock for mutex -- careful where we use it.
int64_t duration_ms = -1;
getDuration(&duration_ms);
mAnalyticsItem->setInt64(kPlayerDuration, duration_ms);
mediametrics_setInt64(mMetricsHandle, kPlayerDuration, duration_ms);
mAnalyticsItem->setInt64(kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
mediametrics_setInt64(mMetricsHandle, kPlayerPlaying, (mPlayingTimeUs+500)/1000 );
if (mRebufferingEvents != 0) {
mAnalyticsItem->setInt64(kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
mAnalyticsItem->setInt32(kPlayerRebufferingCount, mRebufferingEvents);
mAnalyticsItem->setInt32(kPlayerRebufferingAtExit, mRebufferingAtExit);
mediametrics_setInt64(mMetricsHandle, kPlayerRebuffering, (mRebufferingTimeUs+500)/1000 );
mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingCount, mRebufferingEvents);
mediametrics_setInt32(mMetricsHandle, kPlayerRebufferingAtExit, mRebufferingAtExit);
}
mAnalyticsItem->setCString(kPlayerDataSourceType, mPlayer->getDataSourceType());
mediametrics_setCString(mMetricsHandle, kPlayerDataSourceType, mPlayer->getDataSourceType());
}
@ -507,7 +509,7 @@ void NuPlayer2Driver::logMetrics(const char *where) {
}
ALOGV("logMetrics(%p) from %s at state %d", this, where, mState);
if (mAnalyticsItem == NULL || mAnalyticsItem->isEnabled() == false) {
if (mMetricsHandle == 0 || mediametrics_isEnabled() == false) {
return;
}
@ -516,16 +518,12 @@ void NuPlayer2Driver::logMetrics(const char *where) {
// and that always injects 3 fields (duration, playing time, and
// datasource) into the record.
// So the canonical "empty" record has 3 elements in it.
if (mAnalyticsItem->count() > 3) {
mAnalyticsItem->selfrecord();
if (mediametrics_count(mMetricsHandle) > 3) {
mediametrics_selfRecord(mMetricsHandle);
// re-init in case we prepare() and start() again.
delete mAnalyticsItem ;
mAnalyticsItem = new MediaAnalyticsItem(kKeyPlayer);
if (mAnalyticsItem) {
mAnalyticsItem->setUid(mClientUid);
}
mediametrics_delete(mMetricsHandle);
mMetricsHandle = mediametrics_create(kKeyPlayer);
mediametrics_setUid(mMetricsHandle, mClientUid);
} else {
ALOGV("did not have anything to record");
}
@ -649,17 +647,16 @@ status_t NuPlayer2Driver::setParameter(
return INVALID_OPERATION;
}
status_t NuPlayer2Driver::getParameter(int key, Parcel *reply) {
status_t NuPlayer2Driver::getParameter(int key __unused, Parcel *reply __unused) {
return INVALID_OPERATION;
}
if (key == FOURCC('m','t','r','X')) {
// mtrX -- a play on 'metrics' (not matrix)
// gather current info all together, parcel it, and send it back
updateMetrics("api");
mAnalyticsItem->writeToParcel(reply);
status_t NuPlayer2Driver::getMetrics(char **buffer, size_t *length) {
updateMetrics("api");
if (mediametrics_getAttributes(mMetricsHandle, buffer, length))
return OK;
}
return INVALID_OPERATION;
else
return FAILED_TRANSACTION;
}
void NuPlayer2Driver::notifyResetComplete(int64_t /* srcId */) {
@ -867,11 +864,11 @@ void NuPlayer2Driver::notifyListener_l(
// ext1 is our primary 'error type' value. Only add ext2 when non-zero.
// [test against msg is due to fall through from previous switch value]
if (msg == MEDIA2_ERROR) {
mAnalyticsItem->setInt32(kPlayerError, ext1);
mediametrics_setInt32(mMetricsHandle, kPlayerError, ext1);
if (ext2 != 0) {
mAnalyticsItem->setInt32(kPlayerErrorCode, ext2);
mediametrics_setInt32(mMetricsHandle, kPlayerErrorCode, ext2);
}
mAnalyticsItem->setCString(kPlayerErrorState, stateString(mState).c_str());
mediametrics_setCString(mMetricsHandle, kPlayerErrorState, stateString(mState).c_str());
}
mAtEOS = true;
break;

@ -16,7 +16,7 @@
#include <mediaplayer2/MediaPlayer2Interface.h>
#include <media/MediaAnalyticsItem.h>
#include <media/MediaMetrics.h>
#include <media/stagefright/foundation/ABase.h>
#include <mediaplayer2/JObjectHolder.h>
@ -61,6 +61,7 @@ struct NuPlayer2Driver : public MediaPlayer2Interface {
virtual void setAudioSink(const sp<AudioSink> &audioSink) override;
virtual status_t setParameter(int key, const Parcel &request) override;
virtual status_t getParameter(int key, Parcel *reply) override;
virtual status_t getMetrics(char **buf, size_t *length) override;
virtual status_t dump(int fd, const Vector<String16> &args) const override;
@ -132,7 +133,7 @@ private:
sp<AudioSink> mAudioSink;
uint32_t mPlayerFlags;
MediaAnalyticsItem *mAnalyticsItem;
mediametrics_handle_t mMetricsHandle;
uid_t mClientUid;
bool mAtEOS;

Loading…
Cancel
Save