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