// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine Master // License Agreement. // // Format mediadrm framework protobuf metrics #include #include #include #include #include #include #include "mediadrm_metrics.pb.h" namespace mediadrm_metrics { using namespace android::drm_metrics; using std::string; using std::to_string; const string kIndentPerLine = " "; string FormatAttributes(const DrmFrameworkMetrics::Attributes& attributes) { string result; if (attributes.has_error_code()) { result.append("error_code:"); result.append(to_string(attributes.error_code())); } if (attributes.has_key_status_type()) { if (result.size()) result.append(","); result.append("key_status_type:"); result.append(to_string(attributes.key_status_type())); } if (attributes.has_event_type()) { if (result.size()) result.append(","); result.append("event_type:"); result.append(to_string(attributes.event_type())); } if (result.size()) { return string(" {") + result + "}"; } else { return ""; } } string FormatCounter(const DrmFrameworkMetrics::Counter& cm) { string result; if (cm.has_count()) { result = string("count=") + to_string(cm.count()); if (cm.has_attributes()) { result.append(FormatAttributes(cm.attributes())); } } return result; } string FormatDistributionMetric( const DrmFrameworkMetrics::DistributionMetric& dm) { string result; if (dm.has_operation_count()) { if (dm.operation_count() == 1) { if (dm.has_mean()) { std::ostringstream buffer; buffer << dm.mean(); result += string("mean=") + buffer.str(); } } else { if (dm.has_min()) { std::ostringstream buffer; buffer << dm.min(); result = string("min=") + buffer.str(); } if (dm.has_max()) { std::ostringstream buffer; buffer << dm.max(); if (result.size()) result.append(" "); result += string("max=") + buffer.str(); } if (dm.has_mean()) { std::ostringstream buffer; buffer << dm.mean(); if (result.size()) result.append(" "); result += string("mean=") + buffer.str(); } if (dm.has_variance()) { std::ostringstream buffer; buffer << dm.variance(); if (result.size()) result.append(" "); result += string("variance=") + buffer.str(); } if (dm.has_operation_count()) { if (result.size()) result.append(" "); result += string("count=") + to_string(dm.operation_count()); } } if (dm.has_attributes()) { result.append(FormatAttributes(dm.attributes())); } } return result; } #define FORMAT_REPEATED_DISTRIBUTION(NAME, INDENT) \ if (metrics.NAME##_size() == 1) { \ result.append(INDENT + #NAME + ": "); \ result.append(FormatDistributionMetric(metrics.NAME(0)) + "\n"); \ } else { \ for (int i = 0; i < metrics.NAME##_size(); i++) { \ result.append(INDENT + #NAME "[" + to_string(i) + "]: "); \ result.append(FormatDistributionMetric(metrics.NAME(i)) + "\n"); \ } \ } #define FORMAT_REPEATED_COUNTER(NAME, INDENT) \ if (metrics.NAME##_size() == 1) { \ result.append(INDENT + #NAME ": "); \ result.append(FormatCounter(metrics.NAME(0)) + "\n"); \ } else { \ for (int i = 0; i < metrics.NAME##_size(); i++) { \ result.append(INDENT + #NAME "[" + to_string(i) + "]: "); \ result.append(FormatCounter(metrics.NAME(i)) + "\n"); \ } \ } uint8_t hex2bin(char c) { return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10; } string hexdecode(string encoded) { string result; for (size_t i = 0; i < encoded.size(); i += 2) { char c = hex2bin(encoded[i]) << 4 | hex2bin(encoded[i + 1]); result += c; } return result; } string ms_to_seconds(uint64_t time_ms) { uint64_t time_s = time_ms / 1000; uint64_t ms = time_ms - time_s * 1000; return to_string(time_s) + "." + to_string(ms); } void FormatDrmFrameworkMetrics(const DrmFrameworkMetrics& metrics, string& result) { string indent = kIndentPerLine; result.append("mediadrm_metrics\n"); FORMAT_REPEATED_COUNTER(open_session_counter, indent); FORMAT_REPEATED_COUNTER(close_session_counter, indent); FORMAT_REPEATED_DISTRIBUTION(get_key_request_time_us, indent); FORMAT_REPEATED_DISTRIBUTION(provide_key_response_time_us, indent); FORMAT_REPEATED_COUNTER(get_provisioning_request_counter, indent); FORMAT_REPEATED_COUNTER(provide_provisioning_response_counter, indent); FORMAT_REPEATED_COUNTER(key_status_change_counter, indent); FORMAT_REPEATED_COUNTER(event_callback_counter, indent); FORMAT_REPEATED_COUNTER(get_device_unique_id_counter, indent); size_t i = 0; for (auto const& entry : metrics.session_lifetimes()) { DrmFrameworkMetrics_SessionLifetime lifetime = entry.second; if (lifetime.has_start_time_ms() && lifetime.has_end_time_ms()) { result += indent + "session[" + to_string(++i) + "]: \"" + hexdecode(entry.first) + "\""; result += string(" start: ") + ms_to_seconds(lifetime.start_time_ms()) + " sec"; result += string(" duration: ") + to_string(lifetime.end_time_ms() - lifetime.start_time_ms()) + " ms\n"; } } } }; // namespace mediadrm_metrics