diff --git a/libwvdrmengine/Android.mk b/libwvdrmengine/Android.mk index 96366d35..c68752b5 100644 --- a/libwvdrmengine/Android.mk +++ b/libwvdrmengine/Android.mk @@ -202,6 +202,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := \ src/WVCDMSingleton.cpp \ src/WVUUID.cpp \ + src_hidl/wv_metrics.cpp \ src_hidl/WVCreatePluginFactories.cpp \ src_hidl/WVCryptoFactory.cpp \ src_hidl/WVDrmFactory.cpp \ diff --git a/libwvdrmengine/cdm/include/wv_content_decryption_module.h b/libwvdrmengine/cdm/include/wv_content_decryption_module.h index c1756470..217aca6b 100644 --- a/libwvdrmengine/cdm/include/wv_content_decryption_module.h +++ b/libwvdrmengine/cdm/include/wv_content_decryption_module.h @@ -149,6 +149,13 @@ class WvContentDecryptionModule : public android::RefBase, public TimerHandler { virtual CdmResponseType GetMetrics(const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics); + // Fill the metrics parameter with the metrics data for all the CdmEngine + // associated with the given CdmIdentifiers. If there are no CdmEngine + // instances, this will return an error. + virtual CdmResponseType GetMetrics( + std::vector* metrics, + bool* full_list_returned); + // Closes the CdmEngine and sessions associated with the given CdmIdentifier. virtual CdmResponseType CloseCdm(const CdmIdentifier& identifier); diff --git a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp index 96314de6..8a447148 100644 --- a/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp +++ b/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp @@ -378,6 +378,32 @@ bool WvContentDecryptionModule::IsValidServiceCertificate( return cert.has_certificate(); } +CdmResponseType WvContentDecryptionModule::GetMetrics( + std::vector* metrics, bool* full_list_returned) { + if (!metrics || !full_list_returned) { + return PARAMETER_NULL; + } + for (auto& key_value_pair : cdms_) { + drm_metrics::WvCdmMetrics metric; + CdmResponseType status = GetMetrics(key_value_pair.first, &metric); + if (status == NO_ERROR) { + metrics->push_back(metric); + } else { + LOGD("GetMetrics call failed: cdm identifier=%u, error=%d", + key_value_pair.first.unique_id, status); + } + } + // With no streaming activities, cdms_ size would be zero, + // treat it as a non full list in that case. + *full_list_returned = !cdms_.empty() && metrics->size() == cdms_.size(); + + // We only return error if no metrics is returned when cdms_ is not empty. + // - metrics && cdms_ sizes can both be zero, returns NO_ERROR + // - metrics size <= cdms_, returns NO_ERROR + // - metrics is empty, but cdms_ is not, returns UNKNOWN_ERROR + return (metrics->empty() && !cdms_.empty()) ? UNKNOWN_ERROR : NO_ERROR; +} + CdmResponseType WvContentDecryptionModule::GetMetrics( const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) { if (!metrics) { diff --git a/libwvdrmengine/include_hidl/WVDrmFactory.h b/libwvdrmengine/include_hidl/WVDrmFactory.h index 401c6d3b..427d8788 100644 --- a/libwvdrmengine/include_hidl/WVDrmFactory.h +++ b/libwvdrmengine/include_hidl/WVDrmFactory.h @@ -24,21 +24,18 @@ struct WVDrmFactory : public IDrmFactory { WVDrmFactory() {} virtual ~WVDrmFactory() {} - Return isCryptoSchemeSupported(const hidl_array& uuid) - override; + Return isCryptoSchemeSupported( + const hidl_array& uuid) override; Return isCryptoSchemeSupported_1_2(const hidl_array& uuid, const hidl_string& mimeType, - SecurityLevel level) - override; + SecurityLevel level) override; - Return isContentTypeSupported(const hidl_string &mimeType) - override; + Return isContentTypeSupported(const hidl_string& mimeType) override; - Return createPlugin( - const hidl_array& uuid, - const hidl_string& appPackageName, - createPlugin_cb _hidl_cb) override; + Return createPlugin(const hidl_array& uuid, + const hidl_string& appPackageName, + createPlugin_cb _hidl_cb) override; Return getSupportedCryptoSchemes( getSupportedCryptoSchemes_cb _hidl_cb) override; @@ -54,6 +51,7 @@ struct WVDrmFactory : public IDrmFactory { static bool isBlankAppPackageNameAllowed(); static int32_t firstApiLevel(); static std::string stringToHex(const std::string& input); + static void printCdmMetrics(FILE* out); static void printCdmProperties(FILE* out); friend class WVDrmFactoryTestPeer; @@ -67,4 +65,4 @@ extern "C" IDrmFactory* HIDL_FETCH_IDrmFactory(const char* name); } // namespace hardware } // namespace wvdrm -#endif // WV_DRM_FACTORY_H_ +#endif // WV_DRM_FACTORY_H_ diff --git a/libwvdrmengine/include_hidl/wv_metrics.h b/libwvdrmengine/include_hidl/wv_metrics.h new file mode 100644 index 00000000..d559c87e --- /dev/null +++ b/libwvdrmengine/include_hidl/wv_metrics.h @@ -0,0 +1,14 @@ +// Copyright 2020 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/src_hidl/WVDrmFactory.cpp b/libwvdrmengine/src_hidl/WVDrmFactory.cpp index d2e7035b..b4ecfacd 100644 --- a/libwvdrmengine/src_hidl/WVDrmFactory.cpp +++ b/libwvdrmengine/src_hidl/WVDrmFactory.cpp @@ -19,6 +19,7 @@ #include "cutils/properties.h" #include "wv_cdm_constants.h" #include "wv_content_decryption_module.h" +#include "wv_metrics.h" namespace wvdrm { namespace hardware { @@ -148,6 +149,39 @@ std::string WVDrmFactory::stringToHex(const std::string& input) { return output; } +void WVDrmFactory::printCdmMetrics(FILE* out) { + fprintf(out, "\n**** Widevine Cdm Metrics ****\n"); + + // 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; + + sp cdm(getCDM()); + + std::vector metrics; + bool full_list_returned = true; + wvcdm::CdmResponseType result = + cdm->GetMetrics(&metrics, &full_list_returned); + if (metrics.empty()) { + fprintf(out, + "Metrics not available, please retry while streaming a video\n"); + } else if (!full_list_returned) { + fprintf(out, + "Not all metrics are returned due to some GetMetric error, " + "please check logcat for possible GetMetric errors.\n"); + } + if (result == wvcdm::NO_ERROR) { + for (auto& metric : metrics) { + fprintf(out, "*** Metric size=%zu\n", metric.DebugString().size()); + std::string formatted; + wv_metrics::FormatWvCdmMetrics(metric, formatted); + fprintf(out, "%s\n", formatted.c_str()); + } + } else { + fprintf(out, "GetMetrics failed, error=%d\n", result); + } +} + void WVDrmFactory::printCdmProperties(FILE* out) { fprintf(out, "\n**** Widevine CDM properties ****\n"); @@ -155,7 +189,7 @@ void WVDrmFactory::printCdmProperties(FILE* out) { const bool isLevel1 = cdm->IsSecurityLevelSupported(wvcdm::CdmSecurityLevel::kSecurityLevelL1); - fprintf(out, "current security level: [%s]\n", isLevel1 ? "L1" : "L3"); + fprintf(out, "default security level: [%s]\n", isLevel1 ? "L1" : "L3"); std::map cdmProperties = { {"version- Widevine CDM:", wvcdm::QUERY_KEY_WVCDM_VERSION}, @@ -165,7 +199,7 @@ void WVDrmFactory::printCdmProperties(FILE* out) { {"version(minor)- OEM Crypto API:", wvcdm::QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION}, {"id- device:", wvcdm::QUERY_KEY_DEVICE_ID}, - {"id- systen:", wvcdm::QUERY_KEY_SYSTEM_ID}, + {"id- system:", wvcdm::QUERY_KEY_SYSTEM_ID}, {"renewal server url:", wvcdm::QUERY_KEY_RENEWAL_SERVER_URL}, {"hdcp level- max:", wvcdm::QUERY_KEY_MAX_HDCP_LEVEL}, {"hdcp level- current:", wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL}, @@ -192,14 +226,40 @@ void WVDrmFactory::printCdmProperties(FILE* out) { } Return WVDrmFactory::debug(const hidl_handle& fd, - const hidl_vec& /*args*/) { + const hidl_vec& args) { if (fd.getNativeHandle() == nullptr || fd->numFds < 1) { ALOGE("%s: missing fd for writing", __FUNCTION__); return Void(); } FILE* out = fdopen(dup(fd->data[0]), "w"); - printCdmProperties(out); + fprintf(out, "\nDefault to print all info if no arguments are used.\n"); + fprintf(out, "Optional arguments are:\n"); + fprintf(out, "\tm:cdm metrics | p:cdm properties\n"); + fprintf(out, + "Usage: adb shell lshal debug " + "android.hardware.drm@1.3::IDrmFactory/widevine [m|p]\n"); + + bool dumpCdmProperties, dumpCdmMetrics = false; + if (args.size() == 0) { + // default to print all info if no arguments are given + dumpCdmProperties = dumpCdmMetrics = true; + } else { + for (auto& str : args) { + fprintf(out, "args: %s\n", str.c_str()); + std::string option = str.c_str(); + if (option.find('m') != std::string::npos || + option.find('M') != std::string::npos) { + dumpCdmMetrics = true; + } + if (option.find('p') != std::string::npos || + option.find('P') != std::string::npos) { + dumpCdmProperties = true; + } + } + } + if (dumpCdmMetrics) printCdmMetrics(out); + if (dumpCdmProperties) printCdmProperties(out); fclose(out); return Void(); diff --git a/libwvdrmengine/src_hidl/wv_metrics.cpp b/libwvdrmengine/src_hidl/wv_metrics.cpp new file mode 100644 index 00000000..50840dd3 --- /dev/null +++ b/libwvdrmengine/src_hidl/wv_metrics.cpp @@ -0,0 +1,448 @@ +// Copyright 2020 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 "wv_metrics.h" + +#include +#include +#include +#include +#include + +#include "OEMCryptoCENC.h" +#include "wv_cdm_types.h" + +using namespace drm_metrics; +using std::string; +using std::to_string; + +namespace { +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_GENERAL_FAILED"}, + {17, "L3_INITIALIZATION_RNG_FAILED"}, + {18, "L3_INITIALIZATION_SAVE_DEVICE_KEYS_FAILED"}, + {19, "L3_INITIALIZATION_READ_DEVICE_KEYS_FAILED"}, + {20, "L3_INITIALIZATION_VERIFY_DEVIE_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"}, {5, "HDCP_V2_3"}, + {0xff, "NO_DIGITAL_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 (attributes.has_license_type()) { + if (result.size()) result.append(","); + result.append("license_type:"); + result.append(to_string(attributes.license_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); + + // 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); + + // |usage_table_header_lru_evicted_entry_type| refers to the enumeration + // CdmUsageEntryStorageType in wv_cdm_types.h. + 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); + 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); + + // Oemcrypto V16 metrics below + 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) { + 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); +} +} // anonymous namespace + +namespace wv_metrics { +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