diff options
Diffstat (limited to 'drm/libmediadrm/tests/DrmMetrics_test.cpp')
| -rw-r--r-- | drm/libmediadrm/tests/DrmMetrics_test.cpp | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/drm/libmediadrm/tests/DrmMetrics_test.cpp b/drm/libmediadrm/tests/DrmMetrics_test.cpp new file mode 100644 index 0000000000..64aa9d0c99 --- /dev/null +++ b/drm/libmediadrm/tests/DrmMetrics_test.cpp @@ -0,0 +1,475 @@ +/* + * Copyright 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "DrmMetricsTest" +#include "mediadrm/DrmMetrics.h" + +#include <android/hardware/drm/1.0/types.h> +#include <android/hardware/drm/1.1/types.h> +#include <binder/PersistableBundle.h> +#include <google/protobuf/text_format.h> +#include <google/protobuf/util/message_differencer.h> +#include <gtest/gtest.h> +#include <utils/Log.h> + +#include "protos/metrics.pb.h" + +using ::android::drm_metrics::DrmFrameworkMetrics; +using ::android::hardware::hidl_vec; +using ::android::hardware::drm::V1_0::EventType; +using ::android::hardware::drm::V1_0::KeyStatusType; +using ::android::hardware::drm::V1_0::Status; +using ::android::hardware::drm::V1_1::DrmMetricGroup; +using ::android::os::PersistableBundle; +using ::google::protobuf::util::MessageDifferencer; +using ::google::protobuf::TextFormat; + +namespace android { + +/** + * Unit tests for the MediaDrmMetrics class. + */ +class MediaDrmMetricsTest : public ::testing::Test {}; + +/** + * This derived class mocks the clock for testing purposes. + */ +class FakeMediaDrmMetrics : public MediaDrmMetrics { + public: + FakeMediaDrmMetrics() : MediaDrmMetrics(), time_(0) {}; + + int64_t GetCurrentTimeMs() { return time_++; } + int64_t time_; +}; + +TEST_F(MediaDrmMetricsTest, EmptySuccess) { + MediaDrmMetrics metrics; + PersistableBundle bundle; + + metrics.Export(&bundle); + EXPECT_TRUE(bundle.empty()); +} + +TEST_F(MediaDrmMetricsTest, AllValuesSuccessCounts) { + MediaDrmMetrics metrics; + + metrics.mOpenSessionCounter.Increment(OK); + metrics.mCloseSessionCounter.Increment(OK); + + { + EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs); + EventTimer<status_t> provide_key_response_timer( + &metrics.mProvideKeyResponseTimeUs); + get_key_request_timer.SetAttribute(OK); + provide_key_response_timer.SetAttribute(OK); + } + + metrics.mGetProvisionRequestCounter.Increment(OK); + metrics.mProvideProvisionResponseCounter.Increment(OK); + metrics.mGetDeviceUniqueIdCounter.Increment(OK); + + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE); + metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED); + + PersistableBundle bundle; + + 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 = { + { "drm.mediadrm.open_session.ok.count", 1 }, + { "drm.mediadrm.close_session.ok.count", 1 }, + { "drm.mediadrm.get_key_request.ok.count", 1 }, + { "drm.mediadrm.provide_key_response.ok.count", 1 }, + { "drm.mediadrm.get_provision_request.ok.count", 1 }, + { "drm.mediadrm.provide_provision_response.ok.count", 1 }, + { "drm.mediadrm.key_status_change.USABLE.count", 1 }, + { "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(bundle.getLong(key, &value)) + << "Unexpected error retrieviing key: " << key; + EXPECT_EQ(expected_pair.second, value) + << "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(bundle.getLong(get_key_request_key, &value)); + EXPECT_GE(value, 0); + value = -1; + EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value)); + EXPECT_GE(value, 0); +} + +TEST_F(MediaDrmMetricsTest, AllValuesFull) { + MediaDrmMetrics metrics; + + metrics.mOpenSessionCounter.Increment(OK); + metrics.mOpenSessionCounter.Increment(UNEXPECTED_NULL); + + metrics.mCloseSessionCounter.Increment(OK); + metrics.mCloseSessionCounter.Increment(UNEXPECTED_NULL); + + for (status_t s : {OK, UNEXPECTED_NULL}) { + { + EventTimer<status_t> get_key_request_timer(&metrics.mGetKeyRequestTimeUs); + EventTimer<status_t> provide_key_response_timer( + &metrics.mProvideKeyResponseTimeUs); + get_key_request_timer.SetAttribute(s); + provide_key_response_timer.SetAttribute(s); + } + } + + metrics.mGetProvisionRequestCounter.Increment(OK); + metrics.mGetProvisionRequestCounter.Increment(UNEXPECTED_NULL); + metrics.mProvideProvisionResponseCounter.Increment(OK); + metrics.mProvideProvisionResponseCounter.Increment(UNEXPECTED_NULL); + metrics.mGetDeviceUniqueIdCounter.Increment(OK); + metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL); + + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR); + metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED); + metrics.mEventCounter.Increment(EventType::KEY_NEEDED); + metrics.mEventCounter.Increment(EventType::KEY_EXPIRED); + metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED); + metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED); + + android::Vector<uint8_t> sessionId1; + sessionId1.push_back(1); + sessionId1.push_back(2); + android::Vector<uint8_t> sessionId2; + sessionId2.push_back(3); + sessionId2.push_back(4); + String16 hexSessionId1("0102"); + String16 hexSessionId2("0304"); + + metrics.SetSessionStart(sessionId1); + metrics.SetSessionStart(sessionId2); + metrics.SetSessionEnd(sessionId2); + metrics.SetSessionEnd(sessionId1); + + PersistableBundle bundle; + metrics.Export(&bundle); + EXPECT_EQ(35U, bundle.size()); + + // Verify the list of pairs of int64 metrics. + std::vector<std::pair<std::string, int64_t>> expected_values = { + { "drm.mediadrm.open_session.ok.count", 1 }, + { "drm.mediadrm.close_session.ok.count", 1 }, + { "drm.mediadrm.get_key_request.ok.count", 1 }, + { "drm.mediadrm.provide_key_response.ok.count", 1 }, + { "drm.mediadrm.get_provision_request.ok.count", 1 }, + { "drm.mediadrm.provide_provision_response.ok.count", 1 }, + { "drm.mediadrm.get_device_unique_id.ok.count", 1 }, + { "drm.mediadrm.open_session.error.count", 1 }, + { "drm.mediadrm.close_session.error.count", 1 }, + { "drm.mediadrm.get_key_request.error.count", 1 }, + { "drm.mediadrm.provide_key_response.error.count", 1 }, + { "drm.mediadrm.get_provision_request.error.count", 1 }, + { "drm.mediadrm.provide_provision_response.error.count", 1 }, + { "drm.mediadrm.get_device_unique_id.error.count", 1 }, + { "drm.mediadrm.key_status_change.USABLE.count", 1 }, + { "drm.mediadrm.key_status_change.EXPIRED.count", 1 }, + { "drm.mediadrm.key_status_change.OUTPUT_NOT_ALLOWED.count", 1 }, + { "drm.mediadrm.key_status_change.STATUS_PENDING.count", 1 }, + { "drm.mediadrm.key_status_change.INTERNAL_ERROR.count", 1 }, + { "drm.mediadrm.event.PROVISION_REQUIRED.count", 1 }, + { "drm.mediadrm.event.KEY_NEEDED.count", 1 }, + { "drm.mediadrm.event.KEY_EXPIRED.count", 1 }, + { "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(bundle.getLong(key, &value)) + << "Unexpected error retrieviing key: " << key; + EXPECT_EQ(expected_pair.second, value) + << "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; + } + } + + // Verify the lifespans + PersistableBundle start_times; + PersistableBundle end_times; + String16 start_time_key("drm.mediadrm.session_start_times_ms"); + String16 end_time_key("drm.mediadrm.session_end_times_ms"); + ASSERT_TRUE(bundle.getPersistableBundle(start_time_key, &start_times)); + ASSERT_TRUE(bundle.getPersistableBundle(end_time_key, &end_times)); + EXPECT_EQ(2U, start_times.size()); + EXPECT_EQ(2U, end_times.size()); + int64_t start_time, end_time; + for (const auto& sid : { hexSessionId1, hexSessionId2 }) { + start_time = -1; + end_time = -1; + EXPECT_TRUE(start_times.getLong(sid, &start_time)); + EXPECT_TRUE(end_times.getLong(sid, &end_time)); + EXPECT_GT(start_time, 0); + EXPECT_GE(end_time, start_time); + } + + // 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(bundle.getLong(get_key_request_key, &value)); + EXPECT_GE(value, 0); + value = -1; + EXPECT_TRUE(bundle.getLong(provide_key_response_key, &value)); + EXPECT_GE(value, 0); +} + + +TEST_F(MediaDrmMetricsTest, CounterValuesProtoSerialization) { + MediaDrmMetrics metrics; + + metrics.mOpenSessionCounter.Increment(OK); + metrics.mOpenSessionCounter.Increment(UNEXPECTED_NULL); + metrics.mCloseSessionCounter.Increment(OK); + metrics.mCloseSessionCounter.Increment(UNEXPECTED_NULL); + + metrics.mGetProvisionRequestCounter.Increment(OK); + metrics.mGetProvisionRequestCounter.Increment(UNEXPECTED_NULL); + metrics.mProvideProvisionResponseCounter.Increment(OK); + metrics.mProvideProvisionResponseCounter.Increment(UNEXPECTED_NULL); + metrics.mGetDeviceUniqueIdCounter.Increment(OK); + metrics.mGetDeviceUniqueIdCounter.Increment(UNEXPECTED_NULL); + + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::USABLE); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::EXPIRED); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::OUTPUTNOTALLOWED); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::STATUSPENDING); + metrics.mKeyStatusChangeCounter.Increment(KeyStatusType::INTERNALERROR); + metrics.mEventCounter.Increment(EventType::PROVISION_REQUIRED); + metrics.mEventCounter.Increment(EventType::KEY_NEEDED); + metrics.mEventCounter.Increment(EventType::KEY_EXPIRED); + metrics.mEventCounter.Increment(EventType::VENDOR_DEFINED); + metrics.mEventCounter.Increment(EventType::SESSION_RECLAIMED); + + std::string serializedMetrics; + ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics)); + + DrmFrameworkMetrics metricsProto; + ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics)); + + std::string expectedMetrics = + "open_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } " + "open_session_counter { count: 1 attributes { error_code: 0 } } " + "close_session_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } " + "close_session_counter { count: 1 attributes { error_code: 0 } } " + "get_provisioning_request_counter { count: 1 attributes { error_code: -0x7FFFFFF8 } } " + "get_provisioning_request_counter { count: 1 attributes { error_code: 0 } } " + "provide_provisioning_response_counter { count: 1 attributes { error_code: -0x7ffffff8 } } " + "provide_provisioning_response_counter { count: 1 attributes { error_code: 0 } } " + "get_device_unique_id_counter { count: 1 attributes { error_code: -0x7ffffff8 } } " + "get_device_unique_id_counter { count: 1 attributes { error_code: 0 } } " + "key_status_change_counter { count: 1 attributes { key_status_type: 0 } } " + "key_status_change_counter { count: 1 attributes { key_status_type: 1 } } " + "key_status_change_counter { count: 1 attributes { key_status_type: 2 } } " + "key_status_change_counter { count: 1 attributes { key_status_type: 3 } } " + "key_status_change_counter { count: 1 attributes { key_status_type: 4 } } " + "event_callback_counter { count: 1 attributes { event_type: 0 } } " + "event_callback_counter { count: 1 attributes { event_type: 1 } } " + "event_callback_counter { count: 1 attributes { event_type: 2 } } " + "event_callback_counter { count: 1 attributes { event_type: 3 } } " + "event_callback_counter { count: 1 attributes { event_type: 4 } } "; + + DrmFrameworkMetrics expectedMetricsProto; + ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto)); + + std::string diffString; + MessageDifferencer differ; + differ.ReportDifferencesToString(&diffString); + ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto)) + << diffString; +} + +TEST_F(MediaDrmMetricsTest, TimeMetricsProtoSerialization) { + MediaDrmMetrics metrics; + + for (status_t s : {OK, UNEXPECTED_NULL}) { + double time = 0; + for (int i = 0; i < 5; i++) { + time += 1.0; + metrics.mGetKeyRequestTimeUs.Record(time, s); + metrics.mProvideKeyResponseTimeUs.Record(time, s); + } + } + + std::string serializedMetrics; + ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics)); + + DrmFrameworkMetrics metricsProto; + ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics)); + + std::string expectedMetrics = + "get_key_request_time_us { " + " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 " + " attributes { error_code: -0x7FFFFFF8 } " + "} " + "get_key_request_time_us { " + " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 " + " attributes { error_code: 0 } " + "} " + "provide_key_response_time_us { " + " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 " + " attributes { error_code: -0x7FFFFFF8 } " + "} " + "provide_key_response_time_us { " + " min: 1 max: 5 mean: 3.5 variance: 1 operation_count: 5 " + " attributes { error_code: 0 } " + "} "; + + DrmFrameworkMetrics expectedMetricsProto; + ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto)); + + std::string diffString; + MessageDifferencer differ; + differ.ReportDifferencesToString(&diffString); + ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto)) + << diffString; +} + +TEST_F(MediaDrmMetricsTest, SessionLifetimeProtoSerialization) { + // Use the fake so the clock is predictable; + FakeMediaDrmMetrics metrics; + + android::Vector<uint8_t> sessionId1; + sessionId1.push_back(1); + sessionId1.push_back(2); + android::Vector<uint8_t> sessionId2; + sessionId2.push_back(3); + sessionId2.push_back(4); + + metrics.SetSessionStart(sessionId1); + metrics.SetSessionStart(sessionId2); + metrics.SetSessionEnd(sessionId2); + metrics.SetSessionEnd(sessionId1); + + std::string serializedMetrics; + ASSERT_EQ(OK, metrics.GetSerializedMetrics(&serializedMetrics)); + + DrmFrameworkMetrics metricsProto; + ASSERT_TRUE(metricsProto.ParseFromString(serializedMetrics)); + + std::string expectedMetrics = + "session_lifetimes: { " + " key: '0102' " + " value { start_time_ms: 0 end_time_ms: 3 } " + "} " + "session_lifetimes: { " + " key: '0304' " + " value { start_time_ms: 1 end_time_ms: 2 } " + "} "; + + DrmFrameworkMetrics expectedMetricsProto; + ASSERT_TRUE(TextFormat::MergeFromString(expectedMetrics, &expectedMetricsProto)); + + std::string diffString; + MessageDifferencer differ; + differ.ReportDifferencesToString(&diffString); + ASSERT_TRUE(differ.Compare(expectedMetricsProto, metricsProto)) + << diffString; +} + +TEST_F(MediaDrmMetricsTest, HidlToBundleMetricsEmpty) { + hidl_vec<DrmMetricGroup> hidlMetricGroups; + PersistableBundle bundleMetricGroups; + + ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidlMetricGroups, &bundleMetricGroups)); + ASSERT_EQ(0U, bundleMetricGroups.size()); +} + +TEST_F(MediaDrmMetricsTest, HidlToBundleMetricsMultiple) { + DrmMetricGroup hidlMetricGroup = + { { { + "open_session_ok", + { { "status", DrmMetricGroup::ValueType::INT64_TYPE, + (int64_t) Status::OK, 0.0, "" } }, + { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 3, 0.0, "" } } + }, + { + "close_session_not_opened", + { { "status", DrmMetricGroup::ValueType::INT64_TYPE, + (int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, 0.0, "" } }, + { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 7, 0.0, "" } } + } } }; + + PersistableBundle bundleMetricGroups; + ASSERT_EQ(OK, MediaDrmMetrics::HidlMetricsToBundle(hidl_vec<DrmMetricGroup>({hidlMetricGroup}), + &bundleMetricGroups)); + ASSERT_EQ(1U, bundleMetricGroups.size()); + PersistableBundle bundleMetricGroup; + ASSERT_TRUE(bundleMetricGroups.getPersistableBundle(String16("[0]"), &bundleMetricGroup)); + ASSERT_EQ(2U, bundleMetricGroup.size()); + + // Verify each metric. + PersistableBundle metric; + ASSERT_TRUE(bundleMetricGroup.getPersistableBundle(String16("open_session_ok"), &metric)); + PersistableBundle metricInstance; + ASSERT_TRUE(metric.getPersistableBundle(String16("[0]"), &metricInstance)); + int64_t value = 0; + ASSERT_TRUE(metricInstance.getLong(String16("count"), &value)); + ASSERT_EQ(3, value); + PersistableBundle attributeBundle; + ASSERT_TRUE(metricInstance.getPersistableBundle(String16("attributes"), &attributeBundle)); + ASSERT_TRUE(attributeBundle.getLong(String16("status"), &value)); + ASSERT_EQ((int64_t) Status::OK, value); + + ASSERT_TRUE(bundleMetricGroup.getPersistableBundle(String16("close_session_not_opened"), + &metric)); + ASSERT_TRUE(metric.getPersistableBundle(String16("[0]"), &metricInstance)); + ASSERT_TRUE(metricInstance.getLong(String16("count"), &value)); + ASSERT_EQ(7, value); + ASSERT_TRUE(metricInstance.getPersistableBundle(String16("attributes"), &attributeBundle)); + value = 0; + ASSERT_TRUE(attributeBundle.getLong(String16("status"), &value)); + ASSERT_EQ((int64_t) Status::ERROR_DRM_SESSION_NOT_OPENED, value); +} + +} // namespace android |
