1 /*
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 */
16 #define LOG_TAG "DrmMetricsConsumer"
17
18 #include <android-base/macros.h>
19 #include <mediadrm/DrmMetricsConsumer.h>
20 #include <mediadrm/DrmMetrics.h>
21 #include <utils/String8.h>
22 #include <utils/String16.h>
23
24 using ::android::String16;
25 using ::android::String8;
26 using ::android::hardware::hidl_string;
27 using ::android::hardware::hidl_vec;
28 using ::android::hardware::drm::V1_0::EventType;
29 using ::android::hardware::drm::V1_2::KeyStatusType;
30 using ::android::hardware::drm::V1_1::DrmMetricGroup;
31 using ::android::os::PersistableBundle;
32
33 namespace {
34
35 template <typename T> std::string GetAttributeName(T type);
36
GetAttributeName(KeyStatusType type)37 template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) {
38 static const char *type_names[] = {"USABLE", "EXPIRED",
39 "OUTPUT_NOT_ALLOWED", "STATUS_PENDING",
40 "INTERNAL_ERROR"};
41 if (((size_t)type) > arraysize(type_names)) {
42 return "UNKNOWN_TYPE";
43 }
44 return type_names[(size_t)type];
45 }
46
GetAttributeName(EventType type)47 template <> std::string GetAttributeName<EventType>(EventType type) {
48 static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED",
49 "KEY_EXPIRED", "VENDOR_DEFINED",
50 "SESSION_RECLAIMED"};
51 if (((size_t)type) > arraysize(type_names)) {
52 return "UNKNOWN_TYPE";
53 }
54 return type_names[(size_t)type];
55 }
56
57 template <typename T>
ExportCounterMetric(const android::CounterMetric<T> & counter,PersistableBundle * metrics)58 void ExportCounterMetric(const android::CounterMetric<T> &counter,
59 PersistableBundle *metrics) {
60 if (!metrics) {
61 ALOGE("metrics was unexpectedly null.");
62 return;
63 }
64 std::string success_count_name = counter.metric_name() + ".ok.count";
65 std::string error_count_name = counter.metric_name() + ".error.count";
66 std::vector<int64_t> status_values;
67 counter.ExportValues(
68 [&](const android::status_t status, const int64_t value) {
69 if (status == android::OK) {
70 metrics->putLong(android::String16(success_count_name.c_str()),
71 value);
72 } else {
73 int64_t total_errors(0);
74 metrics->getLong(android::String16(error_count_name.c_str()),
75 &total_errors);
76 metrics->putLong(android::String16(error_count_name.c_str()),
77 total_errors + value);
78 status_values.push_back(status);
79 }
80 });
81 if (!status_values.empty()) {
82 std::string error_list_name = counter.metric_name() + ".error.list";
83 metrics->putLongVector(android::String16(error_list_name.c_str()),
84 status_values);
85 }
86 }
87
88 template <typename T>
ExportCounterMetricWithAttributeNames(const android::CounterMetric<T> & counter,PersistableBundle * metrics)89 void ExportCounterMetricWithAttributeNames(
90 const android::CounterMetric<T> &counter, PersistableBundle *metrics) {
91 if (!metrics) {
92 ALOGE("metrics was unexpectedly null.");
93 return;
94 }
95 counter.ExportValues([&](const T &attribute, const int64_t value) {
96 std::string name = counter.metric_name() + "." +
97 GetAttributeName(attribute) + ".count";
98 metrics->putLong(android::String16(name.c_str()), value);
99 });
100 }
101
102 template <typename T>
ExportEventMetric(const android::EventMetric<T> & event,PersistableBundle * metrics)103 void ExportEventMetric(const android::EventMetric<T> &event,
104 PersistableBundle *metrics) {
105 if (!metrics) {
106 ALOGE("metrics was unexpectedly null.");
107 return;
108 }
109 std::string success_count_name = event.metric_name() + ".ok.count";
110 std::string error_count_name = event.metric_name() + ".error.count";
111 std::string timing_name = event.metric_name() + ".ok.average_time_micros";
112 std::vector<int64_t> status_values;
113 event.ExportValues([&](const android::status_t &status,
114 const android::EventStatistics &value) {
115 if (status == android::OK) {
116 metrics->putLong(android::String16(success_count_name.c_str()),
117 value.count);
118 metrics->putLong(android::String16(timing_name.c_str()),
119 value.mean);
120 } else {
121 int64_t total_errors(0);
122 metrics->getLong(android::String16(error_count_name.c_str()),
123 &total_errors);
124 metrics->putLong(android::String16(error_count_name.c_str()),
125 total_errors + value.count);
126 status_values.push_back(status);
127 }
128 });
129 if (!status_values.empty()) {
130 std::string error_list_name = event.metric_name() + ".error.list";
131 metrics->putLongVector(android::String16(error_list_name.c_str()),
132 status_values);
133 }
134 }
135
ExportSessionLifespans(const std::map<std::string,std::pair<int64_t,int64_t>> & sessionLifespans,PersistableBundle * metrics)136 void ExportSessionLifespans(
137 const std::map<std::string, std::pair<int64_t, int64_t>> &sessionLifespans,
138 PersistableBundle *metrics) {
139 if (!metrics) {
140 ALOGE("metrics was unexpectedly null.");
141 return;
142 }
143
144 if (sessionLifespans.empty()) {
145 return;
146 }
147
148 PersistableBundle startTimesBundle;
149 PersistableBundle endTimesBundle;
150 for (auto it = sessionLifespans.begin(); it != sessionLifespans.end();
151 it++) {
152 String16 key(it->first.c_str(), it->first.size());
153 startTimesBundle.putLong(key, it->second.first);
154 endTimesBundle.putLong(key, it->second.second);
155 }
156 metrics->putPersistableBundle(
157 android::String16("drm.mediadrm.session_start_times_ms"),
158 startTimesBundle);
159 metrics->putPersistableBundle(
160 android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle);
161 }
162
163 template <typename CT>
SetValue(const String16 & name,DrmMetricGroup::ValueType type,const CT & value,PersistableBundle * bundle)164 void SetValue(const String16 &name, DrmMetricGroup::ValueType type,
165 const CT &value, PersistableBundle *bundle) {
166 switch (type) {
167 case DrmMetricGroup::ValueType::INT64_TYPE:
168 bundle->putLong(name, value.int64Value);
169 break;
170 case DrmMetricGroup::ValueType::DOUBLE_TYPE:
171 bundle->putDouble(name, value.doubleValue);
172 break;
173 case DrmMetricGroup::ValueType::STRING_TYPE:
174 bundle->putString(name, String16(value.stringValue.c_str()));
175 break;
176 default:
177 ALOGE("Unexpected value type: %hhu", type);
178 }
179 }
180
MakeIndexString(unsigned int index)181 inline String16 MakeIndexString(unsigned int index) {
182 std::string str("[");
183 str.append(std::to_string(index));
184 str.append("]");
185 return String16(str.c_str());
186 }
187
188 } // namespace
189
190 namespace android {
191
consumeFrameworkMetrics(const MediaDrmMetrics & metrics)192 status_t DrmMetricsConsumer::consumeFrameworkMetrics(const MediaDrmMetrics &metrics) {
193 ExportCounterMetric(metrics.mOpenSessionCounter, mBundle);
194 ExportCounterMetric(metrics.mCloseSessionCounter, mBundle);
195 ExportEventMetric(metrics.mGetKeyRequestTimeUs, mBundle);
196 ExportEventMetric(metrics.mProvideKeyResponseTimeUs, mBundle);
197 ExportCounterMetric(metrics.mGetProvisionRequestCounter, mBundle);
198 ExportCounterMetric(metrics.mProvideProvisionResponseCounter, mBundle);
199 ExportCounterMetricWithAttributeNames(metrics.mKeyStatusChangeCounter, mBundle);
200 ExportCounterMetricWithAttributeNames(metrics.mEventCounter, mBundle);
201 ExportCounterMetric(metrics.mGetDeviceUniqueIdCounter, mBundle);
202 ExportSessionLifespans(metrics.GetSessionLifespans(), mBundle);
203 return android::OK;
204 }
205
consumeHidlMetrics(const String8 & vendor,const hidl_vec<DrmMetricGroup> & pluginMetrics)206 status_t DrmMetricsConsumer::consumeHidlMetrics(
207 const String8 &vendor,
208 const hidl_vec<DrmMetricGroup> &pluginMetrics) {
209 PersistableBundle pluginBundle;
210 if (DrmMetricsConsumer::HidlMetricsToBundle(
211 pluginMetrics, &pluginBundle) == OK) {
212 mBundle->putPersistableBundle(String16(vendor), pluginBundle);
213 }
214 return android::OK;
215 }
216
HidlMetricsToBundle(const hidl_vec<DrmMetricGroup> & hidlMetricGroups,PersistableBundle * bundleMetricGroups)217 status_t DrmMetricsConsumer::HidlMetricsToBundle(
218 const hidl_vec<DrmMetricGroup> &hidlMetricGroups,
219 PersistableBundle *bundleMetricGroups) {
220 if (bundleMetricGroups == nullptr) {
221 return UNEXPECTED_NULL;
222 }
223 if (hidlMetricGroups.size() == 0) {
224 return OK;
225 }
226
227 int groupIndex = 0;
228 std::map<String16, int> indexMap;
229 for (const auto &hidlMetricGroup : hidlMetricGroups) {
230 PersistableBundle bundleMetricGroup;
231 for (const auto &hidlMetric : hidlMetricGroup.metrics) {
232 String16 metricName(hidlMetric.name.c_str());
233 PersistableBundle bundleMetric;
234 // Add metric component values.
235 for (const auto &value : hidlMetric.values) {
236 SetValue(String16(value.componentName.c_str()), value.type,
237 value, &bundleMetric);
238 }
239 // Set metric attributes.
240 PersistableBundle bundleMetricAttributes;
241 for (const auto &attribute : hidlMetric.attributes) {
242 SetValue(String16(attribute.name.c_str()), attribute.type,
243 attribute, &bundleMetricAttributes);
244 }
245 // Add attributes to the bundle metric.
246 bundleMetric.putPersistableBundle(String16("attributes"),
247 bundleMetricAttributes);
248 // Add one layer of indirection, allowing for repeated metric names.
249 PersistableBundle repeatedMetrics;
250 bundleMetricGroup.getPersistableBundle(metricName,
251 &repeatedMetrics);
252 int index = indexMap[metricName];
253 repeatedMetrics.putPersistableBundle(MakeIndexString(index),
254 bundleMetric);
255 indexMap[metricName] = ++index;
256
257 // Add the bundle metric to the group of metrics.
258 bundleMetricGroup.putPersistableBundle(metricName,
259 repeatedMetrics);
260 }
261 // Add the bundle metric group to the collection of groups.
262 bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++),
263 bundleMetricGroup);
264 }
265
266 return OK;
267 }
268
269 } // namespace android
270
271