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