diff --git a/libwvdrmengine/Android.mk b/libwvdrmengine/Android.mk index 3796add5..335d7417 100644 --- a/libwvdrmengine/Android.mk +++ b/libwvdrmengine/Android.mk @@ -74,6 +74,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/include \ frameworks/native/include \ vendor/widevine/libwvdrmengine/cdm/core/include \ + vendor/widevine/libwvdrmengine/cdm/profiler/include \ vendor/widevine/libwvdrmengine/cdm/include \ vendor/widevine/libwvdrmengine/include \ vendor/widevine/libwvdrmengine/mediacrypto/include \ diff --git a/libwvdrmengine/build_and_run_all_unit_tests.sh b/libwvdrmengine/build_and_run_all_unit_tests.sh index 2dc63bee..e0dd491d 100755 --- a/libwvdrmengine/build_and_run_all_unit_tests.sh +++ b/libwvdrmengine/build_and_run_all_unit_tests.sh @@ -61,6 +61,8 @@ adb push $OUT/system/bin/device_files_unittest /system/bin adb push $OUT/system/bin/timer_unittest /system/bin adb push $OUT/system/bin/libwvdrmengine_test /system/bin adb push $OUT/system/bin/buffer_reader_test /system/bin +adb push $OUT/system/bin/circular_buffer_test /system/bin +adb push $OUT/system/bin/entry_writer_test /system/bin adb install -r $OUT/system/app/MediaDrmAPITest/MediaDrmAPITest.apk cd $ANDROID_BUILD_TOP/vendor/widevine/libwvdrmengine diff --git a/libwvdrmengine/cdm/Android.mk b/libwvdrmengine/cdm/Android.mk index 38663a6e..923ed31e 100644 --- a/libwvdrmengine/cdm/Android.mk +++ b/libwvdrmengine/cdm/Android.mk @@ -5,6 +5,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_C_INCLUDES := \ + vendor/widevine/libwvdrmengine/cdm/profiler/include \ vendor/widevine/libwvdrmengine/cdm/core/include \ vendor/widevine/libwvdrmengine/cdm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ @@ -17,6 +18,8 @@ LOCAL_STATIC_LIBRARIES := libcdm_protos libcrypto_static SRC_DIR := src CORE_SRC_DIR := core/src +PROFILER_SRC_DIR := profiler/src + LOCAL_SRC_FILES := \ $(CORE_SRC_DIR)/buffer_reader.cpp \ $(CORE_SRC_DIR)/cdm_engine.cpp \ @@ -30,7 +33,12 @@ LOCAL_SRC_FILES := \ $(CORE_SRC_DIR)/oemcrypto_adapter_dynamic.cpp \ $(CORE_SRC_DIR)/policy_engine.cpp \ $(CORE_SRC_DIR)/privacy_crypto_openssl.cpp \ - $(SRC_DIR)/wv_content_decryption_module.cpp + $(SRC_DIR)/wv_content_decryption_module.cpp \ + $(PROFILER_SRC_DIR)/circular_buffer.cpp \ + $(PROFILER_SRC_DIR)/entry_writer.cpp \ + $(PROFILER_SRC_DIR)/profiled_scope.cpp \ + $(PROFILER_SRC_DIR)/stats.cpp \ + $(PROFILER_SRC_DIR)/profiler_session.cpp LOCAL_MODULE := libcdm LOCAL_MODULE_TAGS := optional diff --git a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp index 064a74f5..7272f651 100644 --- a/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp +++ b/libwvdrmengine/cdm/core/src/oemcrypto_adapter_dynamic.cpp @@ -22,6 +22,8 @@ #include "level3.h" #include "lock.h" #include "log.h" +#include "profiled_scope.h" +#include "profiler_session.h" #include "properties.h" using namespace wvoec3; @@ -489,6 +491,9 @@ class Adapter { OEMCryptoResult OpenSession(OEMCrypto_SESSION* session, wvcdm::SecurityLevel level) { + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_OPEN_SESSION); + LevelSession new_session; OEMCryptoResult result; if (level == kLevelDefault && level1_valid_) { @@ -508,10 +513,18 @@ class Adapter { } session_map_[*session] = new_session; } + + if (result == OEMCrypto_SUCCESS) { + wvcdm::oemprofiler::ProfilerSession::Open(static_cast(*session)); + } + return result; } OEMCryptoResult CloseSession(OEMCrypto_SESSION session) { + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_CLOSE_SESSION); + wvcdm::AutoLock auto_lock(session_map_lock_); map_iterator pair = session_map_.find(session); if (pair == session_map_.end()) { @@ -520,6 +533,11 @@ class Adapter { OEMCryptoResult result = pair->second.fcn->CloseSession(pair->second.session); session_map_.erase(pair); + + if (result == OEMCrypto_SUCCESS) { + wvcdm::oemprofiler::ProfilerSession::Close(static_cast(session)); + } + return result; } @@ -552,6 +570,7 @@ namespace wvcdm { OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session, SecurityLevel level) { + if (!kAdapter) return OEMCrypto_ERROR_OPEN_SESSION_FAILED; return kAdapter->OpenSession(session, level); } @@ -559,6 +578,11 @@ OEMCryptoResult OEMCrypto_OpenSession(OEMCrypto_SESSION* session, OEMCryptoResult OEMCrypto_CopyBuffer( SecurityLevel level, const uint8_t* data_addr, size_t data_length, OEMCrypto_DestBufferDesc* out_buffer, uint8_t subsample_flags) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_COPY_BUFFER); + + ps.meta_data_.WriteVLV(static_cast(data_length)); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -569,6 +593,9 @@ OEMCryptoResult OEMCrypto_CopyBuffer( OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, size_t keyBoxLength, SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_INSTALL_KEYBOX); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -576,6 +603,9 @@ OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, } OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_IS_KEYBOX_VALID); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -584,6 +614,9 @@ OEMCryptoResult OEMCrypto_IsKeyboxValid(SecurityLevel level) { OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength, SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_GET_DEVICE_ID); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -592,6 +625,9 @@ OEMCryptoResult OEMCrypto_GetDeviceID(uint8_t* deviceID, size_t* idLength, OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength, SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_GET_KEY_DATA); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -599,6 +635,9 @@ OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, size_t* keyDataLength, } uint32_t OEMCrypto_APIVersion(SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_API_VERSION); + if (!kAdapter) return 0; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return 0; @@ -606,6 +645,9 @@ uint32_t OEMCrypto_APIVersion(SecurityLevel level) { } uint8_t OEMCrypto_Security_Patch_Level(SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_SECURITY_PATCH_LEVEL); + if (!kAdapter) return 0; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return 0; @@ -614,6 +656,9 @@ uint8_t OEMCrypto_Security_Patch_Level(SecurityLevel level) { } const char* OEMCrypto_SecurityLevel(SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_SECURITY_LEVEL); + if (!kAdapter) return ""; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return ""; @@ -623,6 +668,9 @@ const char* OEMCrypto_SecurityLevel(SecurityLevel level) { OEMCryptoResult OEMCrypto_GetHDCPCapability( SecurityLevel level, OEMCrypto_HDCP_Capability* current, OEMCrypto_HDCP_Capability* maximum) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_GET_HDCP_CAPABILITIY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_NOT_IMPLEMENTED; @@ -641,6 +689,9 @@ OEMCryptoResult OEMCrypto_GetHDCPCapability( } bool OEMCrypto_SupportsUsageTable(SecurityLevel level) { + + oemprofiler::ProfiledScope ps(oemprofiler::OEM_FUNCTION_SUPPORTS_USAGE_TABLE); + if (!kAdapter) return false; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return false; @@ -649,6 +700,10 @@ bool OEMCrypto_SupportsUsageTable(SecurityLevel level) { } bool OEMCrypto_IsAntiRollbackHwPresent(SecurityLevel level) { + + oemprofiler::ProfiledScope ps( + oemprofiler::OEM_FUNCTION_IS_ANTI_ROLLBACK_HW_PRESENT); + if (!kAdapter) return false; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return false; @@ -658,6 +713,10 @@ bool OEMCrypto_IsAntiRollbackHwPresent(SecurityLevel level) { OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(SecurityLevel level, size_t* count) { + + oemprofiler::ProfiledScope ps( + oemprofiler::OEM_FUNCTION_GET_NUMBER_OF_OPEN_SESSIONS); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -667,6 +726,10 @@ OEMCryptoResult OEMCrypto_GetNumberOfOpenSessions(SecurityLevel level, OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel level, size_t* maximum) { + + oemprofiler::ProfiledScope ps( + oemprofiler::OEM_FUNCTION_GET_MAX_NUMBER_OF_SESSIONS); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(level); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -676,6 +739,16 @@ OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(SecurityLevel level, } // namespace wvcdm extern "C" OEMCryptoResult OEMCrypto_Initialize(void) { + + if (wvcdm::oemprofiler::ProfilerSession::Find( + wvcdm::oemprofiler::ProfiledScope::kGlobalSID) != NULL) { + wvcdm::oemprofiler::ProfilerSession::Close( + wvcdm::oemprofiler::ProfiledScope::kGlobalSID); + } + + wvcdm::oemprofiler::ProfilerSession::Open( + wvcdm::oemprofiler::ProfiledScope::kGlobalSID); + if (kAdapter) { kAdapter->Terminate(); delete kAdapter; @@ -685,6 +758,13 @@ extern "C" OEMCryptoResult OEMCrypto_Initialize(void) { } extern "C" OEMCryptoResult OEMCrypto_Terminate(void) { + + if (wvcdm::oemprofiler::ProfilerSession::Find( + wvcdm::oemprofiler::ProfiledScope::kGlobalSID) != NULL) { + wvcdm::oemprofiler::ProfilerSession::Close( + wvcdm::oemprofiler::ProfiledScope::kGlobalSID); + } + OEMCryptoResult result = OEMCrypto_SUCCESS; if (kAdapter) { result = kAdapter->Terminate(); @@ -707,6 +787,10 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateDerivedKeys( OEMCrypto_SESSION session, const uint8_t* mac_key_context, uint32_t mac_key_context_length, const uint8_t* enc_key_context, uint32_t enc_key_context_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERATE_DERIVED_KEYS); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -717,6 +801,10 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateDerivedKeys( extern "C" OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, uint32_t* nonce) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERATE_NONCE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -726,6 +814,10 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateNonce(OEMCrypto_SESSION session, extern "C" OEMCryptoResult OEMCrypto_GenerateSignature( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERATE_SIGNATURE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -739,6 +831,10 @@ extern "C" OEMCryptoResult OEMCrypto_LoadKeys( const uint8_t* enc_mac_key_iv, const uint8_t* enc_mac_key, size_t num_keys, const OEMCrypto_KeyObject* key_array, const uint8_t* pst, size_t pst_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_LOAD_KEYS); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -779,6 +875,10 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, size_t num_keys, const OEMCrypto_KeyRefreshObject* key_array) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_REFRESH_KEYS); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -789,6 +889,10 @@ extern "C" OEMCryptoResult OEMCrypto_RefreshKeys( extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl( OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length, uint8_t* key_control_block, size_t* key_control_block_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_QUERY_KEY_CONTROL); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -800,6 +904,10 @@ extern "C" OEMCryptoResult OEMCrypto_QueryKeyControl( extern "C" OEMCryptoResult OEMCrypto_SelectKey(const OEMCrypto_SESSION session, const uint8_t* key_id, size_t key_id_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_SELECT_KEY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -812,6 +920,12 @@ extern "C" OEMCryptoResult OEMCrypto_DecryptCENC( OEMCrypto_DestBufferDesc* out_buffer, const OEMCrypto_CENCEncryptPatternDesc* pattern, uint8_t subsample_flags) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_DECRYPT_CENC); + + ps.meta_data_.WriteVLV(static_cast(data_length)); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -839,6 +953,10 @@ extern "C" OEMCryptoResult OEMCrypto_WrapKeybox(const uint8_t* keybox, size_t* wrappedKeyBoxLength, const uint8_t* transportKey, size_t transportKeyLength) { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_WRAP_KEYBOX); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(kLevelDefault); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -852,6 +970,10 @@ extern "C" OEMCryptoResult OEMCrypto_InstallKeybox(const uint8_t* keybox, } extern "C" OEMCryptoResult OEMCrypto_LoadTestKeybox() { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_LOAD_TEST_KEYBOX); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(kLevelDefault); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -875,6 +997,10 @@ extern "C" OEMCryptoResult OEMCrypto_GetKeyData(uint8_t* keyData, extern "C" OEMCryptoResult OEMCrypto_GetRandom(uint8_t* randomData, size_t dataLength) { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_GET_RANDOM); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(kLevelDefault); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -887,6 +1013,10 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( const uint8_t* enc_rsa_key, size_t enc_rsa_key_length, const uint8_t* enc_rsa_key_iv, uint8_t* wrapped_rsa_key, size_t* wrapped_rsa_key_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_REWRAP_DEVICE_RSA_KEY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -899,6 +1029,10 @@ extern "C" OEMCryptoResult OEMCrypto_RewrapDeviceRSAKey( extern "C" OEMCryptoResult OEMCrypto_LoadDeviceRSAKey( OEMCrypto_SESSION session, const uint8_t* wrapped_rsa_key, size_t wrapped_rsa_key_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_LOAD_DEVICE_RSA_KEY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -907,6 +1041,10 @@ extern "C" OEMCryptoResult OEMCrypto_LoadDeviceRSAKey( } extern "C" OEMCryptoResult OEMCrypto_LoadTestRSAKey() { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_LOAD_TEST_RSA_KEY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn = kAdapter->get(kLevelDefault); if (!fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -918,6 +1056,10 @@ extern "C" OEMCryptoResult OEMCrypto_GenerateRSASignature( OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, RSA_Padding_Scheme padding_scheme) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERATE_RSA_SIGNATURE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -936,6 +1078,10 @@ extern "C" OEMCryptoResult OEMCrypto_DeriveKeysFromSessionKey( size_t enc_session_key_length, const uint8_t* mac_key_context, size_t mac_key_context_length, const uint8_t* enc_key_context, size_t enc_key_context_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_DERIVE_KEYS_FROM_SESSION_KEY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -980,6 +1126,10 @@ extern "C" OEMCryptoResult OEMCrypto_GetMaxNumberOfSessions(size_t* maximum) { extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt( OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERIC_ENCRYPT); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -990,6 +1140,10 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Encrypt( extern "C" OEMCryptoResult OEMCrypto_Generic_Decrypt( OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, const uint8_t* iv, OEMCrypto_Algorithm algorithm, uint8_t* out_buffer) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERIC_DECRYPT); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -1003,6 +1157,10 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Sign(OEMCrypto_SESSION session, OEMCrypto_Algorithm algorithm, uint8_t* signature, size_t* signature_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_GENERIC_SIGN); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -1014,6 +1172,10 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Verify( OEMCrypto_SESSION session, const uint8_t* in_buffer, size_t buffer_length, OEMCrypto_Algorithm algorithm, const uint8_t* signature, size_t signature_length) { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_GENERIC_VERIFY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -1022,6 +1184,10 @@ extern "C" OEMCryptoResult OEMCrypto_Generic_Verify( } extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_UPDATE_USAGE_TABLE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault); const FunctionPointers* fcn3 = kAdapter->get(kLevel3); @@ -1033,6 +1199,10 @@ extern "C" OEMCryptoResult OEMCrypto_UpdateUsageTable() { extern "C" OEMCryptoResult OEMCrypto_DeactivateUsageEntry(const uint8_t* pst, size_t pst_length) { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_DEACTIVATE_USAGE_ENTRY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault); const FunctionPointers* fcn3 = kAdapter->get(kLevel3); @@ -1053,6 +1223,10 @@ extern "C" OEMCryptoResult OEMCrypto_ReportUsage(OEMCrypto_SESSION session, size_t pst_length, OEMCrypto_PST_Report* buffer, size_t* buffer_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_REPORT_USAGE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -1068,6 +1242,10 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry( OEMCrypto_SESSION session, const uint8_t* pst, size_t pst_length, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length) { + + wvcdm::oemprofiler::ProfiledScope ps(session, + wvcdm::oemprofiler::OEM_FUNCTION_DELETE_USAGE_ENTRY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; LevelSession pair = kAdapter->get(session); if (!pair.fcn) return OEMCrypto_ERROR_INVALID_SESSION; @@ -1082,6 +1260,10 @@ extern "C" OEMCryptoResult OEMCrypto_DeleteUsageEntry( extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry( const uint8_t* pst, size_t pst_length) { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_FORCE_DELETE_USAGE_ENTRY); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault); const FunctionPointers* fcn3 = kAdapter->get(kLevel3); @@ -1099,6 +1281,10 @@ extern "C" OEMCryptoResult OEMCrypto_ForceDeleteUsageEntry( } extern "C" OEMCryptoResult OEMCrypto_DeleteUsageTable() { + + wvcdm::oemprofiler::ProfiledScope ps( + wvcdm::oemprofiler::OEM_FUNCTION_DELETE_USAGE_TABLE); + if (!kAdapter) return OEMCrypto_ERROR_UNKNOWN_FAILURE; const FunctionPointers* fcn1 = kAdapter->get(kLevelDefault); const FunctionPointers* fcn3 = kAdapter->get(kLevel3); diff --git a/libwvdrmengine/cdm/profiler/include/circular_buffer.h b/libwvdrmengine/cdm/profiler/include/circular_buffer.h new file mode 100644 index 00000000..c8451427 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/include/circular_buffer.h @@ -0,0 +1,62 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#ifndef WVCDM_PROFILER_CIRCULAR_BUFFER_H_ +#define WVCDM_PROFILER_CIRCULAR_BUFFER_H_ + +#include +#include +#include + +namespace wvcdm { +namespace oemprofiler { + +class CircularBuffer { + public: + explicit CircularBuffer(size_t memoryBudget); + + size_t GetFreeSpace() const; + + size_t GetUsedSpace() const; + + // Add a series of bytes to the buffer. Values will remain in + // the buffer until Remove removes them. If there is not enough + // room for the full series, no bytes are written into the buffer. + bool AddU8s(const uint8_t* values, size_t numValues); + + // Add a single byte to the buffer. The value will remain in the + // buffer until Remove removes it. If the buffer is full, the + // byte will not be written into the buffer. + bool AddU8(uint8_t value); + + // Read a series of bytes without removing them. The start of the + // read is from the end (the oldest entry) + offset (toward the newest + // entry). If requested number of bytes is too large, no bytes are read + // and the function returns false. + bool PeekU8s(size_t offset, uint8_t* out, size_t numToRead) const; + + // Read a single byte without removing it. The read byte is at the index + // of the oldest entry + offset (toward the newest entry). If there are + // no bytes in the buffer the function returns false. + bool PeekU8(size_t offset, uint8_t* out) const; + + // Remove the requested number of bytes from the buffer from oldest + // to newest. If there are not enough bytes to remove, nothing is + // removed and the function returns false. + bool Remove(size_t numBytes); + + private: + std::vector buffer_; + + size_t fill_; + size_t head_; + size_t tail_; + + // disallow copy and assign + CircularBuffer(const CircularBuffer&); + void operator=(const CircularBuffer&); +}; + +} // namespace oemprofiler +} // namespace wvcdm + +#endif diff --git a/libwvdrmengine/cdm/profiler/include/entry_writer.h b/libwvdrmengine/cdm/profiler/include/entry_writer.h new file mode 100644 index 00000000..611f4b8c --- /dev/null +++ b/libwvdrmengine/cdm/profiler/include/entry_writer.h @@ -0,0 +1,71 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#ifndef WVCDM_PROFILER_ENTRY_WRITER_H_ +#define WVCDM_PROFILER_ENTRY_WRITER_H_ + +#include +#include + +namespace wvcdm { +namespace oemprofiler { + +class EntryWriter { + public: + explicit EntryWriter(); + + const uint8_t* GetData() const; + + size_t GetSize() const; + + int WriteU8(uint8_t value); + + int WriteU16(uint16_t value); + + int WriteU32(uint32_t value); + + int WriteU64(uint64_t value); + + // WriteVLV + // Write a uint 64 value using a variable number of bytes. The number + // of bytes used is based on the number of bytes required to + // express the value. + // + // The first 3 bits are used to express the number of bytes + // (ranging 1 to 8 bytes). + // + // 1 byte = 0 to 31 + // 2 bytes = 32 to 8191 + // 3 bytes = 8192 to 2097151 + // 4 bytes = 2097152 to 536870911 + // 5 bytes = 536870912 to 137438953471 + // 6 bytes = 137438953472 to 35184372088831 + // 7 bytes = 35184372088832 to 9007199254740991 + // 8 bytes = 9007199254740992 to 2305843009213693951 + int WriteVLV(uint64_t value); + + void Clear(); + + size_t GetFreeSpace() const; + + private: + static const size_t kBufferSize = 32; + + uint8_t bytes_[kBufferSize]; + size_t write_head_; + + int Write(uint64_t v, size_t num_bytes); + + template + int Write(T v); + + uint8_t GetByte(uint64_t value, size_t byte_index); + + // disallow copy and assign + EntryWriter(const EntryWriter&); + void operator=(const EntryWriter&); +}; + +} // oemprofiler +} // wvcdm + +#endif diff --git a/libwvdrmengine/cdm/profiler/include/oem_functions.h b/libwvdrmengine/cdm/profiler/include/oem_functions.h new file mode 100644 index 00000000..18f6fb7b --- /dev/null +++ b/libwvdrmengine/cdm/profiler/include/oem_functions.h @@ -0,0 +1,59 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#ifndef WVCDM_PROFILER_OEM_FUNCTIONS_H_ +#define WVCDM_PROFILER_OEM_FUNCTIONS_H_ + +namespace wvcdm { +namespace oemprofiler { + +enum OEM_FUNCTION { + OEM_FUNCTION_OPEN_SESSION = 0, + OEM_FUNCTION_COPY_BUFFER, + OEM_FUNCTION_INSTALL_KEYBOX, + OEM_FUNCTION_IS_KEYBOX_VALID, + OEM_FUNCTION_GET_DEVICE_ID, + OEM_FUNCTION_GET_KEY_DATA, + OEM_FUNCTION_API_VERSION, + OEM_FUNCTION_SECURITY_PATCH_LEVEL, + OEM_FUNCTION_SECURITY_LEVEL, + OEM_FUNCTION_GET_HDCP_CAPABILITIY, + OEM_FUNCTION_SUPPORTS_USAGE_TABLE, + OEM_FUNCTION_IS_ANTI_ROLLBACK_HW_PRESENT, + OEM_FUNCTION_GET_NUMBER_OF_OPEN_SESSIONS, + OEM_FUNCTION_GET_MAX_NUMBER_OF_SESSIONS, + OEM_FUNCTION_CLOSE_SESSION, + OEM_FUNCTION_GENERATE_DERIVED_KEYS, + OEM_FUNCTION_GENERATE_NONCE, + OEM_FUNCTION_GENERATE_SIGNATURE, + OEM_FUNCTION_LOAD_KEYS, + OEM_FUNCTION_REFRESH_KEYS, + OEM_FUNCTION_QUERY_KEY_CONTROL, + OEM_FUNCTION_SELECT_KEY, + OEM_FUNCTION_DECRYPT_CENC, + OEM_FUNCTION_WRAP_KEYBOX, + OEM_FUNCTION_LOAD_TEST_KEYBOX, + OEM_FUNCTION_GET_RANDOM, + OEM_FUNCTION_REWRAP_DEVICE_RSA_KEY, + OEM_FUNCTION_LOAD_DEVICE_RSA_KEY, + OEM_FUNCTION_LOAD_TEST_RSA_KEY, + OEM_FUNCTION_GENERATE_RSA_SIGNATURE, + OEM_FUNCTION_DERIVE_KEYS_FROM_SESSION_KEY, + OEM_FUNCTION_GENERIC_ENCRYPT, + OEM_FUNCTION_GENERIC_DECRYPT, + OEM_FUNCTION_GENERIC_SIGN, + OEM_FUNCTION_GENERIC_VERIFY, + OEM_FUNCTION_UPDATE_USAGE_TABLE, + OEM_FUNCTION_DEACTIVATE_USAGE_ENTRY, + OEM_FUNCTION_REPORT_USAGE, + OEM_FUNCTION_DELETE_USAGE_ENTRY, + OEM_FUNCTION_FORCE_DELETE_USAGE_ENTRY, + OEM_FUNCTION_DELETE_USAGE_TABLE, + + OEM_FUNCTION_TESTING, // dummy value for testing purposes + OEM_FUNCTION_COUNT +}; + +} // namespace oemprofiler +} // namespace wvcdm + +#endif diff --git a/libwvdrmengine/cdm/profiler/include/profiled_scope.h b/libwvdrmengine/cdm/profiler/include/profiled_scope.h new file mode 100644 index 00000000..64fcb910 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/include/profiled_scope.h @@ -0,0 +1,46 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#ifndef WVCDM_PROFILER_PROFILED_SCOPE_H_ +#define WVCDM_PROFILER_PROFILED_SCOPE_H_ + +#include + +#include "entry_writer.h" +#include "oem_functions.h" + +namespace wvcdm { +namespace oemprofiler { + +class ProfiledScope { + public: + explicit ProfiledScope(OEM_FUNCTION fid); + explicit ProfiledScope(uint32_t sid, OEM_FUNCTION fid); + ~ProfiledScope(); + + EntryWriter meta_data_; + + // All profiling data must be assigned to a session but some oem + // crypto calls are not associated with crypto sessions. To gather + // those functions' data, the global session id is used. Crypto.Session + // Ids are unsigned 32 bit integers. To use those as a profiling session + // id but also allow for a global id that won't conflict with them, + // we use a -1 as the a proifiling session id is a signed 64 bit integer. + static const int64_t kGlobalSID = -1; + + private: + int64_t sid_; + OEM_FUNCTION fid_; + + uint64_t start_time_; + + void Submit(int64_t sid, uint64_t end_time) const; + uint64_t GetNowUS() const; + + // disallow copy and assign + ProfiledScope(const ProfiledScope&); + void operator=(const ProfiledScope&); +}; + +} // namespace oemprofiler +} // namespace wvcdm +#endif diff --git a/libwvdrmengine/cdm/profiler/include/profiler_session.h b/libwvdrmengine/cdm/profiler/include/profiler_session.h new file mode 100644 index 00000000..a362ae17 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/include/profiler_session.h @@ -0,0 +1,73 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#ifndef WVCDM_PROFILER_SESSION_H_ +#define WVCDM_PROFILER_SESSION_H_ + +#include +#include +#include +#include + +#include "circular_buffer.h" +#include "entry_writer.h" +#include "oem_functions.h" +#include "stats.h" + +namespace wvcdm { +namespace oemprofiler { + +class ProfilerSession { + + public: + ProfilerSession(); + + void Submit( + OEM_FUNCTION fid, + uint64_t start_time, + uint64_t end_time, + const uint8_t* meta_data, + size_t meta_data_length); + + // clear all samples and stats + void Clear(); + + void ReadHistory(std::vector& output) const; + + void ReadAllStats(std::vector& output) const; + const Stat& ReadStat(OEM_FUNCTION fid) const; + + static void Open(int64_t sid); + static void Close(int64_t sid); + + static ProfilerSession* Find(int64_t sid); + + private: + Stat stats_[OEM_FUNCTION_COUNT]; + + CircularBuffer buffer_; + + uint64_t time_at_head_; + uint64_t time_at_tail_; + + bool RequestSpace(uint8_t num_bytes); + + bool ReadNextEntryRealEndTime(uint64_t* output); + + bool DropLastEntry(); + + // Read a variable length value. This is the read that matches + // EntryWriter's WriteVLV. + int ReadVLV(size_t offset, uint64_t* output) const; + + ProfilerSession(const ProfilerSession&); + void operator=(const ProfilerSession&); + + static uint8_t GetByte(uint64_t value, size_t byte_index); + + static std::map sessions_; +}; + +} // namespace oemprofiler +} // namespace wvcdm + +#endif diff --git a/libwvdrmengine/cdm/profiler/include/stats.h b/libwvdrmengine/cdm/profiler/include/stats.h new file mode 100644 index 00000000..831359fe --- /dev/null +++ b/libwvdrmengine/cdm/profiler/include/stats.h @@ -0,0 +1,40 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#ifndef WVCDM_PROFILER_STATS_H_ +#define WVCDM_PROFILER_STATS_H_ + +#include + +namespace wvcdm { +namespace oemprofiler { + +class Stat { + public: + Stat(); + + void Update(uint64_t sample); + void Reset(); + + uint64_t GetMin() const; + uint64_t GetMax() const; + uint64_t GetSampleSize() const; + double GetMean() const; + double GetVariance() const; + + private: + uint64_t min_; + uint64_t max_; + double mean_; + uint64_t count_; + + double sdev_m_; + double sdev_s_; + + Stat(const Stat&); + void operator=(const Stat&); +}; + +} // namespace oemprofiler +} // namespace wvcdm + +#endif diff --git a/libwvdrmengine/cdm/profiler/src/circular_buffer.cpp b/libwvdrmengine/cdm/profiler/src/circular_buffer.cpp new file mode 100644 index 00000000..3b86c346 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/src/circular_buffer.cpp @@ -0,0 +1,92 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#include "circular_buffer.h" + +#include "log.h" + +namespace wvcdm { +namespace oemprofiler { + +CircularBuffer::CircularBuffer(size_t memory_budget) : + buffer_(memory_budget) { + + buffer_.resize(memory_budget, 0x00); + fill_ = head_ = tail_ = 0; +} + +size_t CircularBuffer::GetFreeSpace() const { + return buffer_.size() - fill_; +} + +size_t CircularBuffer::GetUsedSpace() const { + return fill_; +} + +bool CircularBuffer::AddU8(uint8_t value) { + return AddU8s(&value, 1); +} + +bool CircularBuffer::AddU8s(const uint8_t* values, size_t values_length) { + if (GetFreeSpace() < values_length) { + return false; + } + + for (size_t i = 0; i < values_length; i++) { + buffer_[head_] = values[i]; + head_ = (head_ + 1) % buffer_.size(); + } + + fill_ += values_length; + + return true; +} + +bool CircularBuffer::PeekU8s( + size_t offset, + uint8_t* out, + size_t read_length) const { + + if (out == NULL) { + LOGE("Cannot read to null output"); + return false; + } + + if (offset >= GetUsedSpace()) { + LOGE("Cannot read past end of data - %zu >= %zu", + offset, GetUsedSpace()); + + return false; + } + + if (read_length > GetUsedSpace() - offset) { + LOGE("Cannot read when there is not enough data - %zu >= %zu", + GetUsedSpace() - offset, sizeof(uint8_t)); + + return false; + } + + for (size_t i = 0; i < read_length; i++) { + const size_t safe_index = (tail_ + offset + i) % buffer_.size(); + out[i] = buffer_[safe_index]; + } + + return true; +} + +bool CircularBuffer::PeekU8(size_t offset, uint8_t* out) const { + return PeekU8s(offset, out, 1); +} + +bool CircularBuffer::Remove(size_t count) { + if (count > GetUsedSpace()) { + // can't remove more than there is + return false; + } + + fill_ -= count; + tail_ = (tail_ + count) % buffer_.size(); + return true; +} + +} // namespace oemprofiler +} // namespace wvcdm diff --git a/libwvdrmengine/cdm/profiler/src/entry_writer.cpp b/libwvdrmengine/cdm/profiler/src/entry_writer.cpp new file mode 100644 index 00000000..54e911b4 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/src/entry_writer.cpp @@ -0,0 +1,109 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#include "entry_writer.h" +#include "log.h" + +namespace wvcdm { +namespace oemprofiler { + +static const uint64_t MAX_VALUES_FOR_BYTES[8] = { + 0x000000000000001F, + 0x0000000000001FFF, + 0x00000000001FFFFF, + 0x000000001FFFFFFF, + 0x0000001FFFFFFFFF, + 0x00001FFFFFFFFFFF, + 0x001FFFFFFFFFFFFF, + 0x1FFFFFFFFFFFFFFF + }; + +static const uint64_t CODE_FOR_BYTES[8] = { + 0x0000000000000000, + 0x0000000000002000, + 0x0000000000400000, + 0x0000000060000000, + 0x0000008000000000, + 0x0000A00000000000, + 0x00C0000000000000, + 0xE000000000000000 +}; + +EntryWriter::EntryWriter() : write_head_(0){ } + +const uint8_t* EntryWriter::GetData() const { return bytes_; } + +size_t EntryWriter::GetSize() const { return write_head_; } + +int EntryWriter::WriteU8(uint8_t value) { return Write(value); } + +int EntryWriter::WriteU16(uint16_t value) { return Write(value); } + +int EntryWriter::WriteU32(uint32_t value) { return Write(value); } + +int EntryWriter::WriteU64(uint64_t value) { return Write(value); } + +int EntryWriter::WriteVLV(uint64_t value) { + for (size_t i = 0; i < sizeof(uint64_t); i++) { + if (value <= MAX_VALUES_FOR_BYTES[i]) { + return Write(value | CODE_FOR_BYTES[i], i + 1); + } + } + + LOGE("writeVariableLengthValue - value too large for variable length value"); + return -1; +} + +int EntryWriter::Write(uint64_t v, size_t num_bytes) { + if (num_bytes > sizeof(uint64_t)) { + LOGE("read - cannot read %zu bytes when 8 bytes are the max", num_bytes); + return -1; + } + + if (GetFreeSpace() < num_bytes) { + LOGE("write - cannot write %zu when there are only %zu bytes remaining", + num_bytes, GetFreeSpace()); + return -1; + } + + for (int i = num_bytes; i > 0; i--) { + bytes_[write_head_] = GetByte(v, i - 1); + write_head_++; + } + + return static_cast(num_bytes); +} + +void EntryWriter::Clear() { + write_head_ = 0; +} + +size_t EntryWriter::GetFreeSpace() const { + return kBufferSize - write_head_; +} + +template +int EntryWriter::Write(T v) { + // start the values at index 1 so that the number of bytes + // line up with the shift value + static const size_t shifts[8] = { 0, 8, 16, 24, 32, 40, 48, 56 }; + + if (GetFreeSpace() < sizeof(T)) { + LOGE("write - cannot write %zu when there are only %zu bytes remaining", + sizeof(T), GetFreeSpace()); + return -1; // there is not enough room + } + + for (int i = sizeof(T) - 1; i >= 0; i--) { + bytes_[write_head_] = (uint8_t)((v >> shifts[i]) & 0xFF); + write_head_++; + } + + return (int)sizeof(T); +} + +uint8_t EntryWriter::GetByte(uint64_t value, size_t byte_index) { + return static_cast(0xFF & (value >> (byte_index * 8))); +} + +} // oem profiler +} // wvcdm diff --git a/libwvdrmengine/cdm/profiler/src/profiled_scope.cpp b/libwvdrmengine/cdm/profiler/src/profiled_scope.cpp new file mode 100644 index 00000000..2cf687a7 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/src/profiled_scope.cpp @@ -0,0 +1,66 @@ +// Copyright 2016 Google Inc. All Rights Reserved + +#include "profiled_scope.h" + +#include + +#include "profiler_session.h" + +namespace wvcdm { +namespace oemprofiler { + +ProfiledScope::ProfiledScope(OEM_FUNCTION fid) : + meta_data_(), + sid_(kGlobalSID), + fid_(fid), + start_time_(GetNowUS()) { + +} + +// Only allow a user provided sid to be a positive integer +// to prevent a user provided sid from conflicting with the +// global sid +ProfiledScope::ProfiledScope(uint32_t sid, OEM_FUNCTION fid) : + meta_data_(), + sid_(static_cast(sid)), + fid_(fid), + start_time_(GetNowUS()) { + +} + +ProfiledScope::~ProfiledScope() { + const uint64_t end_time = GetNowUS(); + + if (sid_ != kGlobalSID) { + Submit(sid_, end_time); + } + + // Always save a copy to the global session so that all other sessions + // are subsets of the global session + Submit(kGlobalSID, end_time); +} + +void ProfiledScope::Submit(int64_t sid, uint64_t end_time) const { + ProfilerSession* const session = ProfilerSession::Find(sid); + + if (session != NULL) { + session->Submit( + fid_, + start_time_, + end_time, + meta_data_.GetData(), + meta_data_.GetSize()); + } +} + +uint64_t ProfiledScope::GetNowUS() const { + struct timeval tv; + gettimeofday(&tv, NULL); + + const uint64_t kSecondsToUSeconds = 1000000; + return static_cast(tv.tv_sec) * kSecondsToUSeconds + + static_cast(tv.tv_usec); +} + +} // namespace oemprofiler +} // namespace wvcdm diff --git a/libwvdrmengine/cdm/profiler/src/profiler_session.cpp b/libwvdrmengine/cdm/profiler/src/profiler_session.cpp new file mode 100644 index 00000000..254ad59d --- /dev/null +++ b/libwvdrmengine/cdm/profiler/src/profiler_session.cpp @@ -0,0 +1,229 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#include "profiler_session.h" + +#include + +namespace wvcdm { +namespace oemprofiler { + +namespace { + const size_t kProfilingMemoryBudget = 1024; // 1 KB +} + +std::map ProfilerSession::sessions_; + +ProfilerSession::ProfilerSession() : + buffer_(kProfilingMemoryBudget), + time_at_head_(0), + time_at_tail_(0) { + + Clear(); +} + +void ProfilerSession::Submit( + OEM_FUNCTION fid, + uint64_t start_time, + uint64_t end_time, + const uint8_t* meta_data, + size_t meta_data_length) { + + EntryWriter header; + header.WriteU8(fid); + header.WriteVLV(start_time - time_at_tail_); + header.WriteVLV(end_time - start_time); + + const size_t total_packet_size = header.GetSize() + meta_data_length; + + // The max size for a VLV is 8 bytes and the max size for a entry + // writer is 32 bytes. Normally the meta data will be packed using + // an entry writer so the max packet size will be 64 bytes. Since the + // packet size is encoded with a single byte, the packet must first + // be checked to ensure it is not too large for the cast. + if (total_packet_size <= 255 && RequestSpace(total_packet_size + 1)) { + buffer_.AddU8(static_cast(total_packet_size)); + buffer_.AddU8s(header.GetData(), header.GetSize()); + buffer_.AddU8s(meta_data, meta_data_length); + + time_at_tail_ = end_time; + } + + stats_[fid].Update(end_time - start_time); +} + +void ProfilerSession::Clear(){ + buffer_.Remove(buffer_.GetUsedSpace()); + + // the buffer is cleared so we reseting these values is clean and safe + time_at_tail_ = time_at_head_ = 0; + + for (size_t i = 0; i < OEM_FUNCTION_COUNT; i++) { + stats_[i].Reset(); + } +} + +void ProfilerSession::ReadHistory(std::vector& output) const { + // write the tail time + for (size_t i = 1; i <= sizeof(time_at_head_); i++) { + output.push_back(GetByte(time_at_head_, sizeof(time_at_head_) - i)); + } + + // write the whole circular buffer into the output buffer + const size_t num_bytes = buffer_.GetUsedSpace(); + for (size_t i = 0; i < num_bytes; i++) { + uint8_t b; + if (buffer_.PeekU8(i, &b)) { + output.push_back(b); + } + } +} + +void ProfilerSession::ReadAllStats(std::vector& output) const { + + uint64_t values_to_write[7]; + EntryWriter writer; + + const size_t num_values_to_write = + sizeof(values_to_write) / sizeof(values_to_write[0]); + + // make sure there is enough room + output.reserve( + output.size() + OEM_FUNCTION_COUNT * sizeof(values_to_write)); + + for(size_t fid = 0; fid < OEM_FUNCTION_COUNT; fid++) { + const Stat& stat = stats_[fid]; + + values_to_write[0] = stat.GetSampleSize(); + values_to_write[1] = stat.GetMin(); + values_to_write[2] = stat.GetMax(); + values_to_write[3] = static_cast(stat.GetMean()); + values_to_write[4] = static_cast(stat.GetMean() * 100) % 100; + values_to_write[5] = static_cast(stat.GetVariance()); + values_to_write[6] = static_cast(stat.GetVariance() * 100) % 100; + + for (size_t i = 0; i < num_values_to_write; i++) { + writer.Clear(); + writer.WriteU64(values_to_write[i]); + + for (size_t w_index = 0; w_index < writer.GetSize(); w_index++) { + output.push_back(writer.GetData()[w_index]); + } + } + } +} + +const Stat& ProfilerSession::ReadStat(OEM_FUNCTION fid) const { + return stats_[fid]; +} + +bool ProfilerSession::RequestSpace(uint8_t num_bytes) { + // check if it is possible to make enough room + const size_t buffer_size = buffer_.GetFreeSpace() + + buffer_.GetUsedSpace(); + + if (num_bytes > buffer_size) { + LOGE("Requesting more space than possible (requested = %u, max = %zu)", + num_bytes, buffer_size); + return false; + } + + // drop entries until we have enough space + while (num_bytes > buffer_.GetFreeSpace() && DropLastEntry()); + + return num_bytes <= buffer_.GetFreeSpace(); +} + +bool ProfilerSession::ReadNextEntryRealEndTime(uint64_t* output) { + if (output == NULL) { + LOGE("Cannout output to null pointer"); + return false; + } + + size_t initial_time_start_index = 2; + + uint64_t initial_time; + const int initial_time_length = + ReadVLV(initial_time_start_index, &initial_time); + + if (initial_time_length == -1) { + LOGE("Failed to read the start time for head entry"); + return false; + } + + uint64_t delta_time; + const int delta_time_length = ReadVLV( + initial_time_start_index + initial_time_length, &delta_time); + + if (delta_time_length == -1) { + LOGE("Failed to read the delta time for head entry"); + return false; + } + + *output = time_at_head_ + initial_time + delta_time; + return true; +} + +bool ProfilerSession::DropLastEntry() { + uint8_t entry_size; + uint64_t end_time; + + if(buffer_.PeekU8(0, &entry_size) && ReadNextEntryRealEndTime(&end_time)) { + // + 1 because the entry size byte needs to be removed too + if (buffer_.Remove(entry_size + 1)) { + time_at_head_ = end_time; + return true; + } + } + + return false; +} + +int ProfilerSession::ReadVLV(size_t offset, uint64_t* output) const { + uint8_t first_byte; + if (buffer_.PeekU8(offset, &first_byte)) { + const size_t num_bytes = (first_byte >> 5) + 1; + + uint64_t value = first_byte & 0x1F; + for (size_t i = 1; i < num_bytes; i++) { + uint8_t next_byte; + if (buffer_.PeekU8(offset + i, &next_byte)) { + value = value << 8 | next_byte; + } else { + return -1; + } + } + + *output = value; + return num_bytes; + } + + return -1; +} + +uint8_t ProfilerSession::GetByte(uint64_t value, size_t byte_index) { + return (uint8_t)(0xFF & (value >> (byte_index * 8))); +} + +void ProfilerSession::Open(int64_t sid) { + if (sessions_.count(sid) == 0) { + sessions_.insert( + std::pair(sid, new ProfilerSession())); + } +} + +void ProfilerSession::Close(int64_t sid) { + if(sessions_.count(sid) > 0) { + ProfilerSession* session = sessions_.at(sid); + sessions_.erase(sid); + + delete session; + } +} + +ProfilerSession* ProfilerSession::Find(int64_t sid) { + return sessions_.count(sid) > 0 ? sessions_.at(sid) : NULL; +} + +} // namespace wvcdm +} // namespace oemprofiler + diff --git a/libwvdrmengine/cdm/profiler/src/stats.cpp b/libwvdrmengine/cdm/profiler/src/stats.cpp new file mode 100644 index 00000000..01b1383d --- /dev/null +++ b/libwvdrmengine/cdm/profiler/src/stats.cpp @@ -0,0 +1,50 @@ +// Copyright 2016 Google Inc. All Rights Reserved. + +#include "stats.h" + +#include +#include + +namespace wvcdm { +namespace oemprofiler { + +Stat::Stat() { + Reset(); +} + +void Stat::Update(uint64_t sample) { + min_ = std::min(min_, sample); + max_ = std::max(max_, sample); + + mean_ = ((mean_ * count_) + sample) / (count_ + 1.0); + count_ += 1; + + // Welford's method for standard deviation / variance + const double old_sdev_m = sdev_m_; + const double old_sdev_s = sdev_s_; + + sdev_m_ = old_sdev_m + (sample - old_sdev_m) / count_; + sdev_s_ = old_sdev_s + (sample - sdev_m_) * (sample - old_sdev_m); +} + +void Stat::Reset() { + min_ = std::numeric_limits::max(); + max_ = count_ = 0; + + mean_ = sdev_m_ = sdev_s_ = 0.0; +} + +uint64_t Stat::GetMin() const { return min_; } + +uint64_t Stat::GetMax() const { return max_; } + +uint64_t Stat::GetSampleSize() const { return count_; } + +double Stat::GetMean() const { return mean_; } + +double Stat::GetVariance() const { + return count_ > 1 ? sdev_s_ / (count_ - 1) : 0; +} + +} // namespace oemprofiler +} // namespace wvcdm diff --git a/libwvdrmengine/cdm/profiler/test/circular_buffer_test.cpp b/libwvdrmengine/cdm/profiler/test/circular_buffer_test.cpp new file mode 100644 index 00000000..a7326497 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/test/circular_buffer_test.cpp @@ -0,0 +1,225 @@ +// Copyright 2015 Google Inc. All Rights Reserved. + +#include +#include + +#include "circular_buffer.h" + +namespace wvcdm { + +TEST(CircularBufferTest, MixAddU8AndU8s) { + oemprofiler::CircularBuffer buffer(32); + + const uint8_t expected_values[16] = { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07 + }; + + ASSERT_TRUE(buffer.AddU8(expected_values[0])); + ASSERT_TRUE(buffer.AddU8(expected_values[1])); + ASSERT_TRUE(buffer.AddU8s(expected_values + 2, 6)); + + ASSERT_TRUE(buffer.AddU8(expected_values[8])); + ASSERT_TRUE(buffer.AddU8(expected_values[9])); + ASSERT_TRUE(buffer.AddU8s(expected_values + 10, 6)); + + uint8_t read[16]; + ASSERT_TRUE(buffer.PeekU8s(0, read, 16)); + + for (size_t i = 0; i < 16; i++) { + ASSERT_EQ(expected_values[i], read[i]); + } +} + +TEST(CircularBufferTest, MixPeekU8AndU8s) { + oemprofiler::CircularBuffer buffer(32); + + const uint8_t expected_values[16] = { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07 + }; + + ASSERT_TRUE(buffer.AddU8s(expected_values, 16)); + + for (size_t i = 0; i < 2; i++) { + uint8_t read; + ASSERT_TRUE(buffer.PeekU8(i, &read)); + ASSERT_EQ(expected_values[i], read); + } + + { + uint8_t read[8]; + ASSERT_TRUE(buffer.PeekU8s(2, read, 8)); + + for (size_t i = 0; i < 8; i++) { + ASSERT_EQ(expected_values[i + 2], read[i]); + } + } + + for (size_t i = 10; i < 16; i++) { + uint8_t read; + ASSERT_TRUE(buffer.PeekU8(i, &read)); + ASSERT_EQ(expected_values[i], read); + } +} + +TEST(CircularBufferTest, ZeroSpaceBuffer) { + oemprofiler::CircularBuffer buffer(0); + + ASSERT_FALSE(buffer.AddU8(0)); + + const uint8_t values[4] = { 0x00, 0x01, 0x02, 0x03 }; + + ASSERT_FALSE(buffer.AddU8s(values, 4)); +} + +TEST(CircularBufferTest, AddU8sWithLengthZero) { + oemprofiler::CircularBuffer buffer(16); + + const uint8_t expected_values[16] = { + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07, + 0x00, 0x01, 0x02, 0x03, + 0x04, 0x05, 0x06, 0x07 + }; + + ASSERT_TRUE(buffer.AddU8s(expected_values, 0)); + + uint8_t read; + ASSERT_FALSE(buffer.PeekU8(0, &read)); +} + +TEST(CircularBufferTest, MeasureSpaceTest) { + oemprofiler::CircularBuffer buffer(16); + + ASSERT_EQ(16u, buffer.GetFreeSpace()); + ASSERT_EQ(0u, buffer.GetUsedSpace()); + + for (int i = 0; i < 16; i++) { + buffer.AddU8(0); + } + + ASSERT_EQ(0u, buffer.GetFreeSpace()); + ASSERT_EQ(16u, buffer.GetUsedSpace()); + + buffer.Remove(16); + + ASSERT_EQ(16u, buffer.GetFreeSpace()); + ASSERT_EQ(0u, buffer.GetUsedSpace()); +} + +TEST(CircularBufferTest, PeekAddU8Test) { + oemprofiler::CircularBuffer buffer(16); + + for (uint8_t i = 0; i < 16; i++) { + ASSERT_TRUE(buffer.AddU8(i)); + } + + for (uint8_t i = 0; i < 16; i++) { + uint8_t read; + ASSERT_TRUE(buffer.PeekU8(i, &read)); + ASSERT_EQ(i, read); + } + + ASSERT_EQ(16u, buffer.GetUsedSpace()); +} + +TEST(CircularBufferTest, PeekAddU8WrapTest) { + oemprofiler::CircularBuffer buffer(16); + + const uint8_t expected_values[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + }; + + for (size_t i = 0; i < 16; i++) { + ASSERT_TRUE(buffer.AddU8(expected_values[i])); + } + + for (size_t i = 0; i < 16; i++) { + uint8_t read; + ASSERT_TRUE(buffer.PeekU8(i, &read)); + ASSERT_EQ(expected_values[i], read); + } + + ASSERT_EQ(16u, buffer.GetUsedSpace()); + buffer.Remove(8); + ASSERT_EQ(8u, buffer.GetUsedSpace()); + + for (size_t i = 0; i < 8; i++) { + const size_t expected_value_index = 8 + i; + const size_t buffer_index = i; + + uint8_t read; + ASSERT_TRUE(buffer.PeekU8(buffer_index, &read)); + ASSERT_EQ(expected_values[expected_value_index], read); + } + + for (size_t i = 16; i < 24; i++) { + ASSERT_TRUE(buffer.AddU8(expected_values[i])); + } + + for (size_t i = 0; i < 16; i++) { + const size_t expected_value_index = 8 + i; + const size_t buffer_index = i; + + uint8_t read; + buffer.PeekU8(buffer_index, &read); + + ASSERT_EQ(expected_values[expected_value_index], read); + } +} + +TEST(CircularBufferTest, OutOfRoomTest) { + oemprofiler::CircularBuffer buffer(16); + + for (int i = 0; i < 16; i++) { + ASSERT_TRUE(buffer.AddU8(i)); + } + + ASSERT_FALSE(buffer.AddU8(0)); +} + +TEST(CircularBufferTest, PassTailPeekTest) { + oemprofiler::CircularBuffer buffer(16); + + uint8_t read; + ASSERT_FALSE(buffer.PeekU8( 0, &read)); + ASSERT_FALSE(buffer.PeekU8(17, &read)); +} + +TEST(CircularBufferTest, NullOutputPeekTest) { + oemprofiler::CircularBuffer buffer(16); + buffer.AddU8(0); + + ASSERT_FALSE(buffer.PeekU8(0, nullptr)); +} + +TEST(CircularBufferTest, PeekAddU8sTest) { + oemprofiler::CircularBuffer buffer(16); + + const uint8_t data[] = { + 0, 1, 2, 3, + 4, 5, 6, 7, + 8, 9, 10, 11, + 12, 13, 14, 15 + }; + + ASSERT_TRUE(buffer.AddU8s(data, 16)); + + uint8_t read[16]; + ASSERT_TRUE(buffer.PeekU8s(0, read, 16)); + + for (uint8_t i = 0; i < 16; i++) { + ASSERT_EQ(i, read[i]); + } + + ASSERT_EQ(16u, buffer.GetUsedSpace()); +} + +} // namespace diff --git a/libwvdrmengine/cdm/profiler/test/entry_writer_test.cpp b/libwvdrmengine/cdm/profiler/test/entry_writer_test.cpp new file mode 100644 index 00000000..f73f6165 --- /dev/null +++ b/libwvdrmengine/cdm/profiler/test/entry_writer_test.cpp @@ -0,0 +1,168 @@ +// Copyright 2015 Google Inc. All Rights Reserved. + +#include +#include + +#include "entry_writer.h" + +namespace wvcdm { + +TEST(EntryWriterTest, ConstructorTest) { + oemprofiler::EntryWriter writer; + + ASSERT_TRUE(writer.GetData() != nullptr); + ASSERT_EQ(0u, writer.GetSize()); +} + +TEST(EntryWriterTest, WriteU8Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(1, writer.WriteU8(0x01)); + ASSERT_EQ(0x01u, writer.GetData()[0]); +} + +TEST(EntryWriterTest, WriteU16Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(2, writer.WriteU16(0x0102)); + ASSERT_EQ(0x01u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); +} + +TEST(EntryWriterTest, WriteU32Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(4, writer.WriteU32(0x01020304)); + ASSERT_EQ(0x01u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); +} + +TEST(EntryWriterTest, WriteU64Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(8, writer.WriteU64(0x0102030405060708)); + ASSERT_EQ(0x01u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); + ASSERT_EQ(0x05u, writer.GetData()[4]); + ASSERT_EQ(0x06u, writer.GetData()[5]); + ASSERT_EQ(0x07u, writer.GetData()[6]); + ASSERT_EQ(0x08u, writer.GetData()[7]); +} + +TEST(EntryWriterTest, WriteVLVAs8Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(1, writer.WriteVLV(0x01)); + ASSERT_EQ(0x01u, writer.GetData()[0]); +} + +TEST(EntryWriterTest, WriteVLVAs16Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(2, writer.WriteVLV(0x0102)); + ASSERT_EQ(0x01u | 0x20u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); +} + +TEST(EntryWriterTest, WriteVLVAs24Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(3, writer.WriteVLV(0x010203)); + ASSERT_EQ(0x01u | 0x40u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); +} + +TEST(EntryWriterTest, WriteVLVAs32Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(4, writer.WriteVLV(0x01020304)); + ASSERT_EQ(0x01u | 0x60u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); +} + +TEST(EntryWriterTest, WriteVLVAs40Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(5, writer.WriteVLV(0x0102030405)); + ASSERT_EQ(0x01u | 0x80u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); + ASSERT_EQ(0x05u, writer.GetData()[4]); +} + +TEST(EntryWriterTest, WriteVLVAs48Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(6, writer.WriteVLV(0x010203040506)); + ASSERT_EQ(0x01u | 0xA0u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); + ASSERT_EQ(0x05u, writer.GetData()[4]); + ASSERT_EQ(0x06u, writer.GetData()[5]); +} + +TEST(EntryWriterTest, WriteVLVAs56Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(7, writer.WriteVLV(0x01020304050607)); + ASSERT_EQ(0x01u | 0xC0u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); + ASSERT_EQ(0x05u, writer.GetData()[4]); + ASSERT_EQ(0x06u, writer.GetData()[5]); + ASSERT_EQ(0x07u, writer.GetData()[6]); +} + +TEST(EntryWriterTest, WriteVLVAs64Test) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(8, writer.WriteVLV(0x0102030405060708)); + ASSERT_EQ(0x01u | 0xE0u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); + ASSERT_EQ(0x05u, writer.GetData()[4]); + ASSERT_EQ(0x06u, writer.GetData()[5]); + ASSERT_EQ(0x07u, writer.GetData()[6]); + ASSERT_EQ(0x08u, writer.GetData()[7]); +} + +TEST(EntryWriterTest, ClearTest) { + oemprofiler::EntryWriter writer; + + ASSERT_EQ(0u, writer.GetSize()); + + ASSERT_EQ(1, writer.WriteU8(0x01)); + ASSERT_EQ(1u, writer.GetSize()); + + ASSERT_EQ(1, writer.WriteU8(0x02)); + ASSERT_EQ(2u, writer.GetSize()); + + ASSERT_EQ(1, writer.WriteU8(0x03)); + ASSERT_EQ(3u, writer.GetSize()); + + ASSERT_EQ(1, writer.WriteU8(0x04)); + ASSERT_EQ(4u, writer.GetSize()); + + writer.Clear(); + + ASSERT_EQ(0u, writer.GetSize()); + + //Clear should not clear the data form the buffer + ASSERT_EQ(0x01u, writer.GetData()[0]); + ASSERT_EQ(0x02u, writer.GetData()[1]); + ASSERT_EQ(0x03u, writer.GetData()[2]); + ASSERT_EQ(0x04u, writer.GetData()[3]); +} + +} // namespace diff --git a/libwvdrmengine/cdm/test/Android.mk b/libwvdrmengine/cdm/test/Android.mk index b952f46d..dba9f488 100644 --- a/libwvdrmengine/cdm/test/Android.mk +++ b/libwvdrmengine/cdm/test/Android.mk @@ -59,5 +59,13 @@ test_name := timer_unittest test_src_dir := . include $(LOCAL_PATH)/unit-test.mk +test_name := circular_buffer_test +test_src_dir := ../profiler/test +include $(LOCAL_PATH)/unit-test.mk + +test_name := entry_writer_test +test_src_dir := ../profiler/test +include $(LOCAL_PATH)/unit-test.mk + test_name := test_src_dir := diff --git a/libwvdrmengine/cdm/test/unit-test.mk b/libwvdrmengine/cdm/test/unit-test.mk index a13d78be..6822b13e 100644 --- a/libwvdrmengine/cdm/test/unit-test.mk +++ b/libwvdrmengine/cdm/test/unit-test.mk @@ -23,6 +23,8 @@ LOCAL_C_INCLUDES := \ vendor/widevine/libwvdrmengine/android/cdm/test \ vendor/widevine/libwvdrmengine/cdm/core/include \ vendor/widevine/libwvdrmengine/cdm/core/test \ + vendor/widevine/libwvdrmengine/cdm/profiler/include \ + vendor/widevine/libwvdrmengine/cdm/profiler/test \ vendor/widevine/libwvdrmengine/cdm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ vendor/widevine/libwvdrmengine/test/gmock/include diff --git a/libwvdrmengine/mediadrm/Android.mk b/libwvdrmengine/mediadrm/Android.mk index 6038772a..12b5704b 100644 --- a/libwvdrmengine/mediadrm/Android.mk +++ b/libwvdrmengine/mediadrm/Android.mk @@ -10,6 +10,7 @@ LOCAL_C_INCLUDES := \ frameworks/native/include \ vendor/widevine/libwvdrmengine/cdm/core/include \ vendor/widevine/libwvdrmengine/cdm/include \ + vendor/widevine/libwvdrmengine/cdm/profiler/include \ vendor/widevine/libwvdrmengine/include \ vendor/widevine/libwvdrmengine/mediadrm/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \ diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index bd56be53..4713e8f9 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -13,6 +13,7 @@ #include "media/stagefright/foundation/ABase.h" #include "media/stagefright/foundation/AString.h" #include "OEMCryptoCENC.h" +#include "profiler_session.h" #include "utils/Errors.h" #include "utils/KeyedVector.h" #include "utils/List.h" @@ -274,6 +275,19 @@ class WVDrmPlugin : public android::DrmPlugin, status_t mapAndNotifyOfOEMCryptoResult(const Vector& sessionId, OEMCryptoResult res); + bool tryGettingSessionFromPropertyName( + const String8& name, + const String8& tag, + wvcdm::oemprofiler::ProfilerSession** out) const; + + bool tryGettingOEMProfilingHistory( + const String8& name, + Vector& value) const; + + bool tryGettingOEMProfilingStats( + const String8& name, + Vector& value) const; + status_t mapOEMCryptoResult(OEMCryptoResult res); bool initDataResemblesPSSH(const Vector& initData); diff --git a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp index de25d761..e31a7b32 100644 --- a/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp +++ b/libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp @@ -11,11 +11,13 @@ #include #include #include +#include #include #include #include "mapErrors-inl.h" #include "media/stagefright/MediaErrors.h" +#include "profiled_scope.h" #include "utils/Errors.h" #include "wv_cdm_constants.h" @@ -25,6 +27,11 @@ namespace { static const char* const kDisable = "disable"; static const std::string kPsshTag = "pssh"; static const char* const kSpecialUnprovisionResponse = "unprovision"; + + + // profiler proterties constants + static const android::String8 kProfilerHistoryTag("oemProfilerHistory-"); + static const android::String8 kProfilerStatsTag("oemProfilerStats-"); } namespace wvdrm { @@ -492,9 +499,94 @@ status_t WVDrmPlugin::getPropertyString(const String8& name, return android::OK; } +bool WVDrmPlugin::tryGettingSessionFromPropertyName( + const String8& name, + const String8& tag, + oemprofiler::ProfilerSession** out) const { + + if (name.find(tag) != 0) { + return false; + } + + oemprofiler::ProfilerSession* session = NULL; + + // if the name starts with the tag and is the same length + // as the tag, then it must just be the tag + if (name.length() == tag.length()) { + // if it is just the tag, then return the global session + session = oemprofiler::ProfilerSession::Find( + oemprofiler::ProfiledScope::kGlobalSID); + } else { + // make a string that is only the part that comes after the tag. + // If it is a valid property, this should be a cdm session id + const CdmSessionId cdm_session_id(name.string() + tag.length()); + + if (mCryptoSessions.count(cdm_session_id) != 1) { + return false; + } + + const OEMCrypto_SESSION sid = + mCryptoSessions.at(cdm_session_id).oecSessionId(); + + session = oemprofiler::ProfilerSession::Find(static_cast(sid)); + } + + // if the session is not open, then treat the property as not existing + if (session == nullptr) { + return false; + } + + if (out != nullptr) { + *out = session; + } + + return true; +} + +bool WVDrmPlugin::tryGettingOEMProfilingHistory(const String8& name, + Vector& value) const { + + oemprofiler::ProfilerSession* session = nullptr; + + if (!tryGettingSessionFromPropertyName( + name, kProfilerHistoryTag, &session)) { + return false; + } + + // read the data out of the session + std::vector tempValue; + session->ReadHistory(tempValue); + value.appendArray(tempValue.data(), tempValue.size()); + + return true; +} + +bool WVDrmPlugin::tryGettingOEMProfilingStats( + const String8& name, + Vector& value) const { + + oemprofiler::ProfilerSession* session = nullptr; + + if (!tryGettingSessionFromPropertyName( + name, kProfilerStatsTag, &session)) { + return false; + } + + std::vector tempValue; + session->ReadAllStats(tempValue); + value.appendArray(tempValue.data(), tempValue.size()); + + return true; +} + status_t WVDrmPlugin::getPropertyByteArray(const String8& name, Vector& value) const { - if (name == "deviceUniqueId") { + + if (tryGettingOEMProfilingHistory(name, value)) { + return android::OK; + } else if (tryGettingOEMProfilingStats(name, value)) { + return android::OK; + } else if (name == "deviceUniqueId") { return queryProperty(QUERY_KEY_DEVICE_ID, value); } else if (name == "provisioningUniqueId") { return queryProperty(QUERY_KEY_PROVISIONING_ID, value); diff --git a/libwvdrmengine/run_all_unit_tests.sh b/libwvdrmengine/run_all_unit_tests.sh index a6d15e3a..bc3a6274 100755 --- a/libwvdrmengine/run_all_unit_tests.sh +++ b/libwvdrmengine/run_all_unit_tests.sh @@ -62,6 +62,8 @@ adb_shell_run /system/bin/initialization_data_unittest adb_shell_run /system/bin/device_files_unittest adb_shell_run /system/bin/timer_unittest adb_shell_run /system/bin/buffer_reader_test +adb_shell_run /system/bin/circular_buffer_test +adb_shell_run /system/bin/entry_writer_test library_path="/system/vendor/lib/mediadrm/ " adb_shell_run LD_LIBRARY_PATH=$library_path /system/bin/libwvdrmengine_test