Loading media/libmediametrics/include/MediaMetricsItem.h +43 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,49 @@ namespace android { /* * MediaMetrics Keys and Properties for Audio. * * C/C++ friendly constants that ensure * 1) Compilation error on misspelling * 2) Consistent behavior and documentation. * * TODO: Move to separate header file. */ // Taxonomy of audio keys // Key Prefixes are used for MediaMetrics Item Keys and ends with a ".". // They must be appended with another value to make a key. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio." // The AudioRecord key appends the "trackId" to the prefix. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record." // The AudioThread key appends the "threadId" to the prefix. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread." // The AudioTrack key appends the "trackId" to the prefix. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK AMEDIAMETRICS_KEY_PREFIX_AUDIO "track." // Keys are strings used for MediaMetrics Item Keys #define AMEDIAMETRICS_KEY_AUDIO_FLINGER AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger" #define AMEDIAMETRICS_KEY_AUDIO_POLICY AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy" // Props are properties allowed for Mediametrics Items. #define AMEDIAMETRICS_PROP_EVENT "event" // string value (often func name) #define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value #define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value #define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value #define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle // Values are strings accepted for a given property. // An event is a general description, which often is a function name. #define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor" #define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor" #define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN "underrun" // from Thread class IMediaMetricsService; class Parcel; Loading services/mediametrics/AnalyticsState.h +18 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,24 @@ public: return mTimeMachine.put(item, isTrusted) ?: mTransactionLog.put(item); } /** * Returns the TimeMachine. * * The TimeMachine object is internally locked, so access is safe and defined, * but multiple threaded access may change results after calling. */ TimeMachine& timeMachine() { return mTimeMachine; } const TimeMachine& timeMachine() const { return mTimeMachine; } /** * Returns the TransactionLog. * * The TransactionLog object is internally locked, so access is safe and defined, * but multiple threaded access may change results after calling. */ TransactionLog& transactionLog() { return mTransactionLog; } const TransactionLog& transactionLog() const { return mTransactionLog; } /** * Returns a pair consisting of the dump string, and the number of lines in the string. * Loading services/mediametrics/AudioAnalytics.cpp +61 −5 Original line number Diff line number Diff line Loading @@ -32,16 +32,60 @@ AudioAnalytics::AudioAnalytics() // This triggers on an item of "audio.flinger" // with a property "event" set to "AudioFlinger" (the constructor). mActions.addAction( "audio.flinger.event", std::string("AudioFlinger"), AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT, std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR), std::make_shared<AnalyticsActions::Function>( [this](const std::shared_ptr<const android::mediametrics::Item> &){ ALOGW("Audioflinger() constructor event detected"); [this](const std::shared_ptr<const android::mediametrics::Item> &item){ ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str()); mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>( *mAnalyticsState.get())); // Note: get returns shared_ptr temp, whose lifetime is extended // to end of full expression. mAnalyticsState->clear(); // TODO: filter the analytics state. // Perhaps report this. })); // Check underruns mActions.addAction( AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT, std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN), std::make_shared<AnalyticsActions::Function>( [this](const std::shared_ptr<const android::mediametrics::Item> &item){ std::string threadId = item->getKey().substr( sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) - 1); std::string outputDevices; mAnalyticsState->timeMachine().get( item->getKey(), AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices); ALOGD("(key=%s) Thread underrun event detected on io handle:%s device:%s", item->getKey().c_str(), threadId.c_str(), outputDevices.c_str()); if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) { // report this for Bluetooth } })); // Check latencies, playback and startup mActions.addAction( AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_LATENCYMS, std::monostate{}, // accept any value std::make_shared<AnalyticsActions::Function>( [this](const std::shared_ptr<const android::mediametrics::Item> &item){ double latencyMs{}; double startupMs{}; if (!item->get(AMEDIAMETRICS_PROP_LATENCYMS, &latencyMs) || !item->get(AMEDIAMETRICS_PROP_STARTUPMS, &startupMs)) return; std::string trackId = item->getKey().substr( sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) - 1); std::string thread = getThreadFromTrack(item->getKey()); std::string outputDevices; mAnalyticsState->timeMachine().get( thread, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices); ALOGD("(key=%s) Track latencyMs:%lf startupMs:%lf detected on port:%s device:%s", item->getKey().c_str(), latencyMs, startupMs, trackId.c_str(), outputDevices.c_str()); if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) { // report this for Bluetooth } })); } Loading @@ -53,7 +97,7 @@ AudioAnalytics::~AudioAnalytics() status_t AudioAnalytics::submit( const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted) { if (!startsWith(item->getKey(), "audio.")) return BAD_VALUE; if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE; status_t status = mAnalyticsState->submit(item, isTrusted); if (status != NO_ERROR) return status; // may not be permitted. Loading Loading @@ -94,4 +138,16 @@ void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item } } // HELPER METHODS std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const { int32_t threadId_int32{}; if (mAnalyticsState->timeMachine().get( track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) { return {}; } return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32); } } // namespace android services/mediametrics/AudioAnalytics.h +8 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,14 @@ private: */ void checkActions(const std::shared_ptr<const mediametrics::Item>& item); // HELPER METHODS /** * Return the audio thread associated with an audio track name. * e.g. "audio.track.32" -> "audio.thread.10" if the associated * threadId for the audio track is 10. */ std::string getThreadFromTrack(const std::string& track) const; // Actions is individually locked AnalyticsActions mActions; Loading Loading
media/libmediametrics/include/MediaMetricsItem.h +43 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,49 @@ namespace android { /* * MediaMetrics Keys and Properties for Audio. * * C/C++ friendly constants that ensure * 1) Compilation error on misspelling * 2) Consistent behavior and documentation. * * TODO: Move to separate header file. */ // Taxonomy of audio keys // Key Prefixes are used for MediaMetrics Item Keys and ends with a ".". // They must be appended with another value to make a key. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO "audio." // The AudioRecord key appends the "trackId" to the prefix. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_RECORD AMEDIAMETRICS_KEY_PREFIX_AUDIO "record." // The AudioThread key appends the "threadId" to the prefix. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD AMEDIAMETRICS_KEY_PREFIX_AUDIO "thread." // The AudioTrack key appends the "trackId" to the prefix. #define AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK AMEDIAMETRICS_KEY_PREFIX_AUDIO "track." // Keys are strings used for MediaMetrics Item Keys #define AMEDIAMETRICS_KEY_AUDIO_FLINGER AMEDIAMETRICS_KEY_PREFIX_AUDIO "flinger" #define AMEDIAMETRICS_KEY_AUDIO_POLICY AMEDIAMETRICS_KEY_PREFIX_AUDIO "policy" // Props are properties allowed for Mediametrics Items. #define AMEDIAMETRICS_PROP_EVENT "event" // string value (often func name) #define AMEDIAMETRICS_PROP_LATENCYMS "latencyMs" // double value #define AMEDIAMETRICS_PROP_OUTPUTDEVICES "outputDevices" // string value #define AMEDIAMETRICS_PROP_STARTUPMS "startupMs" // double value #define AMEDIAMETRICS_PROP_THREADID "threadId" // int32 value io handle // Values are strings accepted for a given property. // An event is a general description, which often is a function name. #define AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR "ctor" #define AMEDIAMETRICS_PROP_EVENT_VALUE_DTOR "dtor" #define AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN "underrun" // from Thread class IMediaMetricsService; class Parcel; Loading
services/mediametrics/AnalyticsState.h +18 −0 Original line number Diff line number Diff line Loading @@ -55,6 +55,24 @@ public: return mTimeMachine.put(item, isTrusted) ?: mTransactionLog.put(item); } /** * Returns the TimeMachine. * * The TimeMachine object is internally locked, so access is safe and defined, * but multiple threaded access may change results after calling. */ TimeMachine& timeMachine() { return mTimeMachine; } const TimeMachine& timeMachine() const { return mTimeMachine; } /** * Returns the TransactionLog. * * The TransactionLog object is internally locked, so access is safe and defined, * but multiple threaded access may change results after calling. */ TransactionLog& transactionLog() { return mTransactionLog; } const TransactionLog& transactionLog() const { return mTransactionLog; } /** * Returns a pair consisting of the dump string, and the number of lines in the string. * Loading
services/mediametrics/AudioAnalytics.cpp +61 −5 Original line number Diff line number Diff line Loading @@ -32,16 +32,60 @@ AudioAnalytics::AudioAnalytics() // This triggers on an item of "audio.flinger" // with a property "event" set to "AudioFlinger" (the constructor). mActions.addAction( "audio.flinger.event", std::string("AudioFlinger"), AMEDIAMETRICS_KEY_AUDIO_FLINGER "." AMEDIAMETRICS_PROP_EVENT, std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_CTOR), std::make_shared<AnalyticsActions::Function>( [this](const std::shared_ptr<const android::mediametrics::Item> &){ ALOGW("Audioflinger() constructor event detected"); [this](const std::shared_ptr<const android::mediametrics::Item> &item){ ALOGW("(key=%s) Audioflinger constructor event detected", item->getKey().c_str()); mPreviousAnalyticsState.set(std::make_shared<AnalyticsState>( *mAnalyticsState.get())); // Note: get returns shared_ptr temp, whose lifetime is extended // to end of full expression. mAnalyticsState->clear(); // TODO: filter the analytics state. // Perhaps report this. })); // Check underruns mActions.addAction( AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD "*." AMEDIAMETRICS_PROP_EVENT, std::string(AMEDIAMETRICS_PROP_EVENT_VALUE_UNDERRUN), std::make_shared<AnalyticsActions::Function>( [this](const std::shared_ptr<const android::mediametrics::Item> &item){ std::string threadId = item->getKey().substr( sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) - 1); std::string outputDevices; mAnalyticsState->timeMachine().get( item->getKey(), AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices); ALOGD("(key=%s) Thread underrun event detected on io handle:%s device:%s", item->getKey().c_str(), threadId.c_str(), outputDevices.c_str()); if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) { // report this for Bluetooth } })); // Check latencies, playback and startup mActions.addAction( AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK "*." AMEDIAMETRICS_PROP_LATENCYMS, std::monostate{}, // accept any value std::make_shared<AnalyticsActions::Function>( [this](const std::shared_ptr<const android::mediametrics::Item> &item){ double latencyMs{}; double startupMs{}; if (!item->get(AMEDIAMETRICS_PROP_LATENCYMS, &latencyMs) || !item->get(AMEDIAMETRICS_PROP_STARTUPMS, &startupMs)) return; std::string trackId = item->getKey().substr( sizeof(AMEDIAMETRICS_KEY_PREFIX_AUDIO_TRACK) - 1); std::string thread = getThreadFromTrack(item->getKey()); std::string outputDevices; mAnalyticsState->timeMachine().get( thread, AMEDIAMETRICS_PROP_OUTPUTDEVICES, &outputDevices); ALOGD("(key=%s) Track latencyMs:%lf startupMs:%lf detected on port:%s device:%s", item->getKey().c_str(), latencyMs, startupMs, trackId.c_str(), outputDevices.c_str()); if (outputDevices.find("AUDIO_DEVICE_OUT_BLUETOOTH") != std::string::npos) { // report this for Bluetooth } })); } Loading @@ -53,7 +97,7 @@ AudioAnalytics::~AudioAnalytics() status_t AudioAnalytics::submit( const std::shared_ptr<const mediametrics::Item>& item, bool isTrusted) { if (!startsWith(item->getKey(), "audio.")) return BAD_VALUE; if (!startsWith(item->getKey(), AMEDIAMETRICS_KEY_PREFIX_AUDIO)) return BAD_VALUE; status_t status = mAnalyticsState->submit(item, isTrusted); if (status != NO_ERROR) return status; // may not be permitted. Loading Loading @@ -94,4 +138,16 @@ void AudioAnalytics::checkActions(const std::shared_ptr<const mediametrics::Item } } // HELPER METHODS std::string AudioAnalytics::getThreadFromTrack(const std::string& track) const { int32_t threadId_int32{}; if (mAnalyticsState->timeMachine().get( track, AMEDIAMETRICS_PROP_THREADID, &threadId_int32) != NO_ERROR) { return {}; } return std::string(AMEDIAMETRICS_KEY_PREFIX_AUDIO_THREAD) + std::to_string(threadId_int32); } } // namespace android
services/mediametrics/AudioAnalytics.h +8 −0 Original line number Diff line number Diff line Loading @@ -72,6 +72,14 @@ private: */ void checkActions(const std::shared_ptr<const mediametrics::Item>& item); // HELPER METHODS /** * Return the audio thread associated with an audio track name. * e.g. "audio.track.32" -> "audio.thread.10" if the associated * threadId for the audio track is 10. */ std::string getThreadFromTrack(const std::string& track) const; // Actions is individually locked AnalyticsActions mActions; Loading