diff --git a/libwvdrmengine/cdm/core/test/test_printers.cpp b/libwvdrmengine/cdm/core/test/test_printers.cpp index 4e09a8d7..d703a93d 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.cpp +++ b/libwvdrmengine/cdm/core/test/test_printers.cpp @@ -941,7 +941,7 @@ void PrintTo(const enum CdmLicenseType& value, ::std::ostream* os) { *os << "Unknown CdmLicenseType"; break; } -}; +} void PrintTo(const enum CdmSecurityLevel& value, ::std::ostream* os) { switch (value) { @@ -964,7 +964,7 @@ void PrintTo(const enum CdmSecurityLevel& value, ::std::ostream* os) { *os << "Unknown CdmSecurityLevel"; break; } -}; +} void PrintTo(const enum CdmCertificateType& value, ::std::ostream* os) { switch (value) { @@ -978,6 +978,182 @@ void PrintTo(const enum CdmCertificateType& value, ::std::ostream* os) { *os << "Unknown CdmCertificateType"; break; } -}; +} + +void PrintTo(const enum OEMCryptoResult& value, ::std::ostream* os) { + switch (value) { + case OEMCrypto_SUCCESS: + *os << "SUCCESS"; + break; + case OEMCrypto_ERROR_INIT_FAILED: + *os << "INIT_FAILED"; + break; + case OEMCrypto_ERROR_TERMINATE_FAILED: + *os << "TERMINATE_FAILED"; + break; + case OEMCrypto_ERROR_OPEN_FAILURE: + *os << "OPEN_FAILURE"; + break; + case OEMCrypto_ERROR_CLOSE_FAILURE: + *os << "CLOSE_FAILURE"; + break; + case OEMCrypto_ERROR_ENTER_SECURE_PLAYBACK_FAILED: + *os << "ENTER_SECURE_PLAYBACK_FAILED"; + break; + case OEMCrypto_ERROR_EXIT_SECURE_PLAYBACK_FAILED: + *os << "EXIT_SECURE_PLAYBACK_FAILED"; + break; + case OEMCrypto_ERROR_SHORT_BUFFER: + *os << "SHORT_BUFFER"; + break; + case OEMCrypto_ERROR_NO_DEVICE_KEY: + *os << "NO_DEVICE_KEY"; + break; + case OEMCrypto_ERROR_NO_ASSET_KEY: + *os << "NO_ASSET_KEY"; + break; + case OEMCrypto_ERROR_KEYBOX_INVALID: + *os << "KEYBOX_INVALID"; + break; + case OEMCrypto_ERROR_NO_KEYDATA: + *os << "NO_KEYDATA"; + break; + case OEMCrypto_ERROR_NO_CW: + *os << "NO_CW"; + break; + case OEMCrypto_ERROR_DECRYPT_FAILED: + *os << "DECRYPT_FAILED"; + break; + case OEMCrypto_ERROR_WRITE_KEYBOX: + *os << "WRITE_KEYBOX"; + break; + case OEMCrypto_ERROR_WRAP_KEYBOX: + *os << "WRAP_KEYBOX"; + break; + case OEMCrypto_ERROR_BAD_MAGIC: + *os << "BAD_MAGIC"; + break; + case OEMCrypto_ERROR_BAD_CRC: + *os << "BAD_CRC"; + break; + case OEMCrypto_ERROR_NO_DEVICEID: + *os << "NO_DEVICEID"; + break; + case OEMCrypto_ERROR_RNG_FAILED: + *os << "RNG_FAILED"; + break; + case OEMCrypto_ERROR_RNG_NOT_SUPPORTED: + *os << "RNG_NOT_SUPPORTED"; + break; + case OEMCrypto_ERROR_SETUP: + *os << "SETUP"; + break; + case OEMCrypto_ERROR_OPEN_SESSION_FAILED: + *os << "OPEN_SESSION_FAILED"; + break; + case OEMCrypto_ERROR_CLOSE_SESSION_FAILED: + *os << "CLOSE_SESSION_FAILED"; + break; + case OEMCrypto_ERROR_INVALID_SESSION: + *os << "INVALID_SESSION"; + break; + case OEMCrypto_ERROR_NOT_IMPLEMENTED: + *os << "NOT_IMPLEMENTED"; + break; + case OEMCrypto_ERROR_NO_CONTENT_KEY: + *os << "NO_CONTENT_KEY"; + break; + case OEMCrypto_ERROR_CONTROL_INVALID: + *os << "CONTROL_INVALID"; + break; + case OEMCrypto_ERROR_UNKNOWN_FAILURE: + *os << "UNKNOWN_FAILURE"; + break; + case OEMCrypto_ERROR_INVALID_CONTEXT: + *os << "INVALID_CONTEXT"; + break; + case OEMCrypto_ERROR_SIGNATURE_FAILURE: + *os << "SIGNATURE_FAILURE"; + break; + case OEMCrypto_ERROR_TOO_MANY_SESSIONS: + *os << "TOO_MANY_SESSIONS"; + break; + case OEMCrypto_ERROR_INVALID_NONCE: + *os << "INVALID_NONCE"; + break; + case OEMCrypto_ERROR_TOO_MANY_KEYS: + *os << "TOO_MANY_KEYS"; + break; + case OEMCrypto_ERROR_DEVICE_NOT_RSA_PROVISIONED: + *os << "DEVICE_NOT_RSA_PROVISIONED"; + break; + case OEMCrypto_ERROR_INVALID_RSA_KEY: + *os << "INVALID_RSA_KEY"; + break; + case OEMCrypto_ERROR_KEY_EXPIRED: + *os << "KEY_EXPIRED"; + break; + case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES: + *os << "INSUFFICIENT_RESOURCES"; + break; + case OEMCrypto_ERROR_INSUFFICIENT_HDCP: + *os << "INSUFFICIENT_HDCP"; + break; + case OEMCrypto_ERROR_BUFFER_TOO_LARGE: + *os << "BUFFER_TOO_LARGE"; + break; + case OEMCrypto_WARNING_GENERATION_SKEW: + *os << "OEMCrypto_WARNING_GENERATION_SKEW"; + break; + case OEMCrypto_ERROR_GENERATION_SKEW: + *os << "GENERATION_SKEW"; + break; + case OEMCrypto_LOCAL_DISPLAY_ONLY: + *os << "OEMCrypto_LOCAL_DISPLAY_ONLY"; + break; + case OEMCrypto_ERROR_ANALOG_OUTPUT: + *os << "ANALOG_OUTPUT"; + break; + case OEMCrypto_ERROR_WRONG_PST: + *os << "WRONG_PST"; + break; + case OEMCrypto_ERROR_WRONG_KEYS: + *os << "WRONG_KEYS"; + break; + case OEMCrypto_ERROR_MISSING_MASTER: + *os << "MISSING_MASTER"; + break; + case OEMCrypto_ERROR_LICENSE_INACTIVE: + *os << "LICENSE_INACTIVE"; + break; + case OEMCrypto_ERROR_ENTRY_NEEDS_UPDATE: + *os << "ENTRY_NEEDS_UPDATE"; + break; + case OEMCrypto_ERROR_ENTRY_IN_USE: + *os << "ENTRY_IN_USE"; + break; + case OEMCrypto_ERROR_USAGE_TABLE_UNRECOVERABLE: + *os << "USAGE_TABLE_UNRECOVERABLE"; + break; + case OEMCrypto_KEY_NOT_LOADED: + *os << "OEMCrypto_KEY_NOT_LOADED"; + break; + case OEMCrypto_KEY_NOT_ENTITLED: + *os << "OEMCrypto_KEY_NOT_ENTITLED"; + break; + case OEMCrypto_ERROR_BAD_HASH: + *os << "BAD_HASH"; + break; + case OEMCrypto_ERROR_OUTPUT_TOO_LARGE: + *os << "OUTPUT_TOO_LARGE"; + break; + case OEMCrypto_ERROR_SESSION_LOST_STATE: + *os << "SESSION_LOST_STATE"; + break; + case OEMCrypto_ERROR_SYSTEM_INVALIDATED: + *os << "SYSTEM_INVALIDATED"; + break; + } +} } // namespace wvcdm diff --git a/libwvdrmengine/cdm/core/test/test_printers.h b/libwvdrmengine/cdm/core/test/test_printers.h index b41788f1..42bed79c 100644 --- a/libwvdrmengine/cdm/core/test/test_printers.h +++ b/libwvdrmengine/cdm/core/test/test_printers.h @@ -8,6 +8,7 @@ #define CDM_TEST_PRINTERS_H_ #include +#include "OEMCryptoCENC.h" #include "wv_cdm_types.h" namespace wvcdm { @@ -15,6 +16,7 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os); void PrintTo(const enum CdmLicenseType& value, ::std::ostream* os); void PrintTo(const enum CdmSecurityLevel& value, ::std::ostream* os); void PrintTo(const enum CdmCertificateType& value, ::std::ostream* os); +void PrintTo(const enum OEMCryptoResult& value, ::std::ostream* os); } // namespace wvcdm #endif // CDM_TEST_PRINTERS_H_ diff --git a/libwvdrmengine/tools/metrics_dump/Makefile b/libwvdrmengine/tools/metrics_dump/Makefile new file mode 100644 index 00000000..120534a7 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/Makefile @@ -0,0 +1,38 @@ +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/base64decode.h b/libwvdrmengine/tools/metrics_dump/include/base64decode.h new file mode 100644 index 00000000..0918cf7b --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/include/base64decode.h @@ -0,0 +1,19 @@ +// 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. +// +// simple base64 decoder + +#include + +namespace base64 { + +class Base64 { + public: + Base64() {} + ~Base64() {} + + static std::string Decode(const std::string &s); +}; + +} // namespace base64 diff --git a/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h b/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h new file mode 100644 index 00000000..37770cb7 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/include/mediadrm_metrics.h @@ -0,0 +1,15 @@ +// 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 "mediadrm_metrics.pb.h" + +namespace mediadrm_metrics { +void FormatDrmFrameworkMetrics( + const android::drm_metrics::DrmFrameworkMetrics& metrics, + std::string& result); +}; diff --git a/libwvdrmengine/tools/metrics_dump/include/wv_metrics.h b/libwvdrmengine/tools/metrics_dump/include/wv_metrics.h new file mode 100644 index 00000000..740affa1 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/include/wv_metrics.h @@ -0,0 +1,14 @@ +// 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 widevine protobuf metrics + +#include + +#include "metrics.pb.h" + +namespace wv_metrics { +void FormatWvCdmMetrics(const drm_metrics::WvCdmMetrics& metrics, + std::string& result); +}; diff --git a/libwvdrmengine/tools/metrics_dump/proto/mediadrm_metrics.proto b/libwvdrmengine/tools/metrics_dump/proto/mediadrm_metrics.proto new file mode 100644 index 00000000..11728d34 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/proto/mediadrm_metrics.proto @@ -0,0 +1,111 @@ +/* + * 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 new file mode 100644 index 00000000..680d35e6 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/proto/wv_metrics.proto @@ -0,0 +1,219 @@ +// 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 new file mode 100644 index 00000000..722a6c21 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/src/base64decode.cpp @@ -0,0 +1,89 @@ +// 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. +// +// simple base64 decoder + +#include +#include +#include + +#include "base64decode.h" + +namespace base64 { + +using namespace std; + +string Base64::Decode(const string &encoded) { + string s = encoded; + + while (s.size() % 4 != 0) { + s.append("="); + } + + size_t n = s.size(); + + size_t padding = 0; + if (n >= 1 && s[n - 1] == '=') { + padding = 1; + + if (n >= 2 && s[n - 2] == '=') { + padding = 2; + + if (n >= 3 && s[n - 3] == '=') { + padding = 3; + } + } + } + + // We divide first to avoid overflow. It's OK to do this because we + // already made sure that n % 4 == 0. + size_t outLen = (n / 4) * 3 - padding; + + std::unique_ptr buffer(new uint8_t[outLen]); + if (!buffer) { + return ""; + } + uint8_t *out = buffer.get(); + size_t j = 0; + uint32_t accum = 0; + for (size_t i = 0; i < n; ++i) { + char c = s[i]; + unsigned value; + if (c >= 'A' && c <= 'Z') { + value = c - 'A'; + } else if (c >= 'a' && c <= 'z') { + value = 26 + c - 'a'; + } else if (c >= '0' && c <= '9') { + value = 52 + c - '0'; + } else if (c == '+' || c == '-') { + value = 62; + } else if (c == '/' || c == '_') { + value = 63; + } else { + if (c != '=') { + std::cerr << "unexpected character in base64 decode:" << c << std::endl; + } + value = 0; + } + + accum = (accum << 6) | value; + + if (((i + 1) % 4) == 0) { + if (j < outLen) { + out[j++] = (accum >> 16); + } + if (j < outLen) { + out[j++] = (accum >> 8) & 0xff; + } + if (j < outLen) { + out[j++] = accum & 0xff; + } + + accum = 0; + } + } + return string((char *)buffer.get(), outLen); +} + +} // namespace base64 diff --git a/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp b/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp new file mode 100644 index 00000000..e074d82a --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/src/mediadrm_metrics.cpp @@ -0,0 +1,173 @@ +// 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 diff --git a/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp b/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp new file mode 100644 index 00000000..73074714 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/src/metrics_dump.cpp @@ -0,0 +1,201 @@ +// 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 metric output from |adb shell dumpsys media.metrics| + +#include +#include +#include +#include +#include +#include + +#include "base64decode.h" +#include "mediadrm_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; + +string selected_one; +std::vector excluded_ones; + +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); + + // handle specific package and component selection + if (selected_one.size() && package != selected_one && + component != selected_one) { + return; + } + if (std::find(excluded_ones.begin(), excluded_ones.end(), package) != + excluded_ones.end()) { + return; + } + if (std::find(excluded_ones.begin(), excluded_ones.end(), 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; + cout << " " + << "APK PACKAGE -> METRICS COMPONENT" << endl; + cout << " " << package << " -> " << component << " | uid:" << uid + << " pid:" << 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") { + string decoded = Base64::Decode(value); + if (component == "drm.vendor.Google.WidevineCDM") { + drm_metrics::WvCdmMetrics metrics; + if (!metrics.ParseFromString(decoded)) { + cerr << "failed to parse proto string" << endl; + } else { + string result; + FormatWvCdmMetrics(metrics, result); + cout << endl << result << endl; + } + } else { + android::drm_metrics::DrmFrameworkMetrics metrics; + if (!metrics.ParseFromString(decoded)) { + cerr << "failed to parse proto string" << endl; + } else { + string result; + FormatDrmFrameworkMetrics(metrics, result); + cout << endl << result << endl; + } + } + } else { + cout << " " << parameter << ": " << 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 usage() { + 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(-1); +} + +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; + while (i < argc) { + string arg = argv[i]; + if (arg == "--help") { + usage(); + } 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") { + metrics_dump::excluded_ones.push_back(argv[++i]); + } else if (arg == "--select") { + metrics_dump::selected_one = argv[++i]; + } else { + usage(); + } + } + i++; + } + if (i == argc) { + metrics_dump::process_metrics(std::cin); + } + return 0; +} diff --git a/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp b/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp new file mode 100644 index 00000000..208bdc64 --- /dev/null +++ b/libwvdrmengine/tools/metrics_dump/src/wv_metrics.cpp @@ -0,0 +1,415 @@ +// 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 widevine protobuf metrics + +#include +#include +#include +#include +#include + +#include "metrics.pb.h" +#include "OEMCryptoCENC.h" +#include "test_printers.h" +#include "wv_cdm_types.h" + +namespace wv_metrics { + +using namespace drm_metrics; +using std::string; +using std::to_string; + +const string kIndentPerLine = " "; + +string FormatCdmErrorTranslation(int error_code) { + std::stringstream os; + os << static_cast(error_code); + return " " + os.str(); +} + +string FormatOEMCryptoResult(int oemcrypto_result) { + std::stringstream os; + os << static_cast(oemcrypto_result); + return " " + os.str(); +} + +string FormatOEMCryptoInitializeMode(const ValueMetric& vm) { + std::map translations = { + {0, "USING_IN_APP"}, + {1, "FORCING_L3"}, + {2, "USING_L3_NO_L1_LIBRARY_PATH"}, + {3, "USING_L3_L1_OPEN_FAILED"}, + {4, "USING_L3_L1_LOAD_FAILED"}, + {5, "USING_L3_COULD_NOT_INITIALIZE_L1"}, + {6, "USING_L3_WRONG_L1_VERSION"}, + {7, "USING_L1_WITH_KEYBOX"}, + {8, "USING_L1_WITH_CERTIFICATE"}, + {9, "USING_L1_CERTIFICATE_MIX"}, + {10, "USING_L3_BAD_KEYBOX"}, + {11, "USING_L3_COULD_NOT_OPEN_FACTORY_KEYBOX"}, + {12, "USING_L3_COULD_NOT_INSTALL_KEYBOX"}, + {13, "USING_L1_INSTALLED_KEYBOX"}, + {14, "USING_L3_INVALID_L1"}, + {15, "USING_L1_WITH_PROVISIONING_3_0"}, + {16, "L3_INITIALIZATION_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"}}; + return translations[vm.int_value()]; +} + +string FormatOEMCryptoProvisioningMethod(const ValueMetric& vm) { + std::map translations = {{0, "PROVISIONING_ERROR"}, + {1, "DRM_CERTIFICATE"}, + {2, "KEYBOX"}, + {3, "OEM_CERTIFICATE"}}; + return translations[vm.int_value()]; +} + +string FormatAttributes(const Attributes& attributes) { + string result; + if (attributes.has_error_code()) { + result.append("error_code:"); + result.append(to_string(attributes.error_code())); + result.append(FormatCdmErrorTranslation(attributes.error_code())); + } + if (attributes.has_error_code_bool()) { + if (result.size()) result.append(","); + result.append("success:"); + result.append(attributes.error_code_bool() ? "true" : "false"); + } + if (attributes.has_cdm_security_level()) { + if (result.size()) result.append(","); + result.append("cdm_security_level:"); + result.append(to_string(attributes.cdm_security_level())); + } + if (attributes.has_security_level()) { + if (result.size()) result.append(","); + result.append("security_level:"); + result.append(to_string(attributes.security_level())); + } + if (attributes.has_length()) { + if (result.size()) result.append(","); + result.append("length:"); + result.append(to_string(attributes.length())); + } + if (attributes.has_encryption_algorithm()) { + if (result.size()) result.append(","); + result.append("encryption_algorithm:"); + result.append(to_string(attributes.encryption_algorithm())); + } + if (attributes.has_signing_algorithm()) { + if (result.size()) result.append(","); + result.append("signing_algorithm:"); + result.append(to_string(attributes.signing_algorithm())); + } + if (attributes.has_oem_crypto_result()) { + if (result.size()) result.append(","); + result.append("oemcrypto_result:"); + result.append(to_string(attributes.oem_crypto_result())); + result.append(FormatOEMCryptoResult(attributes.oem_crypto_result())); + } + 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 (attributes.has_key_request_type()) { + if (result.size()) result.append(","); + result.append("key_request_type:"); + result.append(to_string(attributes.key_request_type())); + } + if (result.size()) { + return string(" {") + result + "}"; + } else { + return ""; + } +} + +string FormatCounterMetric(const CounterMetric& 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 DistributionMetric& dm) { + string result; + 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; +} + +string FormatValueMetric(const ValueMetric& vm) { + string result; + if (vm.has_error_code()) { + result.append("error(" + to_string(vm.error_code())); + result.append(FormatCdmErrorTranslation(vm.error_code())); + result.append(")"); + } + if (vm.has_int_value()) { + result.append(to_string(vm.int_value())); + } + if (vm.has_double_value()) { + std::ostringstream buffer; + buffer << vm.double_value(); + result.append(buffer.str()); + } + if (vm.has_string_value()) { + result.append("\""); + result.append(vm.string_value()); + result.append("\""); + } + 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(FormatCounterMetric(metrics.NAME(0)) + "\n"); \ + } else { \ + for (int i = 0; i < metrics.NAME##_size(); i++) { \ + result.append(INDENT + #NAME "[" + to_string(i) + "]: "); \ + result.append(FormatCounterMetric(metrics.NAME(i)) + "\n"); \ + } \ + } + +#define FORMAT_OPTIONAL_VALUE(NAME, INDENT) \ + if (metrics.has_##NAME()) { \ + result.append(INDENT + #NAME ": " + FormatValueMetric(metrics.NAME()) + \ + "\n"); \ + } + +#define FORMAT_OPTIONAL_INITIALIZATION_MODE(NAME, INDENT) \ + if (metrics.has_##NAME()) { \ + result.append(INDENT + #NAME ": "); \ + result.append(FormatOEMCryptoInitializeMode(metrics.NAME()) + "\n"); \ + } + +#define FORMAT_OPTIONAL_HDCP_CAPABILITY(NAME, INDENT) \ + if (metrics.has_##NAME()) { \ + result.append(INDENT + #NAME ": "); \ + result.append(FormatOEMCryptoHdcpCapability(metrics.NAME()) + "\n"); \ + } + +#define FORMAT_OPTIONAL_PROVISIONING_METHOD(NAME, INDENT) \ + if (metrics.has_##NAME()) { \ + result.append(INDENT + #NAME ": "); \ + result.append(FormatOEMCryptoProvisioningMethod(metrics.NAME()) + "\n"); \ + } + +#define FORMAT_OPTIONAL_CRYPTO_METRICS(NAME, INDENT) \ + if (metrics.has_##NAME()) { \ + FormatCryptoMetrics(metrics.NAME(), INDENT + kIndentPerLine, result); \ + } + +void FormatCryptoMetrics(const WvCdmMetrics_CryptoMetrics metrics, + const string& indent, string& result) { + // Crypto Session Metrics. + FORMAT_OPTIONAL_VALUE(crypto_session_security_level, indent); + FORMAT_REPEATED_COUNTER(crypto_session_delete_all_usage_reports, indent); + FORMAT_REPEATED_COUNTER(crypto_session_delete_multiple_usage_information, + indent); + FORMAT_REPEATED_DISTRIBUTION(crypto_session_generic_decrypt_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(crypto_session_generic_encrypt_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(crypto_session_generic_sign_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(crypto_session_generic_verify_time_us, indent); + FORMAT_REPEATED_COUNTER(crypto_session_get_device_unique_id, indent); + FORMAT_REPEATED_COUNTER(crypto_session_get_token, indent); + FORMAT_OPTIONAL_VALUE(crypto_session_life_span, indent); + FORMAT_REPEATED_DISTRIBUTION( + crypto_session_load_certificate_private_key_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(crypto_session_open_time_us, indent); + FORMAT_OPTIONAL_VALUE(crypto_session_system_id, indent); + FORMAT_REPEATED_DISTRIBUTION(crypto_session_update_usage_information_time_us, + indent); + FORMAT_OPTIONAL_VALUE(crypto_session_usage_information_support, indent); + + // Usage Table Metrics + FORMAT_OPTIONAL_VALUE(usage_table_header_initial_size, indent); + FORMAT_REPEATED_COUNTER(usage_table_header_add_entry, indent); + FORMAT_REPEATED_COUNTER(usage_table_header_delete_entry, indent); + FORMAT_REPEATED_DISTRIBUTION(usage_table_header_update_entry_time_us, indent); + FORMAT_REPEATED_COUNTER(usage_table_header_load_entry, indent); + + // OemCrypto metrics. + FORMAT_OPTIONAL_VALUE(oemcrypto_api_version, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_close_session, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_copy_buffer_time_us, indent); + FORMAT_OPTIONAL_HDCP_CAPABILITY(oemcrypto_current_hdcp_capability, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_deactivate_usage_entry, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_decrypt_cenc_time_us, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_delete_usage_entry, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_delete_usage_table, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_derive_keys_from_session_key_time_us, + indent); + FORMAT_REPEATED_COUNTER(oemcrypto_force_delete_usage_entry, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generate_derived_keys_time_us, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_generate_nonce, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generate_rsa_signature_time_us, + indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generate_signature_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generic_decrypt_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generic_encrypt_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generic_sign_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_generic_verify_time_us, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_get_device_id, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_get_key_data_time_us, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_get_oem_public_certificate, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_get_random, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_initialize_time_us, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_is_anti_rollback_hw_present, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_is_keybox_valid, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_device_rsa_key_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_entitled_keys_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_load_keys_time_us, indent); + FORMAT_OPTIONAL_HDCP_CAPABILITY(oemcrypto_max_hdcp_capability, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_max_number_of_sessions, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_number_of_open_sessions, indent); + FORMAT_OPTIONAL_PROVISIONING_METHOD(oemcrypto_provisioning_method, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_refresh_keys_time_us, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_report_usage, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_rewrap_device_rsa_key_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_rewrap_device_rsa_key_30_time_us, + indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_security_patch_level, indent); + FORMAT_REPEATED_DISTRIBUTION(oemcrypto_select_key_time_us, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_usage_table_support, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_update_usage_table, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_update_usage_entry, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_create_usage_table_header, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_load_usage_table_header, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_shrink_usage_table_header, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_create_new_usage_entry, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_load_usage_entry, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_move_entry, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_create_old_usage_entry, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_copy_old_usage_entry, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_set_sandbox, indent); + FORMAT_REPEATED_COUNTER(oemcrypto_set_decrypt_hash, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_resource_rating_tier, indent); +} + +void FormatSessionMetrics(const 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); + FORMAT_REPEATED_DISTRIBUTION(cdm_session_renew_key_time_us, indent); + FORMAT_REPEATED_COUNTER(cdm_session_restore_offline_session, indent); + FORMAT_REPEATED_COUNTER(cdm_session_restore_usage_session, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_session_license_request_latency_ms, indent); + FORMAT_OPTIONAL_VALUE(oemcrypto_build_info, indent); + FORMAT_OPTIONAL_VALUE(license_sdk_version, indent); + FORMAT_OPTIONAL_VALUE(license_service_version, indent); +} + +void FormatEngineMetrics(const WvCdmMetrics_EngineMetrics& metrics, + const string& indent, string& result) { + FORMAT_OPTIONAL_CRYPTO_METRICS(crypto_metrics, indent); + + // OEMCrypto Initialize 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); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_add_key_time_us, indent); + FORMAT_OPTIONAL_VALUE(cdm_engine_cdm_version, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_close_session, indent); + FORMAT_OPTIONAL_VALUE(cdm_engine_creation_time_millis, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_decrypt_time_us, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_find_session_for_key, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_generate_key_request_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_get_provisioning_request_time_us, + indent); + FORMAT_REPEATED_COUNTER(cdm_engine_get_secure_stop_ids, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_get_usage_info_time_us, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_handle_provisioning_response_time_us, + indent); + FORMAT_OPTIONAL_VALUE(cdm_engine_life_span_ms, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_open_key_set_session, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_open_session, indent); + FORMAT_REPEATED_DISTRIBUTION(cdm_engine_query_key_status_time_us, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_release_all_usage_info, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_release_usage_info, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_remove_all_usage_info, indent); + FORMAT_REPEATED_COUNTER(cdm_engine_remove_keys, indent); + 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); +} + +void FormatWvCdmMetrics(const WvCdmMetrics& metrics, string& result) { + string indent = kIndentPerLine; + string next_indent = indent + kIndentPerLine; + + result.append("engine_metrics\n"); + if (metrics.has_engine_metrics()) { + FormatEngineMetrics(metrics.engine_metrics(), indent, result); + } + result.append("session_metrics\n"); + for (int i = 0; i < metrics.session_metrics_size(); i++) { + result.append(indent + "session[" + to_string(i) + "]\n"); + FormatSessionMetrics(metrics.session_metrics(i), next_indent, result); + } +} + +}; // namespace wv_metrics