diff --git a/libwvdrmengine/cdm/metrics/src/Android.bp b/libwvdrmengine/cdm/metrics/src/Android.bp index 313f9b02..925a0419 100644 --- a/libwvdrmengine/cdm/metrics/src/Android.bp +++ b/libwvdrmengine/cdm/metrics/src/Android.bp @@ -1,10 +1,47 @@ -cc_library { +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. - name: "libcdm_metrics_protos", +// Build host library for metrics_dump tool. +cc_library_host_shared { + + name: "libcdm_metrics_protos_full_host", vendor: true, + include_dirs: ["external/protobuf/src"], + srcs: [ - "wv_metrics.proto", + "wv_metrics.proto", + ], + + cflags: [ + "-Wall", + "-Werror", + ], + + proto: { + export_proto_headers: true, + type: "full", + }, +} + +cc_library { + + name: "libcdm_metrics_protos", + vendor: true, + + srcs: [ + "wv_metrics.proto", ], cflags: [ @@ -16,5 +53,4 @@ cc_library { export_proto_headers: true, type: "full", }, - } diff --git a/libwvdrmengine/tools/metrics_dump/Android.bp b/libwvdrmengine/tools/metrics_dump/Android.bp new file mode 100644 index 00000000..ae7805ee --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/Android.bp @@ -0,0 +1,54 @@ +// Copyright (C) 2020 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_binary_host { + name: "metrics_dump", + proprietary: true, + vendor: true, + + cflags: [ + "-g", + "-Wall", + + // Suppress unused parameter error. This error occurs + // when using the map type in a proto definition. + "-Wno-unused-parameter", + ], + + local_include_dirs: ["include"], + + include_dirs: [ + "frameworks/av/drm/libmediadrm/protos", + "vendor/widevine/libwvdrmengine/cdm/core/include", + "vendor/widevine/libwvdrmengine/cdm/core/test", + "vendor/widevine/libwvdrmengine/cdm/metrics/include", + "vendor/widevine/libwvdrmengine/include_hidl", + "vendor/widevine/libwvdrmengine/oemcrypto/include", + "vendor/widevine/libwvdrmengine/tools/metrics_dump/include", + ], + + shared_libs: [ + "libcdm_metrics_protos_full_host", + "libdrm_metrics_protos_full_host", + "libprotobuf-cpp-full", + ], + + srcs: [ + "src/base64decode.cpp", + "src/mediadrm_metrics.cpp", + "src/metrics_dump.cpp", + "src/parse_metrics.cpp", + "src/wv_metrics.cpp", + ], +} diff --git a/libwvdrmengine/tools/metrics_dump/Makefile b/libwvdrmengine/tools/metrics_dump/Makefile deleted file mode 100644 index 120534a7..00000000 --- a/libwvdrmengine/tools/metrics_dump/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -CDM=../../../ -OEMCRYPTO=$(CDM)/oemcrypto/include -METRICS=$(CDM)/metrics - -CFLAGS = -g -Wall -Iinclude -Igen `pkg-config --cflags protobuf` \ - -I$(OEMCRYPTO) -I$(CDM)/core/include -I$(CDM)/core/test - -OBJS := obj/metrics_dump.o obj/base64decode.o \ - obj/mediadrm_metrics.pb.o obj/mediadrm_metrics.o \ - obj/wv_metrics.o obj/metrics.pb.o obj/test_printers.o - -PROTO_HEADERS := gen/mediadrm_metrics.pb.h gen/metrics.pb.h - -bin/metrics_dump: $(OBJS) | bin - echo "objs=" $(OBJS) - g++ $(CFLAGS) -o $@ $(OBJS) `pkg-config --libs protobuf` - -gen/%.pb.cc gen/%.pb.h: $(METRICS)/src/%.proto | gen - protoc -I$(METRICS)/src/ --cpp_out=gen $< - -gen/%.pb.cc gen/%.pb.h: proto/%.proto | gen - protoc -Iproto --cpp_out=gen $< - -obj/%.o: src/%.cpp $(PROTO_HEADERS) | obj - g++ -c $(CFLAGS) $< -o $@ - -obj/%.o: gen/%.cc $(PROTO_HEADERS) | obj - g++ -c $(CFLAGS) $< -o $@ - -obj/%.o: $(CDM)/core/test/%.cpp | obj - g++ -c $(CFLAGS) $< -o $@ - -obj gen bin: - mkdir $@ - -clean: - rm -rf obj bin gen - diff --git a/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h b/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h index ee9589db..65d23791 100644 --- a/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h +++ b/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h @@ -6,7 +6,7 @@ #include -#include "mediadrm_metrics.pb.h" +#include "metrics.pb.h" namespace mediadrm_metrics { void FormatDrmFrameworkMetrics( diff --git a/libwvdrmengine/tools/metrics_dump/include/parse_metrics.h b/libwvdrmengine/tools/metrics_dump/include/parse_metrics.h new file mode 100644 index 00000000..384f3487 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/include/parse_metrics.h @@ -0,0 +1,56 @@ +// Copyright 2020 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// Take a line as input, parse the metrics, and returns MediaMetrics +// structure as output. + +#include +#include +#include + +namespace metrics_dump { + +// This is the order of metrics prior to R release, do not change. +// We use this to index into a vector of tokens to retrieve metrics. +typedef enum { + kIndexQ, + kVersionQ, + kComponentQ, + kSessionQ, + kUidQ, + kPackageQ, + kPackageVersionQ, + kPidQ, + kFinalizedQ, + kTimestampQ, + kItemCountQ, + // kPropertiesQ serves as a sentinel to indicate properties follow + kPropertiesQ, +} QMediaMetricsItems; + +// This is the order of metrics since R release, do not change. +// We use this to index into a vector of tokens to retrieve metrics. +typedef enum { + kIndexR, + kComponentR, + kTimestampR, + kPackageR, + kPidR, + kUidR, + // kPropertiesR serves as a sentinel to indicate properties follow + kPropertiesR, +} RMediaMetricsItems; + +typedef struct { + std::string component, finalized, index, item_count; + std::string package, package_version, pid, session; + std::string timestamp, version, uid; + std::vector> properties; +} MediaMetrics; + +bool is_q_metrics(const std::string &line); +void parse_metrics(const std::string& line, MediaMetrics* metrics); +void to_lower(std::string& lower); + +}; // namespace metrics_dump diff --git a/libwvdrmengine/tools/metrics_dump/proto/mediadrm_metrics.proto b/libwvdrmengine/tools/metrics_dump/proto/mediadrm_metrics.proto deleted file mode 100644 index 11728d34..00000000 --- a/libwvdrmengine/tools/metrics_dump/proto/mediadrm_metrics.proto +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto2"; - -package android.drm_metrics; - -// need this if we are using libprotobuf-cpp-2.3.0-lite -option optimize_for = LITE_RUNTIME; - - -// This message contains the specific metrics captured by DrmMetrics. It is -// used for serializing and logging metrics. -// next id: 11. -message DrmFrameworkMetrics { - // TODO: Consider using extensions. - - // Attributes are associated with a recorded value. E.g. A counter may - // represent a count of an operation returning a specific error code. The - // error code will be an attribute. - message Attributes { - // Reserved for compatibility with logging proto. - reserved 2 to 13; - - // A general purpose error code where 0 means OK. - optional int32 error_code = 1; - - // Defined at ::android::hardware::drm::V1_0::KeyStatusType; - optional uint32 key_status_type = 14; - - // Defined at ::android::hardware::drm::V1_0::EventType; - optional uint32 event_type = 15; - } - - // The Counter message is used to store a count value with an associated - // Attribute. - message Counter { - optional uint64 count = 1; - // Represents the attributes associated with this counter instance. - optional Attributes attributes = 2; - } - - // The DistributionMetric is meant to capture the moments of a normally - // distributed (or approximately normal) value. - message DistributionMetric { - optional float min = 1; - optional float max = 2; - optional float mean = 3; - optional double variance = 4; - optional uint64 operation_count = 5; - - // Represents the attributes assocated with this distribution metric - // instance. - optional Attributes attributes = 6; - } - - message SessionLifetime { - // Start time of the session in milliseconds since epoch. - optional uint64 start_time_ms = 1; - - // End time of the session in milliseconds since epoch. - optional uint64 end_time_ms = 2; - } - - // The count of open session operations. Each instance has a specific error - // code associated with it. - repeated Counter open_session_counter = 1; - - // The count of close session operations. Each instance has a specific error - // code associated with it. - repeated Counter close_session_counter = 2; - - // Count and execution time of getKeyRequest calls. - repeated DistributionMetric get_key_request_time_us = 3; - - // Count and execution time of provideKeyResponse calls. - repeated DistributionMetric provide_key_response_time_us = 4; - - // Count of getProvisionRequest calls. - repeated Counter get_provisioning_request_counter = 5; - - // Count of provideProvisionResponse calls. - repeated Counter provide_provisioning_response_counter = 6; - - // Count of key status events broken out by status type. - repeated Counter key_status_change_counter = 7; - - // Count of events broken out by event type - repeated Counter event_callback_counter = 8; - - // Count getPropertyByteArray calls to retrieve the device unique id. - repeated Counter get_device_unique_id_counter = 9; - - // Session ids to lifetime (start and end time) map. - // Session ids are strings of hex-encoded byte arrays. - map session_lifetimes = 10; -} - diff --git a/libwvdrmengine/tools/metrics_dump/proto/wv_metrics.proto b/libwvdrmengine/tools/metrics_dump/proto/wv_metrics.proto deleted file mode 100644 index 680d35e6..00000000 --- a/libwvdrmengine/tools/metrics_dump/proto/wv_metrics.proto +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2017 Google Inc. All Rights Reserved. -// -// This file contains a proto definition for serialization of metrics data. -// -syntax = "proto2"; - -package drm_metrics; - -// need this if we are using libprotobuf-cpp-2.3.0-lite -option optimize_for = LITE_RUNTIME; - -// The Attributes message is used to contain values associated with the -// metric that was captured. E.g. if we're capturing a counter value, the -// Attributes will contain the values assocated with that counter. E.g. we may -// want to count all of the operations with a give error code. -message Attributes { - // Reserved for compatibility with logging proto. - // TODO(blueeyes): The reserved keyword is not supported in the older version - // of protoc in the CE CDM third_party directory. Uncomment the reserved - // line when we upgrade. b/67016366. - // reserved 8, 10 to 13; - - // The error code. See CdmResponseType in wv_cdm_types.h - optional int32 error_code = 1; - // The status of the processed data. Some methods has a bool error code - // rather than a CdmResponseType error code. True if it succeeds, and - // false if it fails. - optional bool error_code_bool = 2; - // The CdmSecurityLevel. Defined in wv_cdm_types.h - optional uint32 cdm_security_level = 3; - // The SecurityLevel. Defined in wv_cdm_types.h. - optional uint32 security_level = 4; - // The length in bytes. - optional uint64 length = 5; - // The CDM encryption algorithm. It can be "AES-CBC-128" or unknown. See - // CdmEncryptionAlgorithm in wv_cdm_types.h - optional uint32 encryption_algorithm = 6; - // The CDM signing algorithm. It can be "HMACSHA256" or unknown. See - // CdmSigningAlgorithm in wv_cdm_types.h - optional uint32 signing_algorithm = 7; - // The OEM crypto result. See OEMCryptoResult in OEMCryptoCENC.h - optional int32 oem_crypto_result = 9; - // Defined at ::android::hardware::drm::V1_0::KeyStatusType; - optional uint32 key_status_type = 14; - // Defined at ::android::hardware::drm::V1_0::EventType; - optional uint32 event_type = 15; - // Contains the CdmKeyRequestType defined in wv_cdm_types.h. - optional uint32 key_request_type = 16; -} - -// The Counter message is used to store a count value with an associated -// Attribute. -message CounterMetric { - optional int64 count = 1; - // Represents the attributes associated with this counter instance. - optional Attributes attributes = 2; -} - -// The DistributionMetric is meant to capture the moments of a normally -// distributed (or approximately normal) value. -message DistributionMetric { - optional float min = 1; - optional float max = 2; - optional float mean = 3; - optional double variance = 4; - optional uint64 operation_count = 5; - - // Represents the attributes assocated with this distribution metric - // instance. - optional Attributes attributes = 6; -} - -// ValueMetric represents either a single value or an error. -message ValueMetric { - // Only one of the following values should be set for the given metric. - optional int32 error_code = 1; - optional int64 int_value = 2; - optional double double_value = 3; - optional string string_value = 4; -} - - -// This message contains the specific metrics captured by DrmMetrics. It is -// used for serializing and logging metrics. -// next id: 3. -message WvCdmMetrics { - // Attributes are associated with a recorded value. E.g. A counter may - // represent a count of an operation returning a specific error code. The - // error code will be an attribute. - - // This contains metrics that were captured at the CryptoSession level. These - // include CryptoSession metrics and most OEMCrypto metrics. - // next id: 58 - message CryptoMetrics { - // Crypto Session Metrics. - optional ValueMetric crypto_session_security_level = 1; - repeated CounterMetric crypto_session_delete_all_usage_reports = 2; - repeated CounterMetric crypto_session_delete_multiple_usage_information = 3; - repeated DistributionMetric crypto_session_generic_decrypt_time_us = 4; - repeated DistributionMetric crypto_session_generic_encrypt_time_us = 5; - repeated DistributionMetric crypto_session_generic_sign_time_us = 6; - repeated DistributionMetric crypto_session_generic_verify_time_us = 7; - repeated CounterMetric crypto_session_get_device_unique_id = 8; - repeated CounterMetric crypto_session_get_token = 9; - optional ValueMetric crypto_session_life_span = 10; - repeated DistributionMetric crypto_session_load_certificate_private_key_time_us = 11; - repeated DistributionMetric crypto_session_open_time_us = 12; - optional ValueMetric crypto_session_system_id = 13; - repeated DistributionMetric crypto_session_update_usage_information_time_us = 14; - repeated DistributionMetric crypto_session_update_usage_entry_time_us = 56; - optional ValueMetric crypto_session_usage_information_support = 15; - // OemCrypto metrics. - optional ValueMetric oemcrypto_api_version = 16; - repeated CounterMetric oemcrypto_close_session = 17; - repeated DistributionMetric oemcrypto_copy_buffer_time_us = 18; - optional ValueMetric oemcrypto_current_hdcp_capability = 19; - repeated CounterMetric oemcrypto_deactivate_usage_entry = 20; - repeated DistributionMetric oemcrypto_decrypt_cenc_time_us = 21; - repeated CounterMetric oemcrypto_delete_usage_entry = 22; - repeated CounterMetric oemcrypto_delete_usage_table = 23; - repeated DistributionMetric oemcrypto_derive_keys_from_session_key_time_us = 24; - repeated CounterMetric oemcrypto_force_delete_usage_entry = 25; - repeated DistributionMetric oemcrypto_generate_derived_keys_time_us = 26; - repeated CounterMetric oemcrypto_generate_nonce = 27; - repeated DistributionMetric oemcrypto_generate_rsa_signature_time_us = 28; - repeated DistributionMetric oemcrypto_generate_signature_time_us = 29; - repeated DistributionMetric oemcrypto_generic_decrypt_time_us = 30; - repeated DistributionMetric oemcrypto_generic_encrypt_time_us = 31; - repeated DistributionMetric oemcrypto_generic_sign_time_us = 32; - repeated DistributionMetric oemcrypto_generic_verify_time_us = 33; - repeated CounterMetric oemcrypto_get_device_id = 34; - repeated DistributionMetric oemcrypto_get_key_data_time_us = 35; - repeated CounterMetric oemcrypto_get_oem_public_certificate = 36; - repeated CounterMetric oemcrypto_get_random = 37; - repeated DistributionMetric oemcrypto_initialize_time_us = 38; - optional ValueMetric oemcrypto_is_anti_rollback_hw_present = 39; - optional ValueMetric oemcrypto_is_keybox_valid = 40; - repeated DistributionMetric oemcrypto_load_device_rsa_key_time_us = 41; - repeated DistributionMetric oemcrypto_load_entitled_keys_time_us = 42; - repeated DistributionMetric oemcrypto_load_keys_time_us = 43; - optional ValueMetric oemcrypto_max_hdcp_capability = 44; - optional ValueMetric oemcrypto_max_number_of_sessions = 45; - optional ValueMetric oemcrypto_number_of_open_sessions = 46; - optional ValueMetric oemcrypto_provisioning_method = 47; - repeated DistributionMetric oemcrypto_refresh_keys_time_us = 48; - repeated CounterMetric oemcrypto_report_usage = 49; - repeated DistributionMetric oemcrypto_rewrap_device_rsa_key_time_us = 50; - repeated DistributionMetric oemcrypto_rewrap_device_rsa_key_30_time_us = 51; - optional ValueMetric oemcrypto_security_patch_level = 52; - repeated DistributionMetric oemcrypto_select_key_time_us = 53; - optional ValueMetric oemcrypto_usage_table_support = 54; - repeated CounterMetric oemcrypto_update_usage_table = 55; - repeated CounterMetric oemcrypto_update_usage_entry = 57; - } - - // This contains metrics that were captured within a CdmSession. This contains - // nested CryptoMetrics that were captured in the context of the session. - // next id: 8 - message SessionMetrics { - optional ValueMetric session_id = 1; - optional CryptoMetrics crypto_metrics = 2; - optional ValueMetric cdm_session_life_span_ms = 3; - repeated DistributionMetric cdm_session_renew_key_time_us = 4; - repeated CounterMetric cdm_session_restore_offline_session = 5; - repeated CounterMetric cdm_session_restore_usage_session = 6; - repeated DistributionMetric cdm_session_license_request_latency_ms = 7; - } - - // These are metrics recorded at the Engine level. This includes CryptoSession - // metrics that were captured in the context of the engine. - // next id: 29 - message EngineMetrics { - optional CryptoMetrics crypto_metrics = 1; - - // OEMCrypto Initialize Metrics. - optional ValueMetric oemcrypto_initialization_mode = 3; - optional ValueMetric oemcrypto_l1_api_version = 4; - optional ValueMetric oemcrypto_l1_min_api_version = 5; - // CdmEngine Metrics. - optional ValueMetric app_package_name = 6; - repeated DistributionMetric cdm_engine_add_key_time_us = 7; - optional ValueMetric cdm_engine_cdm_version = 8; - repeated CounterMetric cdm_engine_close_session = 9; - optional ValueMetric cdm_engine_creation_time_millis = 10; - repeated DistributionMetric cdm_engine_decrypt_time_us = 11; - repeated CounterMetric cdm_engine_find_session_for_key = 12; - repeated DistributionMetric cdm_engine_generate_key_request_time_us = 13; - repeated DistributionMetric cdm_engine_get_provisioning_request_time_us = 14; - repeated CounterMetric cdm_engine_get_secure_stop_ids = 15; - repeated DistributionMetric cdm_engine_get_usage_info_time_us = 16; - repeated DistributionMetric cdm_engine_handle_provisioning_response_time_us = 17; - optional ValueMetric cdm_engine_life_span_ms = 18; - repeated CounterMetric cdm_engine_open_key_set_session = 19; - repeated CounterMetric cdm_engine_open_session = 20; - repeated DistributionMetric cdm_engine_query_key_status_time_us = 21; - repeated CounterMetric cdm_engine_release_all_usage_info = 22; - repeated CounterMetric cdm_engine_release_usage_info = 23; - repeated CounterMetric cdm_engine_remove_all_usage_info = 24; - repeated CounterMetric cdm_engine_remove_keys = 25; - repeated CounterMetric cdm_engine_remove_usage_info = 26; - repeated DistributionMetric cdm_engine_restore_key_time_us = 27; - repeated CounterMetric cdm_engine_unprovision = 28; - } - - optional EngineMetrics engine_metrics = 1; - repeated SessionMetrics session_metrics = 2; -} - -// This message contains a collection of metrics, one per CDM engine instance. -message WvCdmMetricsGroup { - repeated WvCdmMetrics metrics = 1; -} - -// Test message to support unit testing. -message TestMetrics{ - optional ValueMetric test_value_metric = 1; - repeated CounterMetric test_counters = 3; - repeated DistributionMetric test_distributions = 2; -} diff --git a/libwvdrmengine/tools/metrics_dump/src/base64decode.cpp b/libwvdrmengine/tools/metrics_dump/src/base64decode.cpp index 113c69f5..46350010 100644 --- a/libwvdrmengine/tools/metrics_dump/src/base64decode.cpp +++ b/libwvdrmengine/tools/metrics_dump/src/base64decode.cpp @@ -4,12 +4,12 @@ // // simple base64 decoder +#include "base64decode.h" + #include #include #include -#include "base64decode.h" - namespace base64 { using namespace std; diff --git a/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp b/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp index 4a665653..42d5d81d 100644 --- a/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp +++ b/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp @@ -11,7 +11,7 @@ #include #include -#include "mediadrm_metrics.pb.h" +#include "metrics.pb.h" namespace mediadrm_metrics { diff --git a/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp b/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp index 6091f03a..8c2ecc78 100644 --- a/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp +++ b/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp @@ -4,114 +4,106 @@ // // Format metric output from |adb shell dumpsys media.metrics| -#include #include #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 mediadrm_metrics; 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); -#define READ_TOKEN(NAME) \ - if (!std::getline(fields, NAME, ':')) { \ - cerr << "error: expected |" #NAME "| field in '" << line << "'" << endl; \ - } - - string index, version, component, session, uid, package, package_version; - string pid, finalized, timestamp, item_count; - - READ_TOKEN(index); - READ_TOKEN(version); - READ_TOKEN(component); - READ_TOKEN(session); - READ_TOKEN(uid); - READ_TOKEN(package); - READ_TOKEN(package_version); - READ_TOKEN(pid); - READ_TOKEN(finalized); - READ_TOKEN(timestamp); - READ_TOKEN(item_count); + MediaMetrics metrics; + parse_metrics(line, &metrics); // handle specific package and component selection - if (selected_one.size() && package != selected_one && - component != selected_one) { + if (selected_one.size() && metrics.package != selected_one && + metrics.component != selected_one) { return; } - if (std::find(excluded_ones.begin(), excluded_ones.end(), package) != + if (std::find(excluded_ones.begin(), excluded_ones.end(), metrics.package) != excluded_ones.end()) { return; } - if (std::find(excluded_ones.begin(), excluded_ones.end(), component) != - excluded_ones.end()) { + if (std::find(excluded_ones.begin(), excluded_ones.end(), + metrics.component) != excluded_ones.end()) { return; } cout << "====================================================================" "=============" << endl; - char timebuf[64]; - time_t time_s = stoll(timestamp) / 1000000000LL; - strftime(timebuf, sizeof(timebuf), "%a %b %e %H:%M:%S", localtime(&time_s)); - cout << timebuf << " timestamp: " << time_s << endl << 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 << " " << package << " -> " << component << " | uid:" << uid - << " pid:" << pid << endl; + cout << " " << metrics.package << " -> " << metrics.component << endl; + cout << "\tuid:" << metrics.uid << " pid:" << metrics.pid << endl; - size_t items = std::stoi(item_count); - for (size_t i = 0; i < items; i++) { - string parameter, value; - if (!std::getline(fields, parameter, '=')) { - cerr << "error: expected |parameter| in item " << i << " in '" << line - << "'" << endl; - } - if (!std::getline(fields, value, ':')) { - cerr << "error: expected |value| in item " << i << " in '" << line << "'" - << endl; - } - - if (parameter == "serialized_metrics") { + for (auto property : metrics.properties) { + string key = property.first; + string value = property.second; + if (key == "serialized_metrics") { string decoded = Base64::Decode(value); - if (component == "drm.vendor.Google.WidevineCDM") { - drm_metrics::WvCdmMetrics metrics; - if (!metrics.ParseFromString(decoded)) { + 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(metrics, result); + FormatWvCdmMetrics(wv_metrics, result); cout << endl << result << endl; } } else { - android::drm_metrics::DrmFrameworkMetrics metrics; - if (!metrics.ParseFromString(decoded)) { + android::drm_metrics::DrmFrameworkMetrics fw_metrics; + if (!fw_metrics.ParseFromString(decoded)) { cerr << "failed to parse proto string" << endl; } else { string result; - FormatDrmFrameworkMetrics(metrics, result); + mediadrm_metrics::FormatDrmFrameworkMetrics(fw_metrics, result); cout << endl << result << endl; } } } else { - cout << " " << parameter << ": " << value << endl; + cout << " " << key << ": " << value << endl; } } } @@ -170,7 +162,7 @@ int main(int argc, char **argv) { } 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"; + metrics_dump::selected_one = "drm.vendor.google.widevinecdm"; } else if (arg == "--mediadrm") { metrics_dump::selected_one = "mediadrm"; } else if (i == argc - 1) { @@ -185,9 +177,12 @@ int main(int argc, char **argv) { } else { // args with a parameter if (arg == "--exclude") { - metrics_dump::excluded_ones.push_back(argv[++i]); + 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 { usage(); } diff --git a/libwvdrmengine/tools/metrics_dump/src/parse_metrics.cpp b/libwvdrmengine/tools/metrics_dump/src/parse_metrics.cpp new file mode 100644 index 00000000..91318d80 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/src/parse_metrics.cpp @@ -0,0 +1,117 @@ +// 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 diff --git a/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp b/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp index 3dd0ed48..aa494619 100644 --- a/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp +++ b/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp @@ -17,7 +17,9 @@ namespace wv_metrics { -using namespace drm_metrics; +// The following declaration causes +// ambiguous namespace error in metrics_dump.cpp: +// using namespace drm_metrics; using std::string; using std::to_string; @@ -35,7 +37,7 @@ string FormatOEMCryptoResult(int oemcrypto_result) { return " " + os.str(); } -string FormatOEMCryptoInitializeMode(const ValueMetric& vm) { +string FormatOEMCryptoInitializeMode(const drm_metrics::ValueMetric& vm) { std::map translations = { {0, "USING_IN_APP"}, {1, "FORCING_L3"}, @@ -53,18 +55,26 @@ string FormatOEMCryptoInitializeMode(const ValueMetric& vm) { {13, "USING_L1_INSTALLED_KEYBOX"}, {14, "USING_L3_INVALID_L1"}, {15, "USING_L1_WITH_PROVISIONING_3_0"}, - {16, "L3_INITIALIZATION_FAILED"}}; + {16, "L3_INITIALIZATION_FAILED"}, + {17, "L3_RNG_FAILED"}, + {18, "L3_SAVE_DEVICE_KEYS_FAILED"}, + {19, "L3_READ_DEVICE_KEYS_FAILED"}, + {20, "L3_VERIFY_DEVICE_KEYS_FAILED"}}; return translations[vm.int_value()]; } -string FormatOEMCryptoHdcpCapability(const ValueMetric& vm) { - std::map translations = {{0, "HDCP_NONE"}, {1, "HDCP_V1"}, - {2, "HDCP_V2"}, {3, "HDCP_V2_1"}, - {4, "HDCP_V2_2"}, {0xff, "NO_OUTPUT"}}; +string FormatOEMCryptoHdcpCapability(const drm_metrics::ValueMetric& vm) { + std::map translations = {{0, "HDCP_NONE"}, + {1, "HDCP_V1"}, + {2, "HDCP_V2"}, + {3, "HDCP_V2_1"}, + {4, "HDCP_V2_2"}, + {5, "HDCP_V2_3"}, + {0xff, "HDCP_NO_DIGITAL_OUTPUT"}}; return translations[vm.int_value()]; } -string FormatOEMCryptoProvisioningMethod(const ValueMetric& vm) { +string FormatOEMCryptoProvisioningMethod(const drm_metrics::ValueMetric& vm) { std::map translations = {{0, "PROVISIONING_ERROR"}, {1, "DRM_CERTIFICATE"}, {2, "KEYBOX"}, @@ -72,7 +82,7 @@ string FormatOEMCryptoProvisioningMethod(const ValueMetric& vm) { return translations[vm.int_value()]; } -string FormatAttributes(const Attributes& attributes) { +string FormatAttributes(const drm_metrics::Attributes& attributes) { string result; if (attributes.has_error_code()) { result.append("error_code:"); @@ -137,7 +147,7 @@ string FormatAttributes(const Attributes& attributes) { } } -string FormatCounterMetric(const CounterMetric& cm) { +string FormatCounterMetric(const drm_metrics::CounterMetric& cm) { string result; if (cm.has_count()) { result = string("count=") + to_string(cm.count()); @@ -148,7 +158,7 @@ string FormatCounterMetric(const CounterMetric& cm) { return result; } -string FormatDistributionMetric(const DistributionMetric& dm) { +string FormatDistributionMetric(const drm_metrics::DistributionMetric& dm) { string result; if (dm.has_min()) { std::ostringstream buffer; @@ -183,7 +193,7 @@ string FormatDistributionMetric(const DistributionMetric& dm) { return result; } -string FormatValueMetric(const ValueMetric& vm) { +string FormatValueMetric(const drm_metrics::ValueMetric& vm) { string result; if (vm.has_error_code()) { result.append("error(" + to_string(vm.error_code())); @@ -257,7 +267,7 @@ string FormatValueMetric(const ValueMetric& vm) { FormatCryptoMetrics(metrics.NAME(), INDENT + kIndentPerLine, result); \ } -void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics, +void FormatCryptoMetrics(const drm_metrics::WvCdmMetrics_CryptoMetrics metrics, const string& indent, string& result) { // Crypto Session Metrics. FORMAT_OPTIONAL_VALUE(crypto_session_security_level, indent); @@ -286,6 +296,12 @@ void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics, FORMAT_REPEATED_DISTRIBUTION(usage_table_header_update_entry_time_us, indent); FORMAT_REPEATED_COUNTER(usage_table_header_load_entry, indent); + // Usage Table LRU Metrics + FORMAT_OPTIONAL_VALUE(usage_table_header_lru_usage_info_count, indent); + FORMAT_OPTIONAL_VALUE(usage_table_header_lru_offline_license_count, indent); + FORMAT_OPTIONAL_VALUE(usage_table_header_lru_evicted_entry_staleness_s, + indent); + FORMAT_OPTIONAL_VALUE(usage_table_header_lru_evicted_entry_type, indent); // OemCrypto metrics. FORMAT_OPTIONAL_VALUE(oemcrypto_api_version, indent); FORMAT_REPEATED_COUNTER(oemcrypto_close_session, indent); @@ -342,10 +358,24 @@ void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics, FORMAT_OPTIONAL_VALUE(oemcrypto_set_sandbox, indent); FORMAT_REPEATED_COUNTER(oemcrypto_set_decrypt_hash, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_resource_rating_tier, indent); + + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_prep_and_sign_license_request_time_us, + indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_prep_and_sign_renewal_request_time_us, + indent); + FORMAT_REPEATED_DISTRIBUTION( + oemcrypto_prep_and_sign_provisioning_request_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_license_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_renewal_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_provisioning_time_us, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_minor_api_version, indent); + ; + FORMAT_OPTIONAL_VALUE(oemcrypto_maximum_usage_table_header_size, indent); } -void FormatSessionMetrics(const WvCdmMetrics_SessionMetrics& metrics, - const string& indent, string& result) { +void FormatSessionMetrics( + const drm_metrics::WvCdmMetrics_SessionMetrics& metrics, + const string& indent, string& result) { FORMAT_OPTIONAL_VALUE(session_id, indent); FORMAT_OPTIONAL_CRYPTO_METRICS(crypto_metrics, indent); FORMAT_OPTIONAL_VALUE(cdm_session_life_span_ms, indent); @@ -358,7 +388,7 @@ void FormatSessionMetrics(const WvCdmMetrics_SessionMetrics& metrics, FORMAT_OPTIONAL_VALUE(license_service_version, indent); } -void FormatEngineMetrics(const WvCdmMetrics_EngineMetrics& metrics, +void FormatEngineMetrics(const drm_metrics::WvCdmMetrics_EngineMetrics& metrics, const string& indent, string& result) { FORMAT_OPTIONAL_CRYPTO_METRICS(crypto_metrics, indent); @@ -366,8 +396,6 @@ void FormatEngineMetrics(const WvCdmMetrics_EngineMetrics& metrics, FORMAT_OPTIONAL_INITIALIZATION_MODE(oemcrypto_initialization_mode, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_l1_api_version, indent); FORMAT_OPTIONAL_VALUE(oemcrypto_l1_min_api_version, indent); - FORMAT_OPTIONAL_VALUE(level3_oemcrypto_initialization_error, indent); - FORMAT_OPTIONAL_VALUE(previous_oemcrypto_initialization_failure, indent); // CdmEngine Metrics. FORMAT_OPTIONAL_VALUE(app_package_name, indent); @@ -395,9 +423,12 @@ void FormatEngineMetrics(const WvCdmMetrics_EngineMetrics& metrics, FORMAT_REPEATED_COUNTER(cdm_engine_remove_usage_info, indent); FORMAT_REPEATED_DISTRIBUTION(cdm_engine_restore_key_time_us, indent); FORMAT_REPEATED_COUNTER(cdm_engine_unprovision, indent); + FORMAT_OPTIONAL_VALUE(level3_oemcrypto_initialization_error, indent); + FORMAT_OPTIONAL_VALUE(previous_oemcrypto_initialization_failure, indent); } -void FormatWvCdmMetrics(const WvCdmMetrics& metrics, string& result) { +void FormatWvCdmMetrics(const drm_metrics::WvCdmMetrics& metrics, + string& result) { string indent = kIndentPerLine; string next_indent = indent + kIndentPerLine;