diff options
| author | Adam Stone <blueeyes@google.com> | 2018-02-13 18:14:40 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2018-02-13 18:14:40 +0000 |
| commit | 8cc97b178bc6c744eaeef526eca7a4e3f24a1a0e (patch) | |
| tree | 5a094043d266c0c87b0292e659eab22ae7d034be /drm/libmediadrm | |
| parent | 031b695b8e37ca3591ac2f5eb952f6c21439d445 (diff) | |
| parent | 568b3c45d48fab64c80b2780e8547564d35722e9 (diff) | |
| download | frameworks_av-8cc97b178bc6c744eaeef526eca7a4e3f24a1a0e.tar.gz frameworks_av-8cc97b178bc6c744eaeef526eca7a4e3f24a1a0e.tar.bz2 frameworks_av-8cc97b178bc6c744eaeef526eca7a4e3f24a1a0e.zip | |
Merge changes from topic "media-drm-fix-list-metrics"
* changes:
Fix Metrics with PersistableBundle support
Fix DrmHal implementation to return all metrics
Diffstat (limited to 'drm/libmediadrm')
| -rw-r--r-- | drm/libmediadrm/DrmHal.cpp | 7 | ||||
| -rw-r--r-- | drm/libmediadrm/DrmMetrics.cpp | 278 | ||||
| -rw-r--r-- | drm/libmediadrm/IDrm.cpp | 40 | ||||
| -rw-r--r-- | drm/libmediadrm/tests/Android.bp | 1 | ||||
| -rw-r--r-- | drm/libmediadrm/tests/DrmMetrics_test.cpp | 81 |
5 files changed, 266 insertions, 141 deletions
diff --git a/drm/libmediadrm/DrmHal.cpp b/drm/libmediadrm/DrmHal.cpp index 039e1e994b..6b782f034a 100644 --- a/drm/libmediadrm/DrmHal.cpp +++ b/drm/libmediadrm/DrmHal.cpp @@ -52,6 +52,7 @@ using ::android::hardware::hidl_vec; using ::android::hardware::Return; using ::android::hardware::Void; using ::android::hidl::manager::V1_0::IServiceManager; +using ::android::os::PersistableBundle; using ::android::sp; namespace { @@ -594,6 +595,7 @@ status_t DrmHal::openSession(DrmPlugin::SecurityLevel level, DrmSessionManager::Instance()->addSession(getCallingPid(), mDrmSessionClient, sessionId); mOpenSessions.push(sessionId); + mMetrics.SetSessionStart(sessionId); } mMetrics.mOpenSessionCounter.Increment(err); @@ -615,9 +617,10 @@ status_t DrmHal::closeSession(Vector<uint8_t> const &sessionId) { } } } - reportMetrics(); status_t response = toStatusT(status); + mMetrics.SetSessionEnd(sessionId); mMetrics.mCloseSessionCounter.Increment(response); + reportMetrics(); return response; } mMetrics.mCloseSessionCounter.Increment(DEAD_OBJECT); @@ -1095,7 +1098,7 @@ status_t DrmHal::setPropertyByteArray(String8 const &name, return toStatusT(status); } -status_t DrmHal::getMetrics(MediaAnalyticsItem* item) { +status_t DrmHal::getMetrics(PersistableBundle* item) { if (item == nullptr) { return UNEXPECTED_NULL; } diff --git a/drm/libmediadrm/DrmMetrics.cpp b/drm/libmediadrm/DrmMetrics.cpp index 258c4b0d08..dd91058ba4 100644 --- a/drm/libmediadrm/DrmMetrics.cpp +++ b/drm/libmediadrm/DrmMetrics.cpp @@ -14,106 +14,164 @@ * limitations under the License. */ +#include <utility> + #include <android-base/macros.h> #include <media/DrmMetrics.h> +#include <media/stagefright/foundation/base64.h> +#include <sys/time.h> +#include <utils/Timers.h> using ::android::hardware::drm::V1_0::EventType; using ::android::hardware::drm::V1_0::KeyStatusType; +using ::android::os::PersistableBundle; namespace { -template<typename T> -std::string GetAttributeName(T type); - -template<> -std::string GetAttributeName<KeyStatusType>(KeyStatusType type) { - static const char* type_names[] = { - "USABLE", "EXPIRED", "OUTPUT_NOT_ALLOWED", - "STATUS_PENDING", "INTERNAL_ERROR" }; - if (((size_t) type) > arraysize(type_names)) { - return "UNKNOWN_TYPE"; - } - return type_names[(size_t) type]; +template <typename T> std::string GetAttributeName(T type); + +template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) { + static const char *type_names[] = {"USABLE", "EXPIRED", + "OUTPUT_NOT_ALLOWED", "STATUS_PENDING", + "INTERNAL_ERROR"}; + if (((size_t)type) > arraysize(type_names)) { + return "UNKNOWN_TYPE"; + } + return type_names[(size_t)type]; } -template<> -std::string GetAttributeName<EventType>(EventType type) { - static const char* type_names[] = { - "PROVISION_REQUIRED", "KEY_NEEDED", "KEY_EXPIRED", - "VENDOR_DEFINED", "SESSION_RECLAIMED" }; - if (((size_t) type) > arraysize(type_names)) { - return "UNKNOWN_TYPE"; - } - return type_names[(size_t) type]; +template <> std::string GetAttributeName<EventType>(EventType type) { + static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED", + "KEY_EXPIRED", "VENDOR_DEFINED", + "SESSION_RECLAIMED"}; + if (((size_t)type) > arraysize(type_names)) { + return "UNKNOWN_TYPE"; + } + return type_names[(size_t)type]; } -template<typename T> -void ExportCounterMetric(const android::CounterMetric<T>& counter, - android::MediaAnalyticsItem* item) { - if (!item) { - ALOGE("item was unexpectedly null."); - return; - } - std::string success_count_name = counter.metric_name() + ".ok.count"; - std::string error_count_name = counter.metric_name() + ".error.count"; - counter.ExportValues( - [&] (const android::status_t status, const int64_t value) { - if (status == android::OK) { - item->setInt64(success_count_name.c_str(), value); - } else { - int64_t total_errors(0); - item->getInt64(error_count_name.c_str(), &total_errors); - item->setInt64(error_count_name.c_str(), total_errors + value); - // TODO: Add support for exporting the list of error values. - // This probably needs to be added to MediaAnalyticsItem. - } - }); +template <typename T> +void ExportCounterMetric(const android::CounterMetric<T> &counter, + PersistableBundle *metrics) { + if (!metrics) { + ALOGE("metrics was unexpectedly null."); + return; + } + std::string success_count_name = counter.metric_name() + ".ok.count"; + std::string error_count_name = counter.metric_name() + ".error.count"; + std::vector<int64_t> status_values; + counter.ExportValues( + [&](const android::status_t status, const int64_t value) { + if (status == android::OK) { + metrics->putLong(android::String16(success_count_name.c_str()), + value); + } else { + int64_t total_errors(0); + metrics->getLong(android::String16(error_count_name.c_str()), + &total_errors); + metrics->putLong(android::String16(error_count_name.c_str()), + total_errors + value); + status_values.push_back(status); + } + }); + if (!status_values.empty()) { + std::string error_list_name = counter.metric_name() + ".error.list"; + metrics->putLongVector(android::String16(error_list_name.c_str()), + status_values); + } } -template<typename T> +template <typename T> void ExportCounterMetricWithAttributeNames( - const android::CounterMetric<T>& counter, - android::MediaAnalyticsItem* item) { - if (!item) { - ALOGE("item was unexpectedly null."); - return; - } - counter.ExportValues( - [&] (const T& attribute, const int64_t value) { - std::string name = counter.metric_name() - + "." + GetAttributeName(attribute) + ".count"; - item->setInt64(name.c_str(), value); - }); + const android::CounterMetric<T> &counter, PersistableBundle *metrics) { + if (!metrics) { + ALOGE("metrics was unexpectedly null."); + return; + } + counter.ExportValues([&](const T &attribute, const int64_t value) { + std::string name = counter.metric_name() + "." + + GetAttributeName(attribute) + ".count"; + metrics->putLong(android::String16(name.c_str()), value); + }); } -template<typename T> -void ExportEventMetric(const android::EventMetric<T>& event, - android::MediaAnalyticsItem* item) { - if (!item) { - ALOGE("item was unexpectedly null."); - return; - } - std::string success_count_name = event.metric_name() + ".ok.count"; - std::string error_count_name = event.metric_name() + ".error.count"; - std::string timing_name = event.metric_name() + ".ok.average_time_micros"; - event.ExportValues( - [&] (const android::status_t& status, - const android::EventStatistics& value) { - if (status == android::OK) { - item->setInt64(success_count_name.c_str(), value.count); - item->setInt64(timing_name.c_str(), value.mean); - } else { - int64_t total_errors(0); - item->getInt64(error_count_name.c_str(), &total_errors); - item->setInt64(error_count_name.c_str(), +template <typename T> +void ExportEventMetric(const android::EventMetric<T> &event, + PersistableBundle *metrics) { + if (!metrics) { + ALOGE("metrics was unexpectedly null."); + return; + } + std::string success_count_name = event.metric_name() + ".ok.count"; + std::string error_count_name = event.metric_name() + ".error.count"; + std::string timing_name = event.metric_name() + ".ok.average_time_micros"; + std::vector<int64_t> status_values; + event.ExportValues([&](const android::status_t &status, + const android::EventStatistics &value) { + if (status == android::OK) { + metrics->putLong(android::String16(success_count_name.c_str()), + value.count); + metrics->putLong(android::String16(timing_name.c_str()), + value.mean); + } else { + int64_t total_errors(0); + metrics->getLong(android::String16(error_count_name.c_str()), + &total_errors); + metrics->putLong(android::String16(error_count_name.c_str()), total_errors + value.count); - // TODO: Add support for exporting the list of error values. - // This probably needs to be added to MediaAnalyticsItem. - } - }); + status_values.push_back(status); + } + }); + if (!status_values.empty()) { + std::string error_list_name = event.metric_name() + ".error.list"; + metrics->putLongVector(android::String16(error_list_name.c_str()), + status_values); + } +} + +void ExportSessionLifespans( + const std::map<android::String16, std::pair<int64_t, int64_t>> + &mSessionLifespans, + PersistableBundle *metrics) { + if (!metrics) { + ALOGE("metrics was unexpectedly null."); + return; + } + + if (mSessionLifespans.empty()) { + return; + } + + PersistableBundle startTimesBundle; + PersistableBundle endTimesBundle; + for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end(); + it++) { + startTimesBundle.putLong(android::String16(it->first), + it->second.first); + endTimesBundle.putLong(android::String16(it->first), it->second.second); + } + metrics->putPersistableBundle( + android::String16("drm.mediadrm.session_start_times_ms"), + startTimesBundle); + metrics->putPersistableBundle( + android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle); +} + +android::String8 ToHexString(const android::Vector<uint8_t> &sessionId) { + android::String8 result; + for (size_t i = 0; i < sessionId.size(); i++) { + result.appendFormat("%02x", sessionId[i]); + } + return result; +} + +int64_t getCurrentTimeMs() { + struct timeval tv; + gettimeofday(&tv, NULL); + return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000); } -} // namespace anonymous +} // namespace namespace android { @@ -122,31 +180,49 @@ MediaDrmMetrics::MediaDrmMetrics() mCloseSessionCounter("drm.mediadrm.close_session", "status"), mGetKeyRequestTiming("drm.mediadrm.get_key_request", "status"), mProvideKeyResponseTiming("drm.mediadrm.provide_key_response", "status"), - mGetProvisionRequestCounter( - "drm.mediadrm.get_provision_request", "status"), + mGetProvisionRequestCounter("drm.mediadrm.get_provision_request", + "status"), mProvideProvisionResponseCounter( "drm.mediadrm.provide_provision_response", "status"), - mKeyStatusChangeCounter( - "drm.mediadrm.key_status_change", "key_status_type"), + mKeyStatusChangeCounter("drm.mediadrm.key_status_change", + "key_status_type"), mEventCounter("drm.mediadrm.event", "event_type"), - mGetDeviceUniqueIdCounter( - "drm.mediadrm.get_device_unique_id", "status") { + mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") { +} + +void MediaDrmMetrics::SetSessionStart( + const android::Vector<uint8_t> &sessionId) { + String16 sessionIdHex = String16(ToHexString(sessionId)); + mSessionLifespans[sessionIdHex] = + std::make_pair(getCurrentTimeMs(), (int64_t)0); +} + +void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) { + String16 sessionIdHex = String16(ToHexString(sessionId)); + int64_t endTimeMs = getCurrentTimeMs(); + if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) { + mSessionLifespans[sessionIdHex] = + std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs); + } else { + mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs); + } } -void MediaDrmMetrics::Export(MediaAnalyticsItem* item) { - if (!item) { - ALOGE("item was unexpectedly null."); - return; - } - ExportCounterMetric(mOpenSessionCounter, item); - ExportCounterMetric(mCloseSessionCounter, item); - ExportEventMetric(mGetKeyRequestTiming, item); - ExportEventMetric(mProvideKeyResponseTiming, item); - ExportCounterMetric(mGetProvisionRequestCounter, item); - ExportCounterMetric(mProvideProvisionResponseCounter, item); - ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, item); - ExportCounterMetricWithAttributeNames(mEventCounter, item); - ExportCounterMetric(mGetDeviceUniqueIdCounter, item); +void MediaDrmMetrics::Export(PersistableBundle *metrics) { + if (!metrics) { + ALOGE("metrics was unexpectedly null."); + return; + } + ExportCounterMetric(mOpenSessionCounter, metrics); + ExportCounterMetric(mCloseSessionCounter, metrics); + ExportEventMetric(mGetKeyRequestTiming, metrics); + ExportEventMetric(mProvideKeyResponseTiming, metrics); + ExportCounterMetric(mGetProvisionRequestCounter, metrics); + ExportCounterMetric(mProvideProvisionResponseCounter, metrics); + ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics); + ExportCounterMetricWithAttributeNames(mEventCounter, metrics); + ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics); + ExportSessionLifespans(mSessionLifespans, metrics); } -} // namespace android +} // namespace android diff --git a/drm/libmediadrm/IDrm.cpp b/drm/libmediadrm/IDrm.cpp index 9f54dba73c..22e4e6cf6d 100644 --- a/drm/libmediadrm/IDrm.cpp +++ b/drm/libmediadrm/IDrm.cpp @@ -492,7 +492,10 @@ struct BpDrm : public BpInterface<IDrm> { return reply.readInt32(); } - virtual status_t getMetrics(MediaAnalyticsItem *item) { + virtual status_t getMetrics(os::PersistableBundle *metrics) { + if (metrics == NULL) { + return BAD_VALUE; + } Parcel data, reply; data.writeInterfaceToken(IDrm::getInterfaceDescriptor()); @@ -500,9 +503,23 @@ struct BpDrm : public BpInterface<IDrm> { if (status != OK) { return status; } + // The reply data is ordered as + // 1) 32 bit integer reply followed by + // 2) Serialized PersistableBundle containing metrics. + status_t reply_status; + if (reply.readInt32(&reply_status) != OK + || reply_status != OK) { + ALOGE("Failed to read getMetrics response code from parcel. %d", + reply_status); + return reply_status; + } - item->readFromParcel(reply); - return reply.readInt32(); + status = metrics->readFromParcel(&reply); + if (status != OK) { + ALOGE("Failed to read metrics from parcel. %d", status); + return status; + } + return reply_status; } virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId, @@ -1008,11 +1025,18 @@ status_t BnDrm::onTransact( { CHECK_INTERFACE(IDrm, data, reply); - MediaAnalyticsItem item; - status_t result = getMetrics(&item); - item.writeToParcel(reply); - reply->writeInt32(result); - return OK; + os::PersistableBundle metrics; + status_t result = getMetrics(&metrics); + // The reply data is ordered as + // 1) 32 bit integer reply followed by + // 2) Serialized PersistableBundle containing metrics. + // Only write the metrics if the getMetrics result was + // OK and we successfully added the status to reply. + status_t parcel_result = reply->writeInt32(result); + if (result == OK && parcel_result == OK) { + parcel_result = metrics.writeToParcel(reply); + } + return parcel_result; } case SET_CIPHER_ALGORITHM: diff --git a/drm/libmediadrm/tests/Android.bp b/drm/libmediadrm/tests/Android.bp index fdc982dcba..b508c59f31 100644 --- a/drm/libmediadrm/tests/Android.bp +++ b/drm/libmediadrm/tests/Android.bp @@ -16,6 +16,7 @@ cc_test { srcs: ["DrmMetrics_test.cpp"], shared_libs: [ "android.hardware.drm@1.0", + "libbinder", "liblog", "libmediadrm", "libmediametrics", diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp index d1948b478a..d774eae6ed 100644 --- a/drm/libmediadrm/tests/DrmMetrics_test.cpp +++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp @@ -14,12 +14,14 @@ * limitations under the License. */ +#include <binder/PersistableBundle.h> #include <gtest/gtest.h> #include "DrmMetrics.h" using ::android::hardware::drm::V1_0::EventType; using ::android::hardware::drm::V1_0::KeyStatusType; +using ::android::os::PersistableBundle; namespace android { @@ -31,10 +33,10 @@ class MediaDrmMetricsTest : public ::testing::Test { TEST_F(MediaDrmMetricsTest, EmptySuccess) { MediaDrmMetrics metrics; - MediaAnalyticsItem item; + PersistableBundle bundle; - metrics.Export(&item); - EXPECT_EQ(0, item.count()); + metrics.Export(&bundle); + EXPECT_TRUE(bundle.empty()); } TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) { @@ -58,10 +60,10 @@ TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) { metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE); metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED); - MediaAnalyticsItem item; + PersistableBundle bundle; - metrics.Export(&item); - EXPECT_EQ(11, item.count()); + metrics.Export(&bundle); + EXPECT_EQ(11U, bundle.size()); // Verify the list of pairs of int64 metrics. std::vector<std::pair<std::string, int64_t>> expected_values = { @@ -75,24 +77,24 @@ TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) { { "drm.mediadrm.event.PROVISION_REQUIRED.count", 1 }, { "drm.mediadrm.get_device_unique_id.ok.count", 1 }}; for (const auto& expected_pair : expected_values) { + String16 key(expected_pair.first.c_str()); int64_t value = -1; - EXPECT_TRUE(item.getInt64(expected_pair.first.c_str(), &value)) - << "Failed to get " << expected_pair.first; + EXPECT_TRUE(bundle.getLong(key, &value)) + << "Unexpected error retrieviing key: " << key; EXPECT_EQ(expected_pair.second, value) - << "Unexpected value for " << expected_pair.first; + << "Unexpected value for " << expected_pair.first << ". " << value; } // Validate timing values exist. + String16 get_key_request_key( + "drm.mediadrm.get_key_request.ok.average_time_micros"); + String16 provide_key_response_key( + "drm.mediadrm.provide_key_response.ok.average_time_micros"); int64_t value = -1; - EXPECT_TRUE( - item.getInt64("drm.mediadrm.get_key_request.ok.average_time_micros", - &value)); + EXPECT_TRUE(bundle.getLong(get_key_request_key, &value)); EXPECT_GE(value, 0); - value = -1; - EXPECT_TRUE( - item.getInt64("drm.mediadrm.provide_key_response.ok.average_time_micros", - &value)); + EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value)); EXPECT_GE(value, 0); } @@ -133,10 +135,9 @@ TEST_F(MediaDrmMetricsTest, AllValuesFull) { metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED); metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED); - MediaAnalyticsItem item; - - metrics.Export(&item); - EXPECT_EQ(26, item.count()); + PersistableBundle bundle; + metrics.Export(&bundle); + EXPECT_EQ(33U, bundle.size()); // Verify the list of pairs of int64 metrics. std::vector<std::pair<std::string, int64_t>> expected_values = { @@ -165,24 +166,44 @@ TEST_F(MediaDrmMetricsTest, AllValuesFull) { { "drm.mediadrm.event.VENDOR_DEFINED.count", 1 }, { "drm.mediadrm.event.SESSION_RECLAIMED.count", 1 }}; for (const auto& expected_pair : expected_values) { + String16 key(expected_pair.first.c_str()); int64_t value = -1; - EXPECT_TRUE(item.getInt64(expected_pair.first.c_str(), &value)) - << "Failed to get " << expected_pair.first; + EXPECT_TRUE(bundle.getLong(key, &value)) + << "Unexpected error retrieviing key: " << key; EXPECT_EQ(expected_pair.second, value) - << "Unexpected value for " << expected_pair.first; + << "Unexpected value for " << expected_pair.first << ". " << value; + } + + // Verify the error lists + std::vector<std::pair<std::string, std::vector<int64_t>>> expected_vector_values = { + { "drm.mediadrm.close_session.error.list", { UNEXPECTED_NULL } }, + { "drm.mediadrm.get_device_unique_id.error.list", { UNEXPECTED_NULL } }, + { "drm.mediadrm.get_key_request.error.list", { UNEXPECTED_NULL } }, + { "drm.mediadrm.get_provision_request.error.list", { UNEXPECTED_NULL } }, + { "drm.mediadrm.open_session.error.list", { UNEXPECTED_NULL } }, + { "drm.mediadrm.provide_key_response.error.list", { UNEXPECTED_NULL } }, + { "drm.mediadrm.provide_provision_response.error.list", { UNEXPECTED_NULL } }}; + for (const auto& expected_pair : expected_vector_values) { + String16 key(expected_pair.first.c_str()); + std::vector<int64_t> values; + EXPECT_TRUE(bundle.getLongVector(key, &values)) + << "Unexpected error retrieviing key: " << key; + for (auto expected : expected_pair.second) { + EXPECT_TRUE(std::find(values.begin(), values.end(), expected) != values.end()) + << "Could not find " << expected << " for key " << expected_pair.first; + } } // Validate timing values exist. + String16 get_key_request_key( + "drm.mediadrm.get_key_request.ok.average_time_micros"); + String16 provide_key_response_key( + "drm.mediadrm.provide_key_response.ok.average_time_micros"); int64_t value = -1; - EXPECT_TRUE( - item.getInt64("drm.mediadrm.get_key_request.ok.average_time_micros", - &value)); + EXPECT_TRUE(bundle.getLong(get_key_request_key, &value)); EXPECT_GE(value, 0); - value = -1; - EXPECT_TRUE( - item.getInt64("drm.mediadrm.provide_key_response.ok.average_time_micros", - &value)); + EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value)); EXPECT_GE(value, 0); } |
