Loading drm/libmediadrm/DrmHal.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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; } Loading drm/libmediadrm/DrmMetrics.cpp +177 −101 Original line number Diff line number Diff line Loading @@ -14,33 +14,36 @@ * 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 <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" }; 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" }; 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"; } Loading @@ -49,71 +52,126 @@ std::string GetAttributeName<EventType>(EventType type) { template <typename T> void ExportCounterMetric(const android::CounterMetric<T> &counter, android::MediaAnalyticsItem* item) { if (!item) { ALOGE("item was unexpectedly null."); 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) { item->setInt64(success_count_name.c_str(), value); metrics->putLong(android::String16(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. 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> void ExportCounterMetricWithAttributeNames( const android::CounterMetric<T>& counter, android::MediaAnalyticsItem* item) { if (!item) { ALOGE("item was unexpectedly null."); 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"; item->setInt64(name.c_str(), value); 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."); 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"; event.ExportValues( [&] (const android::status_t& status, std::vector<int64_t> status_values; 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); 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); item->getInt64(error_count_name.c_str(), &total_errors); item->setInt64(error_count_name.c_str(), 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); } } } // namespace anonymous 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 namespace android { Loading @@ -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."); void MediaDrmMetrics::Export(PersistableBundle *metrics) { if (!metrics) { ALOGE("metrics 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); 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 drm/libmediadrm/IDrm.cpp +32 −8 Original line number Diff line number Diff line Loading @@ -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()); Loading @@ -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, Loading Loading @@ -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: Loading drm/libmediadrm/tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ cc_test { srcs: ["DrmMetrics_test.cpp"], shared_libs: [ "android.hardware.drm@1.0", "libbinder", "liblog", "libmediadrm", "libmediametrics", Loading drm/libmediadrm/tests/DrmMetrics_test.cpp +51 −30 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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) { Loading @@ -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 = { Loading @@ -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); } Loading Loading @@ -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 = { Loading Loading @@ -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); } Loading Loading
drm/libmediadrm/DrmHal.cpp +5 −2 Original line number Diff line number Diff line Loading @@ -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 { Loading Loading @@ -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); Loading @@ -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); Loading Loading @@ -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; } Loading
drm/libmediadrm/DrmMetrics.cpp +177 −101 Original line number Diff line number Diff line Loading @@ -14,33 +14,36 @@ * 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 <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" }; 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" }; 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"; } Loading @@ -49,71 +52,126 @@ std::string GetAttributeName<EventType>(EventType type) { template <typename T> void ExportCounterMetric(const android::CounterMetric<T> &counter, android::MediaAnalyticsItem* item) { if (!item) { ALOGE("item was unexpectedly null."); 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) { item->setInt64(success_count_name.c_str(), value); metrics->putLong(android::String16(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. 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> void ExportCounterMetricWithAttributeNames( const android::CounterMetric<T>& counter, android::MediaAnalyticsItem* item) { if (!item) { ALOGE("item was unexpectedly null."); 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"; item->setInt64(name.c_str(), value); 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."); 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"; event.ExportValues( [&] (const android::status_t& status, std::vector<int64_t> status_values; 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); 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); item->getInt64(error_count_name.c_str(), &total_errors); item->setInt64(error_count_name.c_str(), 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); } } } // namespace anonymous 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 namespace android { Loading @@ -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."); void MediaDrmMetrics::Export(PersistableBundle *metrics) { if (!metrics) { ALOGE("metrics 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); 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
drm/libmediadrm/IDrm.cpp +32 −8 Original line number Diff line number Diff line Loading @@ -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()); Loading @@ -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, Loading Loading @@ -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: Loading
drm/libmediadrm/tests/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ cc_test { srcs: ["DrmMetrics_test.cpp"], shared_libs: [ "android.hardware.drm@1.0", "libbinder", "liblog", "libmediadrm", "libmediametrics", Loading
drm/libmediadrm/tests/DrmMetrics_test.cpp +51 −30 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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) { Loading @@ -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 = { Loading @@ -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); } Loading Loading @@ -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 = { Loading Loading @@ -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); } Loading