// Copyright 2020 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 "parse_metrics.h" #include #include #include #include #include #include namespace metrics_dump { using std::string; using std::vector; void to_lower(string& lower) { std::transform(lower.begin(), lower.end(), lower.begin(), ::tolower); } void parse_metrics(const string& line, MediaMetrics* metrics) { string regex_delimiters; bool is_r_metrics = is_q_metrics(line) == false; int properties_index = 0; if (is_r_metrics) { // Format of mediadrm metrics (R and forward): // index: {key, (timestamp), (package, pid, uid), (properties, ...)} // properties in this format: (key=value, key=value, ...) // key(component) and packagename may contain '.' // timestamp contains ':' (month-day h:m:s.n) // Note: we want to preserve spaces within a metric field regex_delimiters = "[^()|,|^{}]+"; properties_index = kPropertiesR; } else { // Format of mediadrm metrics before R release: // index: [version:component:session:uid:package:package_version: // pid:finalized:timestamp:item_count:properties:] // properties in this format: :key=value:key=value:...: regex_delimiters = "[^:|^[\\]|\\s]+"; properties_index = kPropertiesQ; } std::regex delimiters(regex_delimiters); auto tokens_begin = std::sregex_iterator(line.begin(), line.end(), delimiters); auto tokens_end = std::sregex_iterator(); vector tokens; vector properties; int count = 0; for (std::sregex_iterator itr = tokens_begin; itr != tokens_end; ++itr) { std::smatch match = *itr; string token = match.str(); // timestamp contains space, so we do not want to filter // all spaces; here we filter out token that contains just spaces if (token.find_first_not_of(' ') != string::npos) { if (count < properties_index) { tokens.push_back(token); count++; } else { // trim leading spaces in token size_t first_non_space = token.find_first_not_of(' '); string trimmed_token = token.substr(first_non_space); properties.push_back(trimmed_token); } } } string component, package; if (is_r_metrics) { component = tokens[kComponentR]; package = tokens[kPackageR]; to_lower(component); to_lower(package); metrics->component = component; metrics->package = package; metrics->pid = tokens[kPidR]; metrics->timestamp = tokens[kTimestampR]; metrics->uid = tokens[kUidR]; // the following fields are not used by the tool metrics->index = tokens[kIndexR]; } else { component = tokens[kComponentQ]; package = tokens[kPackageQ]; to_lower(component); to_lower(package); metrics->component = component; metrics->package = package; metrics->timestamp = tokens[kTimestampQ]; metrics->uid = tokens[kUidQ]; metrics->pid = tokens[kPidQ]; // the following fields are not used by the tool metrics->finalized = tokens[kFinalizedQ]; metrics->index = tokens[kIndexQ]; metrics->item_count = tokens[kItemCountQ]; metrics->package_version = tokens[kPackageVersionQ]; metrics->session = tokens[kSessionQ]; metrics->version = tokens[kVersionQ]; } for (auto property : properties) { size_t equal_pos = property.find_first_of('='); string key = property.substr(0, equal_pos); string value = property.substr(equal_pos + 1); metrics->properties.push_back(std::pair(key, value)); } } } // namespace metrics_dump