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