blob: 03bd88a79293cbad9d45440b2afbd2f09ce6aac0 [file] [log] [blame]
Adam Stonef0e618d2018-01-17 19:20:41 -08001/*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Adam Stonefb679e32018-02-07 10:25:48 -080016#define LOG_TAG "DrmMetrics"
17#include <iomanip>
Adam Stone568b3c42018-01-31 12:57:16 -080018#include <utility>
19
Adam Stonecea91ce2018-01-22 19:23:28 -080020#include <android-base/macros.h>
Adam Stonef0e618d2018-01-17 19:20:41 -080021#include <media/DrmMetrics.h>
Adam Stone568b3c42018-01-31 12:57:16 -080022#include <media/stagefright/foundation/base64.h>
23#include <sys/time.h>
Adam Stonefb679e32018-02-07 10:25:48 -080024#include <utils/Log.h>
Adam Stone568b3c42018-01-31 12:57:16 -080025#include <utils/Timers.h>
Adam Stonef0e618d2018-01-17 19:20:41 -080026
Adam Stonefb679e32018-02-07 10:25:48 -080027#include "protos/metrics.pb.h"
28
29using ::android::String16;
30using ::android::String8;
31using ::android::drm_metrics::DrmFrameworkMetrics;
Adam Stonecea91ce2018-01-22 19:23:28 -080032using ::android::hardware::drm::V1_0::EventType;
33using ::android::hardware::drm::V1_0::KeyStatusType;
Adam Stone637b7852018-01-30 12:09:36 -080034using ::android::os::PersistableBundle;
Adam Stonecea91ce2018-01-22 19:23:28 -080035
Adam Stonef0e618d2018-01-17 19:20:41 -080036namespace {
37
Adam Stone568b3c42018-01-31 12:57:16 -080038template <typename T> std::string GetAttributeName(T type);
Adam Stonecea91ce2018-01-22 19:23:28 -080039
Adam Stone568b3c42018-01-31 12:57:16 -080040template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
41 static const char *type_names[] = {"USABLE", "EXPIRED",
42 "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
43 "INTERNAL_ERROR"};
44 if (((size_t)type) > arraysize(type_names)) {
45 return "UNKNOWN_TYPE";
46 }
47 return type_names[(size_t)type];
Adam Stonecea91ce2018-01-22 19:23:28 -080048}
49
Adam Stone568b3c42018-01-31 12:57:16 -080050template <> std::string GetAttributeName<EventType>(EventType type) {
51 static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
52 "KEY_EXPIRED", "VENDOR_DEFINED",
53 "SESSION_RECLAIMED"};
54 if (((size_t)type) > arraysize(type_names)) {
55 return "UNKNOWN_TYPE";
56 }
57 return type_names[(size_t)type];
Adam Stonecea91ce2018-01-22 19:23:28 -080058}
59
Adam Stone568b3c42018-01-31 12:57:16 -080060template <typename T>
61void ExportCounterMetric(const android::CounterMetric<T> &counter,
62 PersistableBundle *metrics) {
63 if (!metrics) {
64 ALOGE("metrics was unexpectedly null.");
65 return;
66 }
67 std::string success_count_name = counter.metric_name() + ".ok.count";
68 std::string error_count_name = counter.metric_name() + ".error.count";
69 std::vector<int64_t> status_values;
70 counter.ExportValues(
71 [&](const android::status_t status, const int64_t value) {
72 if (status == android::OK) {
73 metrics->putLong(android::String16(success_count_name.c_str()),
74 value);
75 } else {
76 int64_t total_errors(0);
77 metrics->getLong(android::String16(error_count_name.c_str()),
78 &total_errors);
79 metrics->putLong(android::String16(error_count_name.c_str()),
80 total_errors + value);
81 status_values.push_back(status);
82 }
83 });
84 if (!status_values.empty()) {
85 std::string error_list_name = counter.metric_name() + ".error.list";
86 metrics->putLongVector(android::String16(error_list_name.c_str()),
87 status_values);
88 }
Adam Stonef0e618d2018-01-17 19:20:41 -080089}
90
Adam Stone568b3c42018-01-31 12:57:16 -080091template <typename T>
Adam Stonecea91ce2018-01-22 19:23:28 -080092void ExportCounterMetricWithAttributeNames(
Adam Stone568b3c42018-01-31 12:57:16 -080093 const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
94 if (!metrics) {
95 ALOGE("metrics was unexpectedly null.");
96 return;
97 }
98 counter.ExportValues([&](const T &attribute, const int64_t value) {
99 std::string name = counter.metric_name() + "." +
100 GetAttributeName(attribute) + ".count";
101 metrics->putLong(android::String16(name.c_str()), value);
102 });
Adam Stonecea91ce2018-01-22 19:23:28 -0800103}
104
Adam Stone568b3c42018-01-31 12:57:16 -0800105template <typename T>
106void ExportEventMetric(const android::EventMetric<T> &event,
107 PersistableBundle *metrics) {
108 if (!metrics) {
109 ALOGE("metrics was unexpectedly null.");
110 return;
111 }
112 std::string success_count_name = event.metric_name() + ".ok.count";
113 std::string error_count_name = event.metric_name() + ".error.count";
114 std::string timing_name = event.metric_name() + ".ok.average_time_micros";
115 std::vector<int64_t> status_values;
116 event.ExportValues([&](const android::status_t &status,
117 const android::EventStatistics &value) {
118 if (status == android::OK) {
119 metrics->putLong(android::String16(success_count_name.c_str()),
120 value.count);
121 metrics->putLong(android::String16(timing_name.c_str()),
122 value.mean);
123 } else {
124 int64_t total_errors(0);
125 metrics->getLong(android::String16(error_count_name.c_str()),
126 &total_errors);
127 metrics->putLong(android::String16(error_count_name.c_str()),
128 total_errors + value.count);
129 status_values.push_back(status);
130 }
131 });
132 if (!status_values.empty()) {
133 std::string error_list_name = event.metric_name() + ".error.list";
134 metrics->putLongVector(android::String16(error_list_name.c_str()),
135 status_values);
136 }
Adam Stonef0e618d2018-01-17 19:20:41 -0800137}
138
Adam Stone568b3c42018-01-31 12:57:16 -0800139void ExportSessionLifespans(
Adam Stonefb679e32018-02-07 10:25:48 -0800140 const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans,
Adam Stone568b3c42018-01-31 12:57:16 -0800141 PersistableBundle *metrics) {
142 if (!metrics) {
143 ALOGE("metrics was unexpectedly null.");
144 return;
145 }
146
147 if (mSessionLifespans.empty()) {
148 return;
149 }
150
151 PersistableBundle startTimesBundle;
152 PersistableBundle endTimesBundle;
153 for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end();
154 it++) {
Adam Stonefb679e32018-02-07 10:25:48 -0800155 String16 key(it->first.c_str(), it->first.size());
156 startTimesBundle.putLong(key, it->second.first);
157 endTimesBundle.putLong(key, it->second.second);
Adam Stone568b3c42018-01-31 12:57:16 -0800158 }
159 metrics->putPersistableBundle(
160 android::String16("drm.mediadrm.session_start_times_ms"),
161 startTimesBundle);
162 metrics->putPersistableBundle(
163 android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
164}
165
Adam Stonefb679e32018-02-07 10:25:48 -0800166std::string ToHexString(const android::Vector<uint8_t> &sessionId) {
167 std::ostringstream out;
168 out << std::hex << std::setfill('0');
Adam Stone568b3c42018-01-31 12:57:16 -0800169 for (size_t i = 0; i < sessionId.size(); i++) {
Adam Stonefb679e32018-02-07 10:25:48 -0800170 out << std::setw(2) << (int)(sessionId[i]);
Adam Stone568b3c42018-01-31 12:57:16 -0800171 }
Adam Stonefb679e32018-02-07 10:25:48 -0800172 return out.str();
Adam Stone568b3c42018-01-31 12:57:16 -0800173}
174
175} // namespace
Adam Stonef0e618d2018-01-17 19:20:41 -0800176
177namespace android {
178
179MediaDrmMetrics::MediaDrmMetrics()
Adam Stone4bea53c2018-01-24 21:44:58 -0800180 : mOpenSessionCounter("drm.mediadrm.open_session", "status"),
181 mCloseSessionCounter("drm.mediadrm.close_session", "status"),
Adam Stonefb679e32018-02-07 10:25:48 -0800182 mGetKeyRequestTimeUs("drm.mediadrm.get_key_request", "status"),
183 mProvideKeyResponseTimeUs("drm.mediadrm.provide_key_response", "status"),
Adam Stone568b3c42018-01-31 12:57:16 -0800184 mGetProvisionRequestCounter("drm.mediadrm.get_provision_request",
185 "status"),
Adam Stonecea91ce2018-01-22 19:23:28 -0800186 mProvideProvisionResponseCounter(
Adam Stone4bea53c2018-01-24 21:44:58 -0800187 "drm.mediadrm.provide_provision_response", "status"),
Adam Stone568b3c42018-01-31 12:57:16 -0800188 mKeyStatusChangeCounter("drm.mediadrm.key_status_change",
189 "key_status_type"),
Adam Stone4bea53c2018-01-24 21:44:58 -0800190 mEventCounter("drm.mediadrm.event", "event_type"),
Adam Stone568b3c42018-01-31 12:57:16 -0800191 mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") {
Adam Stonef0e618d2018-01-17 19:20:41 -0800192}
193
Adam Stone568b3c42018-01-31 12:57:16 -0800194void MediaDrmMetrics::SetSessionStart(
195 const android::Vector<uint8_t> &sessionId) {
Adam Stonefb679e32018-02-07 10:25:48 -0800196 std::string sessionIdHex = ToHexString(sessionId);
Adam Stone568b3c42018-01-31 12:57:16 -0800197 mSessionLifespans[sessionIdHex] =
Adam Stonefb679e32018-02-07 10:25:48 -0800198 std::make_pair(GetCurrentTimeMs(), (int64_t)0);
Adam Stonef0e618d2018-01-17 19:20:41 -0800199}
200
Adam Stone568b3c42018-01-31 12:57:16 -0800201void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) {
Adam Stonefb679e32018-02-07 10:25:48 -0800202 std::string sessionIdHex = ToHexString(sessionId);
203 int64_t endTimeMs = GetCurrentTimeMs();
Adam Stone568b3c42018-01-31 12:57:16 -0800204 if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) {
205 mSessionLifespans[sessionIdHex] =
206 std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs);
207 } else {
208 mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs);
209 }
210}
211
212void MediaDrmMetrics::Export(PersistableBundle *metrics) {
213 if (!metrics) {
214 ALOGE("metrics was unexpectedly null.");
215 return;
216 }
217 ExportCounterMetric(mOpenSessionCounter, metrics);
218 ExportCounterMetric(mCloseSessionCounter, metrics);
Adam Stonefb679e32018-02-07 10:25:48 -0800219 ExportEventMetric(mGetKeyRequestTimeUs, metrics);
220 ExportEventMetric(mProvideKeyResponseTimeUs, metrics);
Adam Stone568b3c42018-01-31 12:57:16 -0800221 ExportCounterMetric(mGetProvisionRequestCounter, metrics);
222 ExportCounterMetric(mProvideProvisionResponseCounter, metrics);
223 ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics);
224 ExportCounterMetricWithAttributeNames(mEventCounter, metrics);
225 ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics);
226 ExportSessionLifespans(mSessionLifespans, metrics);
227}
228
Adam Stonefb679e32018-02-07 10:25:48 -0800229status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) {
230
231 if (!serializedMetrics) {
232 ALOGE("serializedMetrics was unexpectedly null.");
233 return UNEXPECTED_NULL;
234 }
235
236 DrmFrameworkMetrics metrics;
237
238 mOpenSessionCounter.ExportValues(
239 [&](const android::status_t status, const int64_t value) {
240 DrmFrameworkMetrics::Counter *counter =
241 metrics.add_open_session_counter();
242 counter->set_count(value);
243 counter->mutable_attributes()->set_error_code(status);
244 });
245
246 mCloseSessionCounter.ExportValues(
247 [&](const android::status_t status, const int64_t value) {
248 DrmFrameworkMetrics::Counter *counter =
249 metrics.add_close_session_counter();
250 counter->set_count(value);
251 counter->mutable_attributes()->set_error_code(status);
252 });
253
254 mGetProvisionRequestCounter.ExportValues(
255 [&](const android::status_t status, const int64_t value) {
256 DrmFrameworkMetrics::Counter *counter =
257 metrics.add_get_provisioning_request_counter();
258 counter->set_count(value);
259 counter->mutable_attributes()->set_error_code(status);
260 });
261
262 mProvideProvisionResponseCounter.ExportValues(
263 [&](const android::status_t status, const int64_t value) {
264 DrmFrameworkMetrics::Counter *counter =
265 metrics.add_provide_provisioning_response_counter();
266 counter->set_count(value);
267 counter->mutable_attributes()->set_error_code(status);
268 });
269
270 mKeyStatusChangeCounter.ExportValues(
271 [&](const KeyStatusType key_status_type, const int64_t value) {
272 DrmFrameworkMetrics::Counter *counter =
273 metrics.add_key_status_change_counter();
274 counter->set_count(value);
275 counter->mutable_attributes()->set_key_status_type(
276 (uint32_t)key_status_type);
277 });
278
279 mEventCounter.ExportValues(
280 [&](const EventType event_type, const int64_t value) {
281 DrmFrameworkMetrics::Counter *counter =
282 metrics.add_event_callback_counter();
283 counter->set_count(value);
284 counter->mutable_attributes()->set_event_type((uint32_t)event_type);
285 });
286
287 mGetDeviceUniqueIdCounter.ExportValues(
288 [&](const status_t status, const int64_t value) {
289 DrmFrameworkMetrics::Counter *counter =
290 metrics.add_get_device_unique_id_counter();
291 counter->set_count(value);
292 counter->mutable_attributes()->set_error_code(status);
293 });
294
295 mGetKeyRequestTimeUs.ExportValues(
296 [&](const status_t status, const EventStatistics &stats) {
297 DrmFrameworkMetrics::DistributionMetric *metric =
298 metrics.add_get_key_request_time_us();
299 metric->set_min(stats.min);
300 metric->set_max(stats.max);
301 metric->set_mean(stats.mean);
302 metric->set_operation_count(stats.count);
303 metric->set_variance(stats.sum_squared_deviation / stats.count);
304 metric->mutable_attributes()->set_error_code(status);
305 });
306
307 mProvideKeyResponseTimeUs.ExportValues(
308 [&](const status_t status, const EventStatistics &stats) {
309 DrmFrameworkMetrics::DistributionMetric *metric =
310 metrics.add_provide_key_response_time_us();
311 metric->set_min(stats.min);
312 metric->set_max(stats.max);
313 metric->set_mean(stats.mean);
314 metric->set_operation_count(stats.count);
315 metric->set_variance(stats.sum_squared_deviation / stats.count);
316 metric->mutable_attributes()->set_error_code(status);
317 });
318
319 for (const auto &sessionLifespan : mSessionLifespans) {
320 auto *map = metrics.mutable_session_lifetimes();
321
322 (*map)[sessionLifespan.first].set_start_time_ms(
323 sessionLifespan.second.first);
324 (*map)[sessionLifespan.first].set_end_time_ms(
325 sessionLifespan.second.second);
326 }
327
328 if (!metrics.SerializeToString(serializedMetrics)) {
329 ALOGE("Failed to serialize metrics.");
330 return UNKNOWN_ERROR;
331 }
332
333 return OK;
334}
335
336int64_t MediaDrmMetrics::GetCurrentTimeMs() {
337 struct timeval tv;
338 gettimeofday(&tv, NULL);
339 return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000);
340}
341
Adam Stone568b3c42018-01-31 12:57:16 -0800342} // namespace android