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 "DrmMetrics" 17 #include <iomanip> 18 #include <utility> 19 20 #include <android-base/macros.h> 21 #include <media/stagefright/foundation/base64.h> 22 #include <mediadrm/DrmMetrics.h> 23 #include <sys/time.h> 24 #include <utils/Log.h> 25 #include <utils/Timers.h> 26 27 #include "protos/metrics.pb.h" 28 29 using ::android::String16; 30 using ::android::String8; 31 using ::android::drm_metrics::DrmFrameworkMetrics; 32 using ::android::hardware::hidl_string; 33 using ::android::hardware::hidl_vec; 34 using ::android::hardware::drm::V1_0::EventType; 35 using ::android::hardware::drm::V1_0::KeyStatusType; 36 using ::android::hardware::drm::V1_1::DrmMetricGroup; 37 using ::android::os::PersistableBundle; 38 39 namespace { 40 41 template <typename T> std::string GetAttributeName(T type); 42 43 template <> std::string GetAttributeName<KeyStatusType>(KeyStatusType type) { 44 static const char *type_names[] = {"USABLE", "EXPIRED", 45 "OUTPUT_NOT_ALLOWED", "STATUS_PENDING", 46 "INTERNAL_ERROR"}; 47 if (((size_t)type) > arraysize(type_names)) { 48 return "UNKNOWN_TYPE"; 49 } 50 return type_names[(size_t)type]; 51 } 52 53 template <> std::string GetAttributeName<EventType>(EventType type) { 54 static const char *type_names[] = {"PROVISION_REQUIRED", "KEY_NEEDED", 55 "KEY_EXPIRED", "VENDOR_DEFINED", 56 "SESSION_RECLAIMED"}; 57 if (((size_t)type) > arraysize(type_names)) { 58 return "UNKNOWN_TYPE"; 59 } 60 return type_names[(size_t)type]; 61 } 62 63 template <typename T> 64 void ExportCounterMetric(const android::CounterMetric<T> &counter, 65 PersistableBundle *metrics) { 66 if (!metrics) { 67 ALOGE("metrics was unexpectedly null."); 68 return; 69 } 70 std::string success_count_name = counter.metric_name() + ".ok.count"; 71 std::string error_count_name = counter.metric_name() + ".error.count"; 72 std::vector<int64_t> status_values; 73 counter.ExportValues( 74 [&](const android::status_t status, const int64_t value) { 75 if (status == android::OK) { 76 metrics->putLong(android::String16(success_count_name.c_str()), 77 value); 78 } else { 79 int64_t total_errors(0); 80 metrics->getLong(android::String16(error_count_name.c_str()), 81 &total_errors); 82 metrics->putLong(android::String16(error_count_name.c_str()), 83 total_errors + value); 84 status_values.push_back(status); 85 } 86 }); 87 if (!status_values.empty()) { 88 std::string error_list_name = counter.metric_name() + ".error.list"; 89 metrics->putLongVector(android::String16(error_list_name.c_str()), 90 status_values); 91 } 92 } 93 94 template <typename T> 95 void ExportCounterMetricWithAttributeNames( 96 const android::CounterMetric<T> &counter, PersistableBundle *metrics) { 97 if (!metrics) { 98 ALOGE("metrics was unexpectedly null."); 99 return; 100 } 101 counter.ExportValues([&](const T &attribute, const int64_t value) { 102 std::string name = counter.metric_name() + "." + 103 GetAttributeName(attribute) + ".count"; 104 metrics->putLong(android::String16(name.c_str()), value); 105 }); 106 } 107 108 template <typename T> 109 void ExportEventMetric(const android::EventMetric<T> &event, 110 PersistableBundle *metrics) { 111 if (!metrics) { 112 ALOGE("metrics was unexpectedly null."); 113 return; 114 } 115 std::string success_count_name = event.metric_name() + ".ok.count"; 116 std::string error_count_name = event.metric_name() + ".error.count"; 117 std::string timing_name = event.metric_name() + ".ok.average_time_micros"; 118 std::vector<int64_t> status_values; 119 event.ExportValues([&](const android::status_t &status, 120 const android::EventStatistics &value) { 121 if (status == android::OK) { 122 metrics->putLong(android::String16(success_count_name.c_str()), 123 value.count); 124 metrics->putLong(android::String16(timing_name.c_str()), 125 value.mean); 126 } else { 127 int64_t total_errors(0); 128 metrics->getLong(android::String16(error_count_name.c_str()), 129 &total_errors); 130 metrics->putLong(android::String16(error_count_name.c_str()), 131 total_errors + value.count); 132 status_values.push_back(status); 133 } 134 }); 135 if (!status_values.empty()) { 136 std::string error_list_name = event.metric_name() + ".error.list"; 137 metrics->putLongVector(android::String16(error_list_name.c_str()), 138 status_values); 139 } 140 } 141 142 void ExportSessionLifespans( 143 const std::map<std::string, std::pair<int64_t, int64_t>> &mSessionLifespans, 144 PersistableBundle *metrics) { 145 if (!metrics) { 146 ALOGE("metrics was unexpectedly null."); 147 return; 148 } 149 150 if (mSessionLifespans.empty()) { 151 return; 152 } 153 154 PersistableBundle startTimesBundle; 155 PersistableBundle endTimesBundle; 156 for (auto it = mSessionLifespans.begin(); it != mSessionLifespans.end(); 157 it++) { 158 String16 key(it->first.c_str(), it->first.size()); 159 startTimesBundle.putLong(key, it->second.first); 160 endTimesBundle.putLong(key, it->second.second); 161 } 162 metrics->putPersistableBundle( 163 android::String16("drm.mediadrm.session_start_times_ms"), 164 startTimesBundle); 165 metrics->putPersistableBundle( 166 android::String16("drm.mediadrm.session_end_times_ms"), endTimesBundle); 167 } 168 169 std::string ToHexString(const android::Vector<uint8_t> &sessionId) { 170 std::ostringstream out; 171 out << std::hex << std::setfill('0'); 172 for (size_t i = 0; i < sessionId.size(); i++) { 173 out << std::setw(2) << (int)(sessionId[i]); 174 } 175 return out.str(); 176 } 177 178 template <typename CT> 179 void SetValue(const String16 &name, DrmMetricGroup::ValueType type, 180 const CT &value, PersistableBundle *bundle) { 181 switch (type) { 182 case DrmMetricGroup::ValueType::INT64_TYPE: 183 bundle->putLong(name, value.int64Value); 184 break; 185 case DrmMetricGroup::ValueType::DOUBLE_TYPE: 186 bundle->putDouble(name, value.doubleValue); 187 break; 188 case DrmMetricGroup::ValueType::STRING_TYPE: 189 bundle->putString(name, String16(value.stringValue.c_str())); 190 break; 191 default: 192 ALOGE("Unexpected value type: %hhu", type); 193 } 194 } 195 196 inline String16 MakeIndexString(unsigned int index) { 197 std::string str("["); 198 str.append(std::to_string(index)); 199 str.append("]"); 200 return String16(str.c_str()); 201 } 202 203 } // namespace 204 205 namespace android { 206 207 MediaDrmMetrics::MediaDrmMetrics() 208 : mOpenSessionCounter("drm.mediadrm.open_session", "status"), 209 mCloseSessionCounter("drm.mediadrm.close_session", "status"), 210 mGetKeyRequestTimeUs("drm.mediadrm.get_key_request", "status"), 211 mProvideKeyResponseTimeUs("drm.mediadrm.provide_key_response", "status"), 212 mGetProvisionRequestCounter("drm.mediadrm.get_provision_request", 213 "status"), 214 mProvideProvisionResponseCounter( 215 "drm.mediadrm.provide_provision_response", "status"), 216 mKeyStatusChangeCounter("drm.mediadrm.key_status_change", 217 "key_status_type"), 218 mEventCounter("drm.mediadrm.event", "event_type"), 219 mGetDeviceUniqueIdCounter("drm.mediadrm.get_device_unique_id", "status") { 220 } 221 222 void MediaDrmMetrics::SetSessionStart( 223 const android::Vector<uint8_t> &sessionId) { 224 std::string sessionIdHex = ToHexString(sessionId); 225 mSessionLifespans[sessionIdHex] = 226 std::make_pair(GetCurrentTimeMs(), (int64_t)0); 227 } 228 229 void MediaDrmMetrics::SetSessionEnd(const android::Vector<uint8_t> &sessionId) { 230 std::string sessionIdHex = ToHexString(sessionId); 231 int64_t endTimeMs = GetCurrentTimeMs(); 232 if (mSessionLifespans.find(sessionIdHex) != mSessionLifespans.end()) { 233 mSessionLifespans[sessionIdHex] = 234 std::make_pair(mSessionLifespans[sessionIdHex].first, endTimeMs); 235 } else { 236 mSessionLifespans[sessionIdHex] = std::make_pair((int64_t)0, endTimeMs); 237 } 238 } 239 240 void MediaDrmMetrics::Export(PersistableBundle *metrics) { 241 if (!metrics) { 242 ALOGE("metrics was unexpectedly null."); 243 return; 244 } 245 ExportCounterMetric(mOpenSessionCounter, metrics); 246 ExportCounterMetric(mCloseSessionCounter, metrics); 247 ExportEventMetric(mGetKeyRequestTimeUs, metrics); 248 ExportEventMetric(mProvideKeyResponseTimeUs, metrics); 249 ExportCounterMetric(mGetProvisionRequestCounter, metrics); 250 ExportCounterMetric(mProvideProvisionResponseCounter, metrics); 251 ExportCounterMetricWithAttributeNames(mKeyStatusChangeCounter, metrics); 252 ExportCounterMetricWithAttributeNames(mEventCounter, metrics); 253 ExportCounterMetric(mGetDeviceUniqueIdCounter, metrics); 254 ExportSessionLifespans(mSessionLifespans, metrics); 255 } 256 257 status_t MediaDrmMetrics::GetSerializedMetrics(std::string *serializedMetrics) { 258 259 if (!serializedMetrics) { 260 ALOGE("serializedMetrics was unexpectedly null."); 261 return UNEXPECTED_NULL; 262 } 263 264 DrmFrameworkMetrics metrics; 265 266 mOpenSessionCounter.ExportValues( 267 [&](const android::status_t status, const int64_t value) { 268 DrmFrameworkMetrics::Counter *counter = 269 metrics.add_open_session_counter(); 270 counter->set_count(value); 271 counter->mutable_attributes()->set_error_code(status); 272 }); 273 274 mCloseSessionCounter.ExportValues( 275 [&](const android::status_t status, const int64_t value) { 276 DrmFrameworkMetrics::Counter *counter = 277 metrics.add_close_session_counter(); 278 counter->set_count(value); 279 counter->mutable_attributes()->set_error_code(status); 280 }); 281 282 mGetProvisionRequestCounter.ExportValues( 283 [&](const android::status_t status, const int64_t value) { 284 DrmFrameworkMetrics::Counter *counter = 285 metrics.add_get_provisioning_request_counter(); 286 counter->set_count(value); 287 counter->mutable_attributes()->set_error_code(status); 288 }); 289 290 mProvideProvisionResponseCounter.ExportValues( 291 [&](const android::status_t status, const int64_t value) { 292 DrmFrameworkMetrics::Counter *counter = 293 metrics.add_provide_provisioning_response_counter(); 294 counter->set_count(value); 295 counter->mutable_attributes()->set_error_code(status); 296 }); 297 298 mKeyStatusChangeCounter.ExportValues( 299 [&](const KeyStatusType key_status_type, const int64_t value) { 300 DrmFrameworkMetrics::Counter *counter = 301 metrics.add_key_status_change_counter(); 302 counter->set_count(value); 303 counter->mutable_attributes()->set_key_status_type( 304 (uint32_t)key_status_type); 305 }); 306 307 mEventCounter.ExportValues( 308 [&](const EventType event_type, const int64_t value) { 309 DrmFrameworkMetrics::Counter *counter = 310 metrics.add_event_callback_counter(); 311 counter->set_count(value); 312 counter->mutable_attributes()->set_event_type((uint32_t)event_type); 313 }); 314 315 mGetDeviceUniqueIdCounter.ExportValues( 316 [&](const status_t status, const int64_t value) { 317 DrmFrameworkMetrics::Counter *counter = 318 metrics.add_get_device_unique_id_counter(); 319 counter->set_count(value); 320 counter->mutable_attributes()->set_error_code(status); 321 }); 322 323 mGetKeyRequestTimeUs.ExportValues( 324 [&](const status_t status, const EventStatistics &stats) { 325 DrmFrameworkMetrics::DistributionMetric *metric = 326 metrics.add_get_key_request_time_us(); 327 metric->set_min(stats.min); 328 metric->set_max(stats.max); 329 metric->set_mean(stats.mean); 330 metric->set_operation_count(stats.count); 331 metric->set_variance(stats.sum_squared_deviation / stats.count); 332 metric->mutable_attributes()->set_error_code(status); 333 }); 334 335 mProvideKeyResponseTimeUs.ExportValues( 336 [&](const status_t status, const EventStatistics &stats) { 337 DrmFrameworkMetrics::DistributionMetric *metric = 338 metrics.add_provide_key_response_time_us(); 339 metric->set_min(stats.min); 340 metric->set_max(stats.max); 341 metric->set_mean(stats.mean); 342 metric->set_operation_count(stats.count); 343 metric->set_variance(stats.sum_squared_deviation / stats.count); 344 metric->mutable_attributes()->set_error_code(status); 345 }); 346 347 for (const auto &sessionLifespan : mSessionLifespans) { 348 auto *map = metrics.mutable_session_lifetimes(); 349 350 (*map)[sessionLifespan.first].set_start_time_ms( 351 sessionLifespan.second.first); 352 (*map)[sessionLifespan.first].set_end_time_ms( 353 sessionLifespan.second.second); 354 } 355 356 if (!metrics.SerializeToString(serializedMetrics)) { 357 ALOGE("Failed to serialize metrics."); 358 return UNKNOWN_ERROR; 359 } 360 361 return OK; 362 } 363 364 int64_t MediaDrmMetrics::GetCurrentTimeMs() { 365 struct timeval tv; 366 gettimeofday(&tv, NULL); 367 return ((int64_t)tv.tv_sec * 1000) + ((int64_t)tv.tv_usec / 1000); 368 } 369 370 status_t MediaDrmMetrics::HidlMetricsToBundle( 371 const hidl_vec<DrmMetricGroup> &hidlMetricGroups, 372 PersistableBundle *bundleMetricGroups) { 373 if (bundleMetricGroups == nullptr) { 374 return UNEXPECTED_NULL; 375 } 376 if (hidlMetricGroups.size() == 0) { 377 return OK; 378 } 379 380 int groupIndex = 0; 381 std::map<String16, int> indexMap; 382 for (const auto &hidlMetricGroup : hidlMetricGroups) { 383 PersistableBundle bundleMetricGroup; 384 for (const auto &hidlMetric : hidlMetricGroup.metrics) { 385 String16 metricName(hidlMetric.name.c_str()); 386 PersistableBundle bundleMetric; 387 // Add metric component values. 388 for (const auto &value : hidlMetric.values) { 389 SetValue(String16(value.componentName.c_str()), value.type, 390 value, &bundleMetric); 391 } 392 // Set metric attributes. 393 PersistableBundle bundleMetricAttributes; 394 for (const auto &attribute : hidlMetric.attributes) { 395 SetValue(String16(attribute.name.c_str()), attribute.type, 396 attribute, &bundleMetricAttributes); 397 } 398 // Add attributes to the bundle metric. 399 bundleMetric.putPersistableBundle(String16("attributes"), 400 bundleMetricAttributes); 401 // Add one layer of indirection, allowing for repeated metric names. 402 PersistableBundle repeatedMetrics; 403 bundleMetricGroup.getPersistableBundle(metricName, 404 &repeatedMetrics); 405 int index = indexMap[metricName]; 406 repeatedMetrics.putPersistableBundle(MakeIndexString(index), 407 bundleMetric); 408 indexMap[metricName] = ++index; 409 410 // Add the bundle metric to the group of metrics. 411 bundleMetricGroup.putPersistableBundle(metricName, 412 repeatedMetrics); 413 } 414 // Add the bundle metric group to the collection of groups. 415 bundleMetricGroups->putPersistableBundle(MakeIndexString(groupIndex++), 416 bundleMetricGroup); 417 } 418 419 return OK; 420 } 421 422 } // namespace android 423