// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. // // Format metric output from |adb shell dumpsys media.metrics| #include #include #include #include #include "base64decode.h" #include "mediadrm_metrics.h" #include "parse_metrics.h" #include "wv_metrics.h" namespace metrics_dump { using namespace base64; using namespace wv_metrics; using std::cerr; using std::cout; using std::endl; using std::string; using std::vector; string selected_one; std::vector excluded_ones; // Look for metrics pattern // q-metrics: // [:item:item:] // r-metrics: // {item, (item), (item)} // // @return true if metrics is formatted prior to R release bool is_q_metrics(const string &line) { int left_brackets = std::count(line.begin(), line.end(), '['); int right_brackets = std::count(line.begin(), line.end(), ']'); return (left_brackets == 1 && right_brackets == 1 && line.find('(') == string::npos && line.find(')') == string::npos); } // Process one line of metrics void process_one_metric(const string &line) { std::istringstream fields(line); MediaMetrics metrics; parse_metrics(line, &metrics); // handle specific package and component selection if (selected_one.size() && metrics.package != selected_one && metrics.component != selected_one) { return; } if (std::find(excluded_ones.begin(), excluded_ones.end(), metrics.package) != excluded_ones.end()) { return; } if (std::find(excluded_ones.begin(), excluded_ones.end(), metrics.component) != excluded_ones.end()) { return; } cout << "====================================================================" "=============" << endl; if (is_q_metrics(line)) { char timebuf[128]; time_t time_s = stoll(metrics.timestamp) / 1000000000LL; strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S", localtime(&time_s)); cout << timebuf << " timestamp: " << time_s << endl << endl; } else { cout << metrics.timestamp << endl << endl; } cout << " " << "APK PACKAGE -> METRICS COMPONENT" << endl; cout << " " << metrics.package << " -> " << metrics.component << endl; cout << "\tuid:" << metrics.uid << " pid:" << metrics.pid << endl; for (auto property : metrics.properties) { string key = property.first; string value = property.second; if (key == "serialized_metrics") { string decoded = Base64::Decode(value); if (metrics.component == "drm.vendor.google.widevinecdm") { drm_metrics::WvCdmMetrics wv_metrics; if (!wv_metrics.ParseFromString(decoded)) { cerr << "failed to parse proto string" << endl; } else { string result; FormatWvCdmMetrics(wv_metrics, result); cout << endl << result << endl; } } else { android::drm_metrics::DrmFrameworkMetrics fw_metrics; if (!fw_metrics.ParseFromString(decoded)) { cerr << "failed to parse proto string" << endl; } else { string result; mediadrm_metrics::FormatDrmFrameworkMetrics(fw_metrics, result); cout << endl << result << endl; } } } else { cout << " " << key << ": " << value << endl; } } } void process_metrics(std::istream &instream) { string line; while (std::getline(instream, line)) { if (line.find("serialized_metrics") != string::npos) { process_one_metric(line); } } } } // namespace metrics_dump using std::cerr; using std::endl; using std::string; void exit_with_menu() { cerr << "usage: metrics_dump [options] []" << endl; cerr << endl; cerr << "Displays the drm metrics that are generated by" << endl; cerr << "adb shell dumpsys media.metrics. Input may be from a file" << endl; cerr << "such as a bugreport, or from stdin." << endl; cerr << endl; cerr << "options:" << endl; cerr << " --no-gms" << endl; cerr << " ignore metrics from package com.google.android.gms" << endl; cerr << " which are generated frequently by droidguard" << endl; cerr << " --widevine" << endl; cerr << " show only widevine metrics, " "component=drm.vendor.Google.WidevineCDM" << endl; cerr << " --mediadrm" << endl; cerr << " show only framework drm metrics, component=mediadrm" << endl; cerr << " --exclude |" << endl; cerr << " ignore metrics from the specified package or component" << endl; cerr << " --select |" << endl; cerr << " only show metrics from the specified package or component" << endl; exit(0); } int main(int argc, char **argv) { // Verify that the version of the library that we linked against is // compatible with the version of the headers we compiled against. GOOGLE_PROTOBUF_VERIFY_VERSION; int i = 1; if (argc == 1) exit_with_menu(); while (i < argc) { string arg = argv[i]; if (arg == "--help") { exit_with_menu(); } else if (arg == "--no-gms") { metrics_dump::excluded_ones.push_back("com.google.android.gms"); } else if (arg == "--widevine") { metrics_dump::selected_one = "drm.vendor.google.widevinecdm"; } else if (arg == "--mediadrm") { metrics_dump::selected_one = "mediadrm"; } else if (i == argc - 1) { std::ifstream bugfile(argv[i]); if (bugfile.is_open()) { metrics_dump::process_metrics(bugfile); bugfile.close(); } else { cerr << "unable to open input file " << argv[i] << endl; } break; } else { // args with a parameter if (arg == "--exclude") { string lowercase_argv = argv[++i]; metrics_dump::to_lower(lowercase_argv); metrics_dump::excluded_ones.push_back(lowercase_argv); } else if (arg == "--select") { metrics_dump::selected_one = argv[++i]; metrics_dump::to_lower(metrics_dump::selected_one); } else { exit_with_menu(); } } i++; } if (i == argc) { metrics_dump::process_metrics(std::cin); } return 0; }