From 6d3457b9d947cd585ea4af736590a3f77127c338 Mon Sep 17 00:00:00 2001 From: Edwin Wong Date: Sat, 19 Nov 2022 04:52:25 +0000 Subject: [PATCH] Remove hidl support. Merged from http://go/wvgerrit/161857 Test: streaming(Netflix, Play Movies & TV) Test: ./build_and_run_all_unit_tests.sh Test: adb shell ps | grep drm Test: metrics_dump Test: hardware/interfaces/drm/aidl/vts$ atest VtsAidlHalDrmTargetTest Bug: 259299992 Change-Id: I76bcc82bbfb3fc60987b66265a580946a16c341d --- libwvdrmengine/Android.bp | 314 +- libwvdrmengine/build_all_unit_tests.sh | 10 +- .../cdm/core/include/wv_cdm_constants.h | 3 - .../cdm/core/include/wv_cdm_types.h | 1 - libwvdrmengine/cdm/test/coverage-test.mk | 13 +- libwvdrmengine/cdm/test/integration-test.mk | 13 +- libwvdrmengine/cdm/test/unit-test.mk | 14 +- libwvdrmengine/cdm/util/src/log.cpp | 11 +- .../include_hidl/HidlMapErrors-inl.h | 753 ---- libwvdrmengine/include_hidl/HidlTypes.h | 66 - .../HidlWVCreatePluginFactories.h | 28 - .../include_hidl/HidlWVDrmFactory.h | 68 - libwvdrmengine/include_hidl/HidlWVTypes.h | 22 - libwvdrmengine/include_hidl/TypeConvert.h | 119 - libwvdrmengine/include_hidl/WVCryptoFactory.h | 42 - ...roid.hardware.drm@1.2-service.widevine.xml | 23 - ...roid.hardware.drm@1.3-service.widevine.xml | 23 - ...roid.hardware.drm@1.4-service.widevine.xml | 23 - libwvdrmengine/mediacrypto/Android.bp | 44 - .../mediacrypto/include_hidl/WVCryptoPlugin.h | 97 - .../mediacrypto/src_hidl/WVCryptoPlugin.cpp | 372 -- libwvdrmengine/mediacrypto/test/Android.mk | 52 - .../test/hidl/WVCryptoPlugin_test.cpp | 643 ---- libwvdrmengine/mediadrm/Android.bp | 46 - libwvdrmengine/mediadrm/include/WVDrmPlugin.h | 2 +- .../mediadrm/include_hidl/WVDrmPlugin.h | 510 --- .../include_hidl/WVGenericCryptoInterface.h | 98 - .../include_hidl/hidl_metrics_adapter.h | 113 - .../mediadrm/src_hidl/WVDrmPlugin.cpp | 2364 ------------ .../src_hidl/WVGenericCryptoInterface.cpp | 50 - .../src_hidl/hidl_metrics_adapter.cpp | 650 ---- libwvdrmengine/mediadrm/test/Android.mk | 99 +- .../test/hal_metrics_adapter_unittest.cpp | 2 +- .../mediadrm/test/hidl/WVDrmPlugin_test.cpp | 3264 ----------------- .../hidl/hidl_metrics_adapter_unittest.cpp | 459 --- .../oemcrypto/test/GEN_api_lock_file.c | 306 ++ libwvdrmengine/oemcrypto/test/common.mk | 14 +- .../prebuilts_hidl/arm/libwvhidl@1.3.so | Bin 2838440 -> 0 bytes .../prebuilts_hidl/arm64/libwvhidl@1.3.so | Bin 3488216 -> 0 bytes .../prebuilts_hidl/x86/libwvhidl@1.3.so | Bin 3473276 -> 0 bytes .../prebuilts_hidl/x86_64/libwvhidl@1.3.so | Bin 3561704 -> 0 bytes libwvdrmengine/run_all_unit_tests.sh | 6 - .../src_hidl/WVCreatePluginFactories.cpp | 33 - libwvdrmengine/src_hidl/WVCryptoFactory.cpp | 60 - libwvdrmengine/src_hidl/WVDrmFactory.cpp | 277 -- ....hardware.drm@1.2-service-lazy.widevine.rc | 26 - ...droid.hardware.drm@1.2-service.widevine.rc | 25 - ....hardware.drm@1.3-service-lazy.widevine.rc | 29 - ...droid.hardware.drm@1.3-service.widevine.rc | 27 - ....hardware.drm@1.4-service-lazy.widevine.rc | 30 - ...droid.hardware.drm@1.4-service.widevine.rc | 28 - libwvdrmengine/src_hidl/service.cpp | 44 - libwvdrmengine/src_hidl/service@1.3.cpp | 108 - libwvdrmengine/src_hidl/serviceLazy.cpp | 47 - libwvdrmengine/src_hidl/wv_metrics.cpp | 451 --- libwvdrmengine/test/unit/Android.mk | 43 - .../unit/WVCreatePluginFactories_test.cpp | 38 - .../test/unit/WVCryptoFactory_test.cpp | 54 - .../test/unit/WVDrmFactory_test.cpp | 150 - .../hidl/WVCreatePluginFactories_test.cpp | 38 - .../test/unit/hidl/WVCryptoFactory_test.cpp | 54 - .../test/unit/hidl/WVDrmFactory_test.cpp | 150 - libwvdrmengine/tools/metrics_dump/Android.bp | 2 +- libwvdrmengine/vts/vendor_module/Android.bp | 1 - 64 files changed, 339 insertions(+), 12113 deletions(-) delete mode 100644 libwvdrmengine/include_hidl/HidlMapErrors-inl.h delete mode 100644 libwvdrmengine/include_hidl/HidlTypes.h delete mode 100644 libwvdrmengine/include_hidl/HidlWVCreatePluginFactories.h delete mode 100644 libwvdrmengine/include_hidl/HidlWVDrmFactory.h delete mode 100644 libwvdrmengine/include_hidl/HidlWVTypes.h delete mode 100644 libwvdrmengine/include_hidl/TypeConvert.h delete mode 100644 libwvdrmengine/include_hidl/WVCryptoFactory.h delete mode 100644 libwvdrmengine/manifest_android.hardware.drm@1.2-service.widevine.xml delete mode 100644 libwvdrmengine/manifest_android.hardware.drm@1.3-service.widevine.xml delete mode 100644 libwvdrmengine/manifest_android.hardware.drm@1.4-service.widevine.xml delete mode 100644 libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h delete mode 100644 libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp delete mode 100644 libwvdrmengine/mediacrypto/test/hidl/WVCryptoPlugin_test.cpp delete mode 100644 libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h delete mode 100644 libwvdrmengine/mediadrm/include_hidl/WVGenericCryptoInterface.h delete mode 100644 libwvdrmengine/mediadrm/include_hidl/hidl_metrics_adapter.h delete mode 100644 libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp delete mode 100644 libwvdrmengine/mediadrm/src_hidl/WVGenericCryptoInterface.cpp delete mode 100644 libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp delete mode 100644 libwvdrmengine/mediadrm/test/hidl/WVDrmPlugin_test.cpp delete mode 100644 libwvdrmengine/mediadrm/test/hidl/hidl_metrics_adapter_unittest.cpp create mode 100644 libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c delete mode 100644 libwvdrmengine/prebuilts_hidl/arm/libwvhidl@1.3.so delete mode 100644 libwvdrmengine/prebuilts_hidl/arm64/libwvhidl@1.3.so delete mode 100644 libwvdrmengine/prebuilts_hidl/x86/libwvhidl@1.3.so delete mode 100644 libwvdrmengine/prebuilts_hidl/x86_64/libwvhidl@1.3.so delete mode 100644 libwvdrmengine/src_hidl/WVCreatePluginFactories.cpp delete mode 100644 libwvdrmengine/src_hidl/WVCryptoFactory.cpp delete mode 100644 libwvdrmengine/src_hidl/WVDrmFactory.cpp delete mode 100644 libwvdrmengine/src_hidl/android.hardware.drm@1.2-service-lazy.widevine.rc delete mode 100644 libwvdrmengine/src_hidl/android.hardware.drm@1.2-service.widevine.rc delete mode 100644 libwvdrmengine/src_hidl/android.hardware.drm@1.3-service-lazy.widevine.rc delete mode 100644 libwvdrmengine/src_hidl/android.hardware.drm@1.3-service.widevine.rc delete mode 100644 libwvdrmengine/src_hidl/android.hardware.drm@1.4-service-lazy.widevine.rc delete mode 100644 libwvdrmengine/src_hidl/android.hardware.drm@1.4-service.widevine.rc delete mode 100644 libwvdrmengine/src_hidl/service.cpp delete mode 100644 libwvdrmengine/src_hidl/service@1.3.cpp delete mode 100644 libwvdrmengine/src_hidl/serviceLazy.cpp delete mode 100644 libwvdrmengine/src_hidl/wv_metrics.cpp delete mode 100644 libwvdrmengine/test/unit/WVCreatePluginFactories_test.cpp delete mode 100644 libwvdrmengine/test/unit/WVCryptoFactory_test.cpp delete mode 100644 libwvdrmengine/test/unit/WVDrmFactory_test.cpp delete mode 100644 libwvdrmengine/test/unit/hidl/WVCreatePluginFactories_test.cpp delete mode 100644 libwvdrmengine/test/unit/hidl/WVCryptoFactory_test.cpp delete mode 100644 libwvdrmengine/test/unit/hidl/WVDrmFactory_test.cpp diff --git a/libwvdrmengine/Android.bp b/libwvdrmengine/Android.bp index 6c7ab650..07207d5a 100644 --- a/libwvdrmengine/Android.bp +++ b/libwvdrmengine/Android.bp @@ -89,31 +89,6 @@ common_widevine_service { }, } -cc_defaults { - name: "common_widevine_service-multilib-defaults@1.3", - owner: "widevine", - proprietary: true, - relative_install_path: "hw", - include_dirs: [ - "vendor/widevine/libwvdrmengine/include_hidl", - "vendor/widevine/libwvdrmengine/mediadrm/include_hidl", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - header_libs: ["libstagefright_foundation_headers"], - - shared_libs: [ - "android.hardware.drm@1.0", - "android.hardware.drm@1.1", - "android.hardware.drm@1.2", - "android.hardware.drm@1.3", - "libbase", - "libbinder", - "libhidlbase", - "liblog", - "libutils", - ], -} - cc_defaults { name: "common_widevine_service-multilib-defaults-aidl", owner: "widevine", @@ -136,118 +111,6 @@ cc_defaults { ], } -cc_defaults { - name: "common_widevine_service-multilib-defaults", - defaults: [ - "common_widevine_service-multilib-defaults@1.3", - ], - - shared_libs: [ - "android.hardware.drm@1.4", - "libwvhidl", - ], -} - -// ---------------------------------------------------------------------------- -// Builds android.hardware.drm@1.2-service.widevine -// -cc_binary { - name: "android.hardware.drm@1.2-service.widevine", - defaults: [ - "common_widevine_service-multilib-first", - "common_widevine_service-multilib-defaults", - ], - - srcs: ["src_hidl/service.cpp"], - init_rc: ["src_hidl/android.hardware.drm@1.2-service.widevine.rc"], - vintf_fragments: ["manifest_android.hardware.drm@1.2-service.widevine.xml"], - -} - -// ---------------------------------------------------------------------------- -// Builds android.hardware.drm@1.2-service-lazy.widevine -// -cc_binary { - name: "android.hardware.drm@1.2-service-lazy.widevine", - defaults: [ - "common_widevine_service-multilib-first", - "common_widevine_service-multilib-defaults", - ], - - srcs: ["src_hidl/serviceLazy.cpp"], - overrides: ["android.hardware.drm@1.2-service.widevine"], - init_rc: ["src_hidl/android.hardware.drm@1.2-service-lazy.widevine.rc"], - vintf_fragments: ["manifest_android.hardware.drm@1.2-service.widevine.xml"], - -} - -// ---------------------------------------------------------------------------- -// Builds android.hardware.drm@1.3-service.widevine -// -cc_binary { - name: "android.hardware.drm@1.3-service.widevine", - defaults: [ - "common_widevine_service-multilib-first", - "common_widevine_service-multilib-defaults@1.3", - ], - - srcs: ["src_hidl/service@1.3.cpp"], - shared_libs: ["libwvhidl@1.3"], - init_rc: ["src_hidl/android.hardware.drm@1.3-service.widevine.rc"], - vintf_fragments: ["manifest_android.hardware.drm@1.3-service.widevine.xml"], - -} - -// ---------------------------------------------------------------------------- -// Builds android.hardware.drm@1.3-service-lazy.widevine -// -cc_binary { - name: "android.hardware.drm@1.3-service-lazy.widevine", - defaults: [ - "common_widevine_service-multilib-first", - "common_widevine_service-multilib-defaults", - ], - - srcs: ["src_hidl/serviceLazy.cpp"], - overrides: ["android.hardware.drm@1.3-service.widevine"], - init_rc: ["src_hidl/android.hardware.drm@1.3-service-lazy.widevine.rc"], - vintf_fragments: ["manifest_android.hardware.drm@1.4-service.widevine.xml"], - -} - -// ---------------------------------------------------------------------------- -// Builds android.hardware.drm@1.4-service.widevine -// -cc_binary { - name: "android.hardware.drm@1.4-service.widevine", - defaults: [ - "common_widevine_service-multilib-first", - "common_widevine_service-multilib-defaults", - ], - - srcs: ["src_hidl/service.cpp"], - init_rc: ["src_hidl/android.hardware.drm@1.4-service.widevine.rc"], - vintf_fragments: ["manifest_android.hardware.drm@1.4-service.widevine.xml"], - -} - -// ---------------------------------------------------------------------------- -// Builds android.hardware.drm@1.4-service-lazy.widevine -// -cc_binary { - name: "android.hardware.drm@1.4-service-lazy.widevine", - defaults: [ - "common_widevine_service-multilib-first", - "common_widevine_service-multilib-defaults", - ], - - srcs: ["src_hidl/serviceLazy.cpp"], - overrides: ["android.hardware.drm@1.4-service.widevine"], - init_rc: ["src_hidl/android.hardware.drm@1.4-service-lazy.widevine.rc"], - vintf_fragments: ["manifest_android.hardware.drm@1.4-service.widevine.xml"], - -} - // ---------------------------------------------------------------------------- // Builds android.hardware.drm-service.widevine // @@ -293,64 +156,30 @@ cc_binary { } // ---------------------------------------------------------------------------- -// Builds libcdm_utils.a and libcdm_utils_hidl.a +// Builds libcdm_utils.a // - -cdm_util_src_files = [ - "cdm/core/src/properties.cpp", - "cdm/src/properties_android.cpp", - "cdm/src/timer.cpp", - "cdm/util/src/cdm_random.cpp", - "cdm/util/src/clock.cpp", - "cdm/util/src/error_string_util.cpp", - "cdm/util/src/file_store.cpp", - "cdm/util/src/file_utils.cpp", - "cdm/util/src/log.cpp", - "cdm/util/src/platform.cpp", - "cdm/util/src/rw_lock.cpp", - "cdm/util/src/string_conversions.cpp", - "cdm/util/src/string_format.cpp", -] - -cc_library_static { - - name: "libcdm_utils_hidl", - - proprietary: true, - - include_dirs: [ - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - header_libs: [ - "libbase_headers", - "libutils_headers", - ], - - shared_libs: [ - "libbinder_ndk", - "libcrypto", - "libhidlbase", - "liblog", - ], - - cflags: [ - "-DIS_HIDL", - ], - - srcs: cdm_util_src_files, - -} - cc_library_static { name: "libcdm_utils", proprietary: true, + srcs: [ + "cdm/core/src/properties.cpp", + "cdm/src/properties_android.cpp", + "cdm/src/timer.cpp", + "cdm/util/src/cdm_random.cpp", + "cdm/util/src/clock.cpp", + "cdm/util/src/error_string_util.cpp", + "cdm/util/src/file_store.cpp", + "cdm/util/src/file_utils.cpp", + "cdm/util/src/log.cpp", + "cdm/util/src/platform.cpp", + "cdm/util/src/rw_lock.cpp", + "cdm/util/src/string_conversions.cpp", + "cdm/util/src/string_format.cpp", + ], + include_dirs: [ "vendor/widevine/libwvdrmengine/cdm/core/include", "vendor/widevine/libwvdrmengine/cdm/include", @@ -366,117 +195,8 @@ cc_library_static { shared_libs: [ "libbinder_ndk", "libcrypto", - "libhidlbase", "liblog", ], - - srcs: cdm_util_src_files, -} - -// ---------------------------------------------------------------------------- -// Builds libwvhidl.so -// -cc_library_shared { - name: "libwvhidl", - - srcs: [ - "src/WVCDMSingleton.cpp", - "src/WVUUID.cpp", - "src_hidl/wv_metrics.cpp", - "src_hidl/WVCreatePluginFactories.cpp", - "src_hidl/WVCryptoFactory.cpp", - "src_hidl/WVDrmFactory.cpp", - ], - - include_dirs: [ - "frameworks/av/include", - "frameworks/native/include", - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/metrics/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/include", - "vendor/widevine/libwvdrmengine/include_hidl", - "vendor/widevine/libwvdrmengine/mediacrypto/include_hidl", - "vendor/widevine/libwvdrmengine/mediadrm/include_hidl", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - static_libs: [ - "libcdm", - "libcdm_protos", - "libcdm_utils_hidl", - "libjsmn", - "libwvdrmcryptoplugin_hidl", - "libwvdrmdrmplugin_hidl", - "libwvlevel3", - "libwv_odk", - ], - - shared_libs: [ - "android.hardware.drm@1.0", - "android.hardware.drm@1.1", - "android.hardware.drm@1.2", - "android.hardware.drm@1.3", - "android.hardware.drm@1.4", - "android.hidl.memory@1.0", - "libbase", - "libcrypto", - "libcutils", - "libdl", - "libhidlbase", - "libhidlmemory", - "liblog", - "libprotobuf-cpp-lite", - "libutils", - ], - - header_libs: ["libstagefright_foundation_headers"], - - owner: "widevine", - - proprietary: true, - -} - -cc_prebuilt_library_shared { - name: "libwvhidl@1.3", - target: { - android_arm: { - srcs: ["prebuilts_hidl/arm/libwvhidl@1.3.so"], - }, - android_arm64: { - srcs: ["prebuilts_hidl/arm64/libwvhidl@1.3.so"], - }, - android_x86: { - srcs: ["prebuilts_hidl/x86/libwvhidl@1.3.so"], - }, - android_x86_64: { - srcs: ["prebuilts_hidl/x86_64/libwvhidl@1.3.so"], - }, - }, - - shared_libs: [ - "android.hardware.drm@1.0", - "android.hardware.drm@1.1", - "android.hardware.drm@1.2", - "android.hardware.drm@1.3", - "android.hidl.memory@1.0", - "libbase", - "libcrypto", - "libcutils", - "libdl", - "libhidlbase", - "libhidlmemory", - "liblog", - "libprotobuf-cpp-lite", - "libutils", - ], - - owner: "widevine", - - proprietary: true, - } // ---------------------------------------------------------------------------- diff --git a/libwvdrmengine/build_all_unit_tests.sh b/libwvdrmengine/build_all_unit_tests.sh index 42636f0f..c95b0b4f 100755 --- a/libwvdrmengine/build_all_unit_tests.sh +++ b/libwvdrmengine/build_all_unit_tests.sh @@ -9,12 +9,9 @@ fi # Read arguments in case the user wants to do a multicore build or # copy files to a specific android device by providing a serial number. -# The default build target is for AIDL service, use "-t hidl" to -# build for HIDL service. -WV_UNITTESTS_BUILD_TARGET="" NUM_CORES=1 SERIAL_NUM="" -while getopts "j:s:t:" opt; do +while getopts "j:s:" opt; do case $opt in j) NUM_CORES=$OPTARG @@ -22,9 +19,6 @@ while getopts "j:s:t:" opt; do s) SERIAL_NUM="-s $OPTARG" ;; - t) - WV_UNITTESTS_BUILD_TARGET="WV_UNITTESTS_BUILD_TARGET=$OPTARG" - ;; esac done @@ -81,7 +75,7 @@ WV_UNITTESTS="base64_test \ cd $ANDROID_BUILD_TOP pwd -m -j $NUM_CORES $WV_UNITTESTS $WV_UNITTESTS_BUILD_TARGET +m -j $NUM_CORES $WV_UNITTESTS # Detect the device and check if Verity is going to stop the script from working diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h index 4aaaaff6..d67313c2 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_constants.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_constants.h @@ -61,11 +61,8 @@ constexpr char ATSC_APP_PACKAGE_NAME[] = "org.atsc"; // Define query keys, values here. // To expose these query items to Android update: // android/mediadrm/src/WVDrmPlugin.cpp -// android/mediadrm/src_hidl/WVDrmPlugin.cpp // Update test QueryStatus and QueryStatusL3 test for all possible outputs: // android/cdm/test/request_license_test.cpp -// Update HIDL debug output: -// android/src_hidl/WVDrmFactory.cpp static const std::string QUERY_KEY_LICENSE_TYPE = "LicenseType"; // "Streaming", "Offline" static const std::string QUERY_KEY_PLAY_ALLOWED = diff --git a/libwvdrmengine/cdm/core/include/wv_cdm_types.h b/libwvdrmengine/cdm/core/include/wv_cdm_types.h index 18d6cf57..14cd4cda 100644 --- a/libwvdrmengine/cdm/core/include/wv_cdm_types.h +++ b/libwvdrmengine/cdm/core/include/wv_cdm_types.h @@ -445,7 +445,6 @@ enum CdmResponseType : int32_t { // Don't forget to add new values to // * core/test/test_printers.cpp. // * android/include/mapErrors-inl.h - // * android/include_hidl/HidlMapErrors-inl.h }; enum CdmKeyStatus : int32_t { diff --git a/libwvdrmengine/cdm/test/coverage-test.mk b/libwvdrmengine/cdm/test/coverage-test.mk index 571c657a..c8e89a16 100644 --- a/libwvdrmengine/cdm/test/coverage-test.mk +++ b/libwvdrmengine/cdm/test/coverage-test.mk @@ -3,15 +3,6 @@ # include $(CLEAR_VARS) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) -HIDL_EXTENSION := _hidl -LIB_BINDER := libhidlbase -else -HIDL_EXTENSION := -LIB_BINDER := libbinder_ndk -endif - LOCAL_LICENSE_CONDITIONS := by_exception_only LOCAL_LICENSE_KINDS := legacy_by_exception_only LOCAL_MODULE := cdm_coverage_test @@ -69,7 +60,7 @@ LOCAL_C_INCLUDES += external/protobuf/src LOCAL_STATIC_LIBRARIES := \ libcdm \ libcdm_protos \ - libcdm_utils$(HIDL_EXTENSION) \ + libcdm_utils \ libjsmn \ libgmock \ libgtest \ @@ -81,7 +72,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libcrypto \ libdl \ - $(LIB_BINDER) \ + libbinder_ndk \ liblog \ libmedia_omx \ libprotobuf-cpp-lite \ diff --git a/libwvdrmengine/cdm/test/integration-test.mk b/libwvdrmengine/cdm/test/integration-test.mk index cd9eb659..f8907a06 100644 --- a/libwvdrmengine/cdm/test/integration-test.mk +++ b/libwvdrmengine/cdm/test/integration-test.mk @@ -6,15 +6,6 @@ $(call assert-not-null,test_name) include $(CLEAR_VARS) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) -HIDL_EXTENSION := _hidl -LIB_BINDER := libhidlbase -else -HIDL_EXTENSION := -LIB_BINDER := libbinder_ndk -endif - LOCAL_MODULE := $(test_name) LOCAL_LICENSE_KINDS := legacy_by_exception_only LOCAL_LICENSE_CONDITIONS := by_exception_only @@ -59,7 +50,7 @@ LOCAL_C_INCLUDES += external/protobuf/src LOCAL_STATIC_LIBRARIES := \ libcdm \ libcdm_protos \ - libcdm_utils$(HIDL_EXTENSION) \ + libcdm_utils \ libjsmn \ libgmock \ libgtest \ @@ -71,7 +62,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libcrypto \ libdl \ - $(LIB_BINDER) \ + libbinder_ndk \ liblog \ libmedia_omx \ libprotobuf-cpp-lite \ diff --git a/libwvdrmengine/cdm/test/unit-test.mk b/libwvdrmengine/cdm/test/unit-test.mk index 084f79df..e3d14a5d 100644 --- a/libwvdrmengine/cdm/test/unit-test.mk +++ b/libwvdrmengine/cdm/test/unit-test.mk @@ -6,15 +6,6 @@ $(call assert-not-null,test_name) include $(CLEAR_VARS) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) -HIDL_EXTENSION := _hidl -LIB_BINDER := libhidlbase -else -HIDL_EXTENSION := -LIB_BINDER := libbinder_ndk -endif - LOCAL_MODULE := $(test_name) LOCAL_LICENSE_KINDS := legacy_by_exception_only LOCAL_LICENSE_CONDITIONS := by_exception_only @@ -52,7 +43,7 @@ LOCAL_C_INCLUDES += external/protobuf/src LOCAL_STATIC_LIBRARIES := \ libcdm \ libcdm_protos \ - libcdm_utils$(HIDL_EXTENSION) \ + libcdm_utils \ libjsmn \ libgmock \ libgtest \ @@ -63,8 +54,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libcrypto \ libdl \ - libhidlbase \ - $(LIB_BINDER) \ + libbinder_ndk \ liblog \ libmedia_omx \ libprotobuf-cpp-lite \ diff --git a/libwvdrmengine/cdm/util/src/log.cpp b/libwvdrmengine/cdm/util/src/log.cpp index c8598bf2..4f09b009 100644 --- a/libwvdrmengine/cdm/util/src/log.cpp +++ b/libwvdrmengine/cdm/util/src/log.cpp @@ -23,11 +23,7 @@ #include "log.h" -#ifdef IS_HIDL -# include -#else // AIDL is the default -# include -#endif +#include #include #include #include @@ -80,12 +76,7 @@ void ClearLoggingUid() { uint32_t GetLoggingUid() { return tl_logging_uid_; } uint32_t GetIpcCallingUid() { -#ifdef IS_HIDL - const auto self = android::hardware::IPCThreadState::selfOrNull(); - return self ? self->getCallingUid() : UNKNOWN_UID; -#else // AIDL is the default return AIBinder_getCallingUid(); -#endif } void InitLogging() {} diff --git a/libwvdrmengine/include_hidl/HidlMapErrors-inl.h b/libwvdrmengine/include_hidl/HidlMapErrors-inl.h deleted file mode 100644 index a6d351d8..00000000 --- a/libwvdrmengine/include_hidl/HidlMapErrors-inl.h +++ /dev/null @@ -1,753 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_MAP_ERRORS_H_ -#define WV_MAP_ERRORS_H_ - -#include "media/stagefright/MediaErrors.h" -#include "utils/Errors.h" -#include "wv_cdm_types.h" -#include "HidlTypes.h" -#include "WVErrors.h" - -namespace wvdrm { - -static Status mapCdmResponseType_1_0(wvcdm::CdmResponseType res) { - switch (res) { - case wvcdm::KEY_ADDED: - case wvcdm::KEY_MESSAGE: - case wvcdm::KEY_CANCELED: - // KEY_ADDED, KEY_MESSAGE, and KEY_CANCELLED are all alternative - // success messages for certain CDM methods instead of NO_ERROR. - case wvcdm::NO_ERROR: - return Status::OK; - - case wvcdm::DECRYPT_NOT_READY: - case wvcdm::KEY_NOT_FOUND_IN_SESSION: - case wvcdm::NEED_KEY: - case wvcdm::NO_MATCHING_ENTITLEMENT_KEY: - // TODO(http://b/119690361): there are several NO_CONTENT_* errors. - // that should probably all turn into NO_LICENSE. Here, and below, and - // everywhere. - case wvcdm::NO_CONTENT_KEY_3: - return Status::ERROR_DRM_NO_LICENSE; - - case wvcdm::NEED_PROVISIONING: - return Status::ERROR_DRM_NOT_PROVISIONED; - - case wvcdm::DEVICE_REVOKED: - return Status::ERROR_DRM_DEVICE_REVOKED; - - case wvcdm::INSUFFICIENT_CRYPTO_RESOURCES: - return Status::ERROR_DRM_RESOURCE_BUSY; - - case wvcdm::RELEASE_USAGE_INFO_ERROR: - case wvcdm::RELEASE_USAGE_INFO_FAILED: - case wvcdm::SYSTEM_INVALIDATED_ERROR: - return Status::ERROR_DRM_INVALID_STATE; - - case wvcdm::SESSION_NOT_FOUND_FOR_DECRYPT: - case wvcdm::SESSION_NOT_FOUND_1: - case wvcdm::SESSION_NOT_FOUND_2: - case wvcdm::SESSION_NOT_FOUND_3: - case wvcdm::SESSION_NOT_FOUND_4: - case wvcdm::SESSION_NOT_FOUND_5: - case wvcdm::SESSION_NOT_FOUND_6: - case wvcdm::SESSION_NOT_FOUND_7: - case wvcdm::SESSION_NOT_FOUND_8: - case wvcdm::SESSION_NOT_FOUND_9: - case wvcdm::SESSION_NOT_FOUND_10: - case wvcdm::SESSION_NOT_FOUND_18: - case wvcdm::SESSION_NOT_FOUND_19: - case wvcdm::SESSION_NOT_FOUND_20: - case wvcdm::SESSION_NOT_FOUND_21: - case wvcdm::SESSION_NOT_FOUND_22: - case wvcdm::SESSION_NOT_FOUND_23: - return Status::ERROR_DRM_SESSION_NOT_OPENED; - - case wvcdm::DECRYPT_ERROR: - case wvcdm::SECURE_BUFFER_REQUIRED: - return Status::ERROR_DRM_CANNOT_HANDLE; - - case wvcdm::ANALOG_OUTPUT_ERROR: - case wvcdm::KEY_PROHIBITED_FOR_SECURITY_LEVEL: - case wvcdm::INSUFFICIENT_OUTPUT_PROTECTION: - return Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION; - - case wvcdm::KEYSET_ID_NOT_FOUND_4: - return Status::BAD_VALUE; - - // The following cases follow the order in wv_cdm_types.h - // to make it easier to keep track of newly defined errors. - case wvcdm::KEY_ERROR: - case wvcdm::ADD_KEY_ERROR: - case wvcdm::CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE: - case wvcdm::CERT_PROVISIONING_GET_KEYBOX_ERROR_1: - case wvcdm::CERT_PROVISIONING_INVALID_CERT_TYPE: - case wvcdm::CERT_PROVISIONING_REQUEST_ERROR_1: - case wvcdm::CERT_PROVISIONING_NONCE_GENERATION_ERROR: - case wvcdm::CERT_PROVISIONING_REQUEST_ERROR_4: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_1: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_2: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_3: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_4: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_7: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_8: - case wvcdm::DEVICE_CERTIFICATE_ERROR_1: - case wvcdm::DEVICE_CERTIFICATE_ERROR_2: - case wvcdm::DEVICE_CERTIFICATE_ERROR_3: - case wvcdm::DEVICE_CERTIFICATE_ERROR_4: - case wvcdm::EMPTY_KEY_DATA_1: - case wvcdm::EMPTY_KEY_DATA_2: - case wvcdm::EMPTY_KEYSET_ID: - case wvcdm::EMPTY_KEYSET_ID_ENG_1: - case wvcdm::EMPTY_KEYSET_ID_ENG_2: - case wvcdm::EMPTY_KEYSET_ID_ENG_3: - case wvcdm::EMPTY_KEYSET_ID_ENG_4: - case wvcdm::EMPTY_LICENSE_RENEWAL: - case wvcdm::EMPTY_LICENSE_RESPONSE_1: - case wvcdm::EMPTY_LICENSE_RESPONSE_2: - case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_1: - case wvcdm::EMPTY_PROVISIONING_RESPONSE: - case wvcdm::EMPTY_SESSION_ID: - case wvcdm::GENERATE_DERIVED_KEYS_ERROR: - case wvcdm::LICENSE_RENEWAL_NONCE_GENERATION_ERROR: - case wvcdm::GENERATE_USAGE_REPORT_ERROR: - case wvcdm::GET_LICENSE_ERROR: - case wvcdm::GET_RELEASED_LICENSE_ERROR: - case wvcdm::GET_USAGE_INFO_ERROR_1: - case wvcdm::GET_USAGE_INFO_ERROR_2: - case wvcdm::GET_USAGE_INFO_ERROR_3: - case wvcdm::GET_USAGE_INFO_ERROR_4: - case wvcdm::INIT_DATA_NOT_FOUND: - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_1: - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_2: - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_3: - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_4: - case wvcdm::INVALID_DEVICE_CERTIFICATE_TYPE: - case wvcdm::INVALID_KEY_SYSTEM: - case wvcdm::INVALID_LICENSE_RESPONSE: - case wvcdm::INVALID_LICENSE_TYPE: - case wvcdm::PARAMETER_NULL: - case wvcdm::INVALID_PARAMETERS_LIC_1: - case wvcdm::INVALID_PARAMETERS_LIC_2: - case wvcdm::INVALID_PROVISIONING_PARAMETERS_1: - case wvcdm::INVALID_PROVISIONING_PARAMETERS_2: - case wvcdm::INVALID_PROVISIONING_REQUEST_PARAM_1: - case wvcdm::INVALID_PROVISIONING_REQUEST_PARAM_2: - case wvcdm::INVALID_QUERY_KEY: - case wvcdm::INVALID_SESSION_ID: - case wvcdm::KEY_REQUEST_ERROR_1: - case wvcdm::KEY_SIZE_ERROR_1: - case wvcdm::KEY_SIZE_ERROR_2: - case wvcdm::KEYSET_ID_NOT_FOUND_1: - case wvcdm::KEYSET_ID_NOT_FOUND_2: - case wvcdm::KEYSET_ID_NOT_FOUND_3: - case wvcdm::LICENSE_ID_NOT_FOUND: - case wvcdm::LICENSE_PARSER_INIT_ERROR: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_1: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_2: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_3: - case wvcdm::LICENSE_RESPONSE_NOT_SIGNED: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_1: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_2: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_3: - case wvcdm::LOAD_KEY_ERROR: - case wvcdm::NO_CONTENT_KEY: - case wvcdm::REFRESH_KEYS_ERROR: - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_1: - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_2: - case wvcdm::RELEASE_KEY_ERROR: - case wvcdm::RELEASE_KEY_REQUEST_ERROR: - case wvcdm::RELEASE_LICENSE_ERROR_1: - case wvcdm::RELEASE_LICENSE_ERROR_2: - case wvcdm::RENEW_KEY_ERROR_1: - case wvcdm::RENEW_KEY_ERROR_2: - case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_2: - case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3: - case wvcdm::NOT_INITIALIZED_ERROR: - case wvcdm::REINIT_ERROR: - case wvcdm::SESSION_KEYS_NOT_FOUND: - case wvcdm::SIGNATURE_NOT_FOUND: - case wvcdm::STORE_LICENSE_ERROR_1: - case wvcdm::STORE_LICENSE_ERROR_2: - case wvcdm::STORE_USAGE_INFO_ERROR: - case wvcdm::UNPROVISION_ERROR_1: - case wvcdm::UNPROVISION_ERROR_2: - case wvcdm::UNPROVISION_ERROR_3: - case wvcdm::UNPROVISION_ERROR_4: - case wvcdm::UNSUPPORTED_INIT_DATA: - case wvcdm::USAGE_INFO_NOT_FOUND: - case wvcdm::PARSE_SERVICE_CERTIFICATE_ERROR: - case wvcdm::CLIENT_ID_GENERATE_RANDOM_ERROR: - case wvcdm::CLIENT_ID_AES_INIT_ERROR: - case wvcdm::CLIENT_ID_AES_ENCRYPT_ERROR: - case wvcdm::CLIENT_ID_RSA_INIT_ERROR: - case wvcdm::CLIENT_ID_RSA_ENCRYPT_ERROR: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_4: - case wvcdm::INVALID_PARAMETERS_LIC_3: - case wvcdm::INVALID_PARAMETERS_LIC_4: - case wvcdm::INVALID_PARAMETERS_LIC_6: - case wvcdm::INVALID_PARAMETERS_LIC_7: - case wvcdm::CENC_INIT_DATA_UNAVAILABLE: - case wvcdm::PREPARE_CENC_CONTENT_ID_FAILED: - case wvcdm::WEBM_INIT_DATA_UNAVAILABLE: - case wvcdm::PREPARE_WEBM_CONTENT_ID_FAILED: - case wvcdm::UNSUPPORTED_INIT_DATA_FORMAT: - case wvcdm::LICENSE_REQUEST_NONCE_GENERATION_ERROR: - case wvcdm::LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR: - case wvcdm::EMPTY_LICENSE_REQUEST: - case wvcdm::DUPLICATE_SESSION_ID_SPECIFIED: - case wvcdm::LICENSE_RENEWAL_PROHIBITED: - case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_2: - case wvcdm::OFFLINE_LICENSE_PROHIBITED: - case wvcdm::STORAGE_PROHIBITED: - case wvcdm::EMPTY_KEYSET_ID_ENG_5: - case wvcdm::SESSION_NOT_FOUND_11: - case wvcdm::LOAD_USAGE_INFO_FILE_ERROR: - case wvcdm::LOAD_USAGE_INFO_MISSING: - case wvcdm::SESSION_FILE_HANDLE_INIT_ERROR: - case wvcdm::INCORRECT_CRYPTO_MODE: - case wvcdm::INVALID_PARAMETERS_ENG_5: - case wvcdm::SESSION_NOT_FOUND_12: - case wvcdm::KEY_NOT_FOUND_1: - case wvcdm::KEY_NOT_FOUND_2: - case wvcdm::KEY_CONFLICT_1: - case wvcdm::SESSION_NOT_FOUND_13: - case wvcdm::SESSION_NOT_FOUND_14: - case wvcdm::SESSION_NOT_FOUND_15: - case wvcdm::SESSION_NOT_FOUND_16: - case wvcdm::KEY_NOT_FOUND_3: - case wvcdm::KEY_NOT_FOUND_4: - case wvcdm::KEY_NOT_FOUND_5: - case wvcdm::KEY_NOT_FOUND_6: - case wvcdm::INVALID_SESSION_1: - case wvcdm::NO_DEVICE_KEY_1: - case wvcdm::NO_CONTENT_KEY_2: - case wvcdm::INVALID_PARAMETERS_ENG_13: - case wvcdm::INVALID_PARAMETERS_ENG_14: - case wvcdm::INVALID_PARAMETERS_ENG_15: - case wvcdm::INVALID_PARAMETERS_ENG_16: - case wvcdm::CLIENT_IDENTIFICATION_TOKEN_ERROR_1: - case wvcdm::UNKNOWN_SELECT_KEY_ERROR_1: - case wvcdm::UNKNOWN_SELECT_KEY_ERROR_2: - case wvcdm::CREATE_USAGE_TABLE_ERROR: - case wvcdm::LOAD_USAGE_HEADER_GENERATION_SKEW: - case wvcdm::LOAD_USAGE_HEADER_SIGNATURE_FAILURE: - case wvcdm::LOAD_USAGE_HEADER_BAD_MAGIC: - case wvcdm::LOAD_USAGE_HEADER_UNKNOWN_ERROR: - case wvcdm::CREATE_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::LOAD_USAGE_ENTRY_GENERATION_SKEW: - case wvcdm::LOAD_USAGE_ENTRY_SIGNATURE_FAILURE: - case wvcdm::LOAD_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::UPDATE_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR: - case wvcdm::MOVE_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::COPY_OLD_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::INVALID_PARAMETERS_ENG_22: - case wvcdm::INVALID_PARAMETERS_ENG_23: - case wvcdm::USAGE_INFORMATION_SUPPORT_FAILED: - case wvcdm::USAGE_SUPPORT_GET_API_FAILED: - case wvcdm::UNEXPECTED_EMPTY_USAGE_ENTRY: - case wvcdm::INVALID_USAGE_ENTRY_NUMBER_MODIFICATION: - case wvcdm::USAGE_INVALID_NEW_ENTRY: - case wvcdm::USAGE_INVALID_PARAMETERS_1: - case wvcdm::USAGE_ENTRY_NUMBER_MISMATCH: - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED: - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_USAGE_INFO_FAILED: - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_LICENSE_FAILED: - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_USAGE_INFO_FAILED: - case wvcdm::USAGE_STORE_LICENSE_FAILED: - case wvcdm::USAGE_STORE_USAGE_INFO_FAILED: - case wvcdm::USAGE_INVALID_LOAD_ENTRY: - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_5: - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_6: - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_7: - case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_1: - case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2: - case wvcdm::NO_USAGE_ENTRIES: - case wvcdm::LIST_LICENSE_ERROR_1: - case wvcdm::LIST_LICENSE_ERROR_2: - case wvcdm::LIST_USAGE_ERROR_1: - case wvcdm::LIST_USAGE_ERROR_2: - case wvcdm::DELETE_USAGE_ERROR_1: - case wvcdm::DELETE_USAGE_ERROR_2: - case wvcdm::DELETE_USAGE_ERROR_3: - case wvcdm::PRIVACY_MODE_ERROR_1: - case wvcdm::PRIVACY_MODE_ERROR_2: - case wvcdm::PRIVACY_MODE_ERROR_3: - case wvcdm::EMPTY_RESPONSE_ERROR_1: - case wvcdm::INVALID_PARAMETERS_ENG_24: - case wvcdm::PARSE_RESPONSE_ERROR_1: - case wvcdm::PARSE_RESPONSE_ERROR_2: - case wvcdm::PARSE_RESPONSE_ERROR_3: - case wvcdm::PARSE_RESPONSE_ERROR_4: - case wvcdm::LOAD_SYSTEM_ID_ERROR: - case wvcdm::REMOVE_USAGE_INFO_ERROR_1: - case wvcdm::REMOVE_USAGE_INFO_ERROR_2: - case wvcdm::REMOVE_USAGE_INFO_ERROR_3: - case wvcdm::NOT_AN_ENTITLEMENT_SESSION: - case wvcdm::LOAD_ENTITLED_CONTENT_KEYS_ERROR: - case wvcdm::GET_PROVISIONING_METHOD_ERROR: - case wvcdm::INVALID_SESSION_2: - case wvcdm::DEVICE_CANNOT_REPROVISION: - case wvcdm::SET_DECRYPT_HASH_ERROR: - case wvcdm::GET_DECRYPT_HASH_ERROR: - case wvcdm::INVALID_DECRYPT_HASH_FORMAT: - case wvcdm::EMPTY_LICENSE_REQUEST_2: - case wvcdm::EMPTY_LICENSE_REQUEST_3: - case wvcdm::EMPTY_LICENSE_RESPONSE_3: - case wvcdm::EMPTY_LICENSE_RESPONSE_4: - case wvcdm::PARSE_REQUEST_ERROR_1: - case wvcdm::PARSE_REQUEST_ERROR_2: - case wvcdm::INVALID_LICENSE_REQUEST_TYPE_1: - case wvcdm::INVALID_LICENSE_REQUEST_TYPE_2: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_4: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_5: - case wvcdm::INVALID_LICENSE_TYPE_2: - case wvcdm::SIGNATURE_NOT_FOUND_2: - case wvcdm::SESSION_KEYS_NOT_FOUND_2: - case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_1: - case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_2: - case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_1: - case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_2: - case wvcdm::OUTPUT_TOO_LARGE_ERROR: - case wvcdm::SESSION_LOST_STATE_ERROR: - case wvcdm::GENERATE_DERIVED_KEYS_ERROR_2: - case wvcdm::LOAD_DEVICE_RSA_KEY_ERROR: - case wvcdm::NONCE_GENERATION_ERROR: - case wvcdm::GENERATE_SIGNATURE_ERROR: - case wvcdm::UNKNOWN_CLIENT_TOKEN_TYPE: - case wvcdm::DEACTIVATE_USAGE_ENTRY_ERROR: - case wvcdm::SERVICE_CERTIFICATE_PROVIDER_ID_EMPTY: - case wvcdm::OPEN_CRYPTO_SESSION_ERROR: - case wvcdm::LOAD_SRM_ERROR: - case wvcdm::RANDOM_GENERATION_ERROR: - case wvcdm::CRYPTO_SESSION_NOT_INITIALIZED: - case wvcdm::GET_DEVICE_ID_ERROR: - case wvcdm::GET_TOKEN_FROM_OEM_CERT_ERROR: - case wvcdm::CRYPTO_SESSION_NOT_OPEN: - case wvcdm::GET_TOKEN_FROM_KEYBOX_ERROR: - case wvcdm::KEYBOX_TOKEN_TOO_SHORT: - case wvcdm::EXTRACT_SYSTEM_ID_FROM_OEM_CERT_ERROR: - case wvcdm::RSA_SIGNATURE_GENERATION_ERROR: - case wvcdm::GET_HDCP_CAPABILITY_FAILED: - case wvcdm::GET_NUMBER_OF_OPEN_SESSIONS_ERROR: - case wvcdm::GET_MAX_NUMBER_OF_OPEN_SESSIONS_ERROR: - case wvcdm::NOT_IMPLEMENTED_ERROR: - case wvcdm::GET_SRM_VERSION_ERROR: - case wvcdm::REWRAP_DEVICE_RSA_KEY_ERROR: - case wvcdm::INVALID_SRM_LIST: - case wvcdm::USAGE_INVALID_PARAMETERS_2: - case wvcdm::CORE_MESSAGE_NOT_FOUND: - case wvcdm::LOAD_PROVISIONING_ERROR: - case wvcdm::LOAD_LICENSE_ERROR: - case wvcdm::LOAD_RENEWAL_ERROR: - case wvcdm::CANNOT_DECRYPT_ZERO_SAMPLES: - case wvcdm::CANNOT_DECRYPT_ZERO_SUBSAMPLES: - case wvcdm::SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH: - case wvcdm::INVALID_IV_SIZE: - case wvcdm::LOAD_USAGE_ENTRY_INVALID_SESSION: - case wvcdm::MOVE_USAGE_ENTRY_DESTINATION_IN_USE: - case wvcdm::SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE: - case wvcdm::LICENSE_USAGE_ENTRY_MISSING: - case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: - case wvcdm::NO_SRM_VERSION: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: - case wvcdm::CLIENT_TOKEN_NOT_SET: - case wvcdm::USAGE_ENTRY_ALREADY_LOADED: - case wvcdm::PARSE_OKP_RESPONSE_ERROR: - case wvcdm::OKP_ALREADY_PROVISIONED: - case wvcdm::PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR: - case wvcdm::GET_BOOT_CERTIFICATE_CHAIN_ERROR: - case wvcdm::GENERATE_CERTIFICATE_KEY_PAIR_ERROR: - case wvcdm::GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_ERROR: - case wvcdm::LOAD_OEM_CERTIFICATE_PRIVATE_KEY_ERROR: - case wvcdm::PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN: - case wvcdm::PROVISIONING_4_FILE_SYSTEM_IS_NULL: - case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES: - case wvcdm::PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE: - case wvcdm::PROVISIONING_4_RESPONSE_HAS_ERROR_STATUS: - case wvcdm::PROVISIONING_4_RESPONSE_HAS_NO_CERTIFICATE: - case wvcdm::PROVISIONING_4_NO_PRIVATE_KEY: - case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2: - case wvcdm::PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE: - case wvcdm::PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE: - case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_3: - ALOGW("Returns UNKNOWN error for legacy status: %d", res); - return Status::ERROR_DRM_UNKNOWN; - - case wvcdm::UNKNOWN_ERROR: - return Status::ERROR_DRM_UNKNOWN; - } - - // Return here instead of as a default case so that the compiler will warn - // us if we forget to include an enum member in the switch statement. - return Status::ERROR_DRM_UNKNOWN; -} - -static Status_V1_2 mapCdmResponseType_1_2( - wvcdm::CdmResponseType res) { - switch(res) { - case wvcdm::KEY_PROHIBITED_FOR_SECURITY_LEVEL: - return Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY; - case wvcdm::OUTPUT_TOO_LARGE_ERROR: - return Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE; - case wvcdm::SESSION_LOST_STATE_ERROR: - return Status_V1_2::ERROR_DRM_SESSION_LOST_STATE; - case wvcdm::LICENSE_REQUEST_NONCE_GENERATION_ERROR: - case wvcdm::LICENSE_RENEWAL_NONCE_GENERATION_ERROR: - case wvcdm::CERT_PROVISIONING_NONCE_GENERATION_ERROR: - case wvcdm::NONCE_GENERATION_ERROR: - // These are likely nonce flood errors - return Status_V1_2::ERROR_DRM_RESOURCE_CONTENTION; - - default: - return static_cast(mapCdmResponseType_1_0(res)); - } -} - -template -static S mapCdmResponseType(wvcdm::CdmResponseType res) { - ::drm::V1_4::Status err = ::drm::V1_4::Status::ERROR_DRM_UNKNOWN; - switch(res) { - case wvcdm::CANNOT_DECRYPT_ZERO_SUBSAMPLES: - err = ::drm::V1_4::Status::CANNOT_DECRYPT_ZERO_SUBSAMPLES; - break; - case wvcdm::CLIENT_ID_AES_ENCRYPT_ERROR: - case wvcdm::CLIENT_ID_AES_INIT_ERROR: - case wvcdm::CLIENT_ID_RSA_ENCRYPT_ERROR: - err = ::drm::V1_4::Status::CRYPTO_LIBRARY_ERROR; - break; - case wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC: - err = ::drm::V1_4::Status::ERROR_DRM_CANNOT_HANDLE; - break; - case wvcdm::CERT_PROVISIONING_REQUEST_ERROR_4: - case wvcdm::CLIENT_IDENTIFICATION_TOKEN_ERROR_1: - case wvcdm::CREATE_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::CREATE_USAGE_TABLE_ERROR: - case wvcdm::DEACTIVATE_USAGE_ENTRY_ERROR: - case wvcdm::EMPTY_LICENSE_RENEWAL: - case wvcdm::EMPTY_LICENSE_REQUEST: - case wvcdm::EXTRACT_SYSTEM_ID_FROM_OEM_CERT_ERROR: - case wvcdm::GENERATE_DERIVED_KEYS_ERROR: - case wvcdm::GENERATE_DERIVED_KEYS_ERROR_2: - case wvcdm::GENERATE_SIGNATURE_ERROR: - case wvcdm::GENERATE_USAGE_REPORT_ERROR: - case wvcdm::GET_DECRYPT_HASH_ERROR: - case wvcdm::GET_DEVICE_ID_ERROR: - case wvcdm::GET_HDCP_CAPABILITY_FAILED: - case wvcdm::GET_MAX_NUMBER_OF_OPEN_SESSIONS_ERROR: - case wvcdm::GET_NUMBER_OF_OPEN_SESSIONS_ERROR: - case wvcdm::GET_PROVISIONING_METHOD_ERROR: - case wvcdm::GET_SRM_VERSION_ERROR: - case wvcdm::GET_TOKEN_FROM_KEYBOX_ERROR: - case wvcdm::GET_TOKEN_FROM_OEM_CERT_ERROR: - case wvcdm::INVALID_DECRYPT_HASH_FORMAT: - case wvcdm::INVALID_SESSION_1: - case wvcdm::INVALID_SESSION_2: - case wvcdm::KEYBOX_TOKEN_TOO_SHORT: - case wvcdm::LOAD_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::LOAD_USAGE_HEADER_UNKNOWN_ERROR: - case wvcdm::MOVE_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::OPEN_CRYPTO_SESSION_ERROR: - case wvcdm::RANDOM_GENERATION_ERROR: - case wvcdm::SET_DECRYPT_HASH_ERROR: - case wvcdm::SHRINK_USAGE_TABLE_HEADER_UNKNOWN_ERROR: - case wvcdm::UNKNOWN_CLIENT_TOKEN_TYPE: - case wvcdm::UNKNOWN_SELECT_KEY_ERROR_1: - case wvcdm::UNKNOWN_SELECT_KEY_ERROR_2: - case wvcdm::UPDATE_USAGE_ENTRY_UNKNOWN_ERROR: - case wvcdm::USAGE_SUPPORT_GET_API_FAILED: - err = ::drm::V1_4::Status::GENERAL_OEM_ERROR; - break; - case wvcdm::CANNOT_DECRYPT_ZERO_SAMPLES: - case wvcdm::CERT_PROVISIONING_REQUEST_ERROR_1: - case wvcdm::CLIENT_TOKEN_NOT_SET: - case wvcdm::CRYPTO_SESSION_NOT_INITIALIZED: - case wvcdm::CRYPTO_SESSION_NOT_OPEN: - case wvcdm::DEVICE_CANNOT_REPROVISION: - case wvcdm::DEVICE_CERTIFICATE_ERROR_1: - case wvcdm::DUPLICATE_SESSION_ID_SPECIFIED: - case wvcdm::EMPTY_KEYSET_ID_ENG_5: - case wvcdm::EMPTY_RESPONSE_ERROR_1: - case wvcdm::EMPTY_SESSION_ID: - case wvcdm::GENERATE_CERTIFICATE_KEY_PAIR_ERROR: - case wvcdm::GENERATE_CERTIFICATE_KEY_PAIR_UNKNOWN_TYPE_ERROR: - case wvcdm::GET_BOOT_CERTIFICATE_CHAIN_ERROR: - case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_1: - case wvcdm::INCORRECT_USAGE_SUPPORT_TYPE_2: - case wvcdm::INVALID_IV_SIZE: - case wvcdm::INVALID_KEY_SYSTEM: - case wvcdm::INVALID_PARAMETERS_ENG_22: - case wvcdm::INVALID_PARAMETERS_ENG_23: - case wvcdm::INVALID_PARAMETERS_ENG_24: - case wvcdm::INVALID_PARAMETERS_LIC_1: - case wvcdm::INVALID_PARAMETERS_LIC_2: - case wvcdm::INVALID_PARAMETERS_LIC_6: - case wvcdm::INVALID_PARAMETERS_LIC_7: - case wvcdm::INVALID_PROVISIONING_PARAMETERS_1: - case wvcdm::INVALID_PROVISIONING_PARAMETERS_2: - case wvcdm::INVALID_PROVISIONING_REQUEST_PARAM_1: - case wvcdm::INVALID_PROVISIONING_REQUEST_PARAM_2: - case wvcdm::INVALID_SESSION_ID: - case wvcdm::KEYSET_ID_NOT_FOUND_1: - case wvcdm::KEYSET_ID_NOT_FOUND_2: - case wvcdm::KEYSET_ID_NOT_FOUND_3: - case wvcdm::KEY_CONFLICT_1: - case wvcdm::KEY_NOT_FOUND_2: - case wvcdm::KEY_REQUEST_ERROR_1: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_1: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_2: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_3: - case wvcdm::LICENSE_PARSER_NOT_INITIALIZED_4: - case wvcdm::LICENSE_REQUEST_SERVICE_CERTIFICATE_GENERATION_ERROR: - case wvcdm::LICENSE_USAGE_ENTRY_MISSING: - case wvcdm::LOAD_ENTITLED_CONTENT_KEYS_ERROR: - case wvcdm::LOAD_OEM_CERTIFICATE_PRIVATE_KEY_ERROR: - case wvcdm::LOAD_USAGE_ENTRY_GENERATION_SKEW: - case wvcdm::LOAD_USAGE_ENTRY_INVALID_SESSION: - case wvcdm::LOAD_USAGE_ENTRY_SIGNATURE_FAILURE: - case wvcdm::LOAD_USAGE_HEADER_BAD_MAGIC: - case wvcdm::LOAD_USAGE_HEADER_GENERATION_SKEW: - case wvcdm::LOAD_USAGE_HEADER_SIGNATURE_FAILURE: - case wvcdm::LOAD_USAGE_INFO_MISSING: - case wvcdm::MOVE_USAGE_ENTRY_DESTINATION_IN_USE: - case wvcdm::NOT_IMPLEMENTED_ERROR: - case wvcdm::NOT_INITIALIZED_ERROR: - case wvcdm::NO_SRM_VERSION: - case wvcdm::NO_USAGE_ENTRIES: - case wvcdm::PARAMETER_NULL: - case wvcdm::PREPARE_CENC_CONTENT_ID_FAILED: - case wvcdm::PREPARE_WEBM_CONTENT_ID_FAILED: - case wvcdm::PROVISIONING_4_CRYPTO_SESSION_NOT_OPEN: - case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES: - case wvcdm::PROVISIONING_4_FILE_SYSTEM_IS_NULL: - case wvcdm::PROVISIONING_4_NO_PRIVATE_KEY: - case wvcdm::PROVISIONING_TYPE_IS_NOT_BOOT_CERTIFICATE_CHAIN_ERROR: - case wvcdm::REINIT_ERROR: - case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_2: - case wvcdm::REMOVE_USAGE_INFO_ERROR_3: - case wvcdm::SESSION_NOT_FOUND_11: - case wvcdm::SESSION_NOT_FOUND_12: - case wvcdm::SESSION_NOT_FOUND_13: - case wvcdm::SESSION_NOT_FOUND_14: - case wvcdm::SESSION_NOT_FOUND_15: - case wvcdm::SESSION_NOT_FOUND_16: - case wvcdm::SHRINK_USAGE_TABLE_HEADER_ENTRY_IN_USE: - case wvcdm::STORAGE_PROHIBITED: - case wvcdm::STORE_LICENSE_ERROR_2: - case wvcdm::USAGE_ENTRY_NUMBER_MISMATCH: - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: - case wvcdm::USAGE_INFORMATION_SUPPORT_FAILED: - case wvcdm::USAGE_INVALID_LOAD_ENTRY: - case wvcdm::USAGE_INVALID_NEW_ENTRY: - case wvcdm::USAGE_INVALID_PARAMETERS_1: - case wvcdm::USAGE_INVALID_PARAMETERS_2: - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_INVALID_STORAGE_TYPE: - err = ::drm::V1_4::Status::GENERAL_PLUGIN_ERROR; - break; - case wvcdm::CLIENT_ID_GENERATE_RANDOM_ERROR: - err = ::drm::V1_4::Status::ERROR_DRM_RESOURCE_CONTENTION; - break; - case wvcdm::CENC_INIT_DATA_UNAVAILABLE: - case wvcdm::INIT_DATA_NOT_FOUND: - case wvcdm::INVALID_PARAMETERS_LIC_3: - case wvcdm::INVALID_PARAMETERS_LIC_4: - case wvcdm::UNSUPPORTED_INIT_DATA: - case wvcdm::UNSUPPORTED_INIT_DATA_FORMAT: - case wvcdm::WEBM_INIT_DATA_UNAVAILABLE: - err = ::drm::V1_4::Status::INIT_DATA_INVALID; - break; - case wvcdm::EMPTY_KEYSET_ID: - case wvcdm::EMPTY_KEYSET_ID_ENG_1: - case wvcdm::EMPTY_KEYSET_ID_ENG_2: - case wvcdm::EMPTY_KEYSET_ID_ENG_3: - case wvcdm::EMPTY_KEYSET_ID_ENG_4: - case wvcdm::EMPTY_LICENSE_RESPONSE_1: - case wvcdm::EMPTY_LICENSE_RESPONSE_2: - case wvcdm::EMPTY_PROVISIONING_RESPONSE: - case wvcdm::INVALID_PARAMETERS_ENG_13: - case wvcdm::INVALID_PARAMETERS_ENG_14: - case wvcdm::INVALID_PARAMETERS_ENG_15: - case wvcdm::INVALID_PARAMETERS_ENG_16: - case wvcdm::INVALID_QUERY_KEY: - case wvcdm::KEY_NOT_FOUND_1: - case wvcdm::SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH: - err = ::drm::V1_4::Status::BAD_VALUE; - break; - case wvcdm::KEY_NOT_FOUND_3: - case wvcdm::KEY_NOT_FOUND_4: - case wvcdm::KEY_NOT_FOUND_5: - case wvcdm::KEY_NOT_FOUND_6: - err = ::drm::V1_4::Status::KEY_NOT_LOADED; - break; - case wvcdm::ADD_KEY_ERROR: - case wvcdm::CORE_MESSAGE_NOT_FOUND: - case wvcdm::EMPTY_KEY_DATA_1: - case wvcdm::EMPTY_KEY_DATA_2: - case wvcdm::INVALID_LICENSE_RESPONSE: - case wvcdm::INVALID_LICENSE_TYPE: - case wvcdm::INVALID_SRM_LIST: - case wvcdm::KEY_SIZE_ERROR_1: - case wvcdm::KEY_SIZE_ERROR_2: - case wvcdm::LICENSE_ID_NOT_FOUND: - case wvcdm::LICENSE_RESPONSE_NOT_SIGNED: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_1: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_2: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_3: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_4: - case wvcdm::LICENSE_RESPONSE_PARSE_ERROR_5: - case wvcdm::LOAD_KEY_ERROR: - case wvcdm::LOAD_LICENSE_ERROR: - case wvcdm::LOAD_RENEWAL_ERROR: - case wvcdm::LOAD_SRM_ERROR: - case wvcdm::NOT_AN_ENTITLEMENT_SESSION: - case wvcdm::NO_CONTENT_KEY: - case wvcdm::NO_CONTENT_KEY_2: - case wvcdm::NO_DEVICE_KEY_1: - case wvcdm::PROVISIONING_4_RESPONSE_FAILED_TO_PARSE_MESSAGE: - case wvcdm::REFRESH_KEYS_ERROR: - case wvcdm::SESSION_KEYS_NOT_FOUND: - case wvcdm::SIGNATURE_NOT_FOUND: - err = ::drm::V1_4::Status::LICENSE_PARSE_ERROR; - break; - case wvcdm::LICENSE_RENEWAL_PROHIBITED: - case wvcdm::OFFLINE_LICENSE_PROHIBITED: - err = ::drm::V1_4::Status::LICENSE_POLICY_ERROR; - break; - case wvcdm::PARSE_REQUEST_ERROR_2: - case wvcdm::RELEASE_LICENSE_ERROR_1: - case wvcdm::SESSION_KEYS_NOT_FOUND_2: - err = ::drm::V1_4::Status::LICENSE_RELEASE_ERROR; - break; - case wvcdm::KEY_ERROR: - case wvcdm::RELEASE_KEY_ERROR: - case wvcdm::RENEW_KEY_ERROR_1: - err = ::drm::V1_4::Status::LICENSE_REQUEST_REJECTED; - break; - case wvcdm::EMPTY_LICENSE_REQUEST_2: - case wvcdm::EMPTY_LICENSE_REQUEST_3: - case wvcdm::EMPTY_LICENSE_RESPONSE_3: - case wvcdm::EMPTY_LICENSE_RESPONSE_4: - case wvcdm::INVALID_LICENSE_REQUEST_TYPE_1: - case wvcdm::INVALID_LICENSE_REQUEST_TYPE_2: - case wvcdm::INVALID_LICENSE_TYPE_2: - case wvcdm::PARSE_REQUEST_ERROR_1: - case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_2: - case wvcdm::SIGNATURE_NOT_FOUND_2: - err = ::drm::V1_4::Status::LICENSE_RESTORE_ERROR; - break; - case wvcdm::GET_RELEASED_LICENSE_ERROR: - case wvcdm::RESTORE_OFFLINE_LICENSE_ERROR_3: - case wvcdm::USAGE_ENTRY_ALREADY_LOADED: - err = ::drm::V1_4::Status::LICENSE_STATE_ERROR; - break; - case wvcdm::DEVICE_CERTIFICATE_ERROR_2: - case wvcdm::DEVICE_CERTIFICATE_ERROR_3: - case wvcdm::DEVICE_CERTIFICATE_ERROR_4: - case wvcdm::LICENSE_PARSER_INIT_ERROR: - case wvcdm::PARSE_RESPONSE_ERROR_1: - case wvcdm::PARSE_RESPONSE_ERROR_2: - case wvcdm::PARSE_RESPONSE_ERROR_3: - case wvcdm::PARSE_RESPONSE_ERROR_4: - err = ::drm::V1_4::Status::MALFORMED_CERTIFICATE; - break; - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_2: - case wvcdm::INVALID_DECRYPT_PARAMETERS_ENG_4: - err = ::drm::V1_4::Status::MEDIA_FRAMEWORK_ERROR; - break; - case wvcdm::PRIVACY_MODE_ERROR_1: - case wvcdm::PRIVACY_MODE_ERROR_2: - case wvcdm::PRIVACY_MODE_ERROR_3: - err = ::drm::V1_4::Status::MISSING_CERTIFICATE; - break; - case wvcdm::LOAD_DEVICE_RSA_KEY_ERROR: - err = ::drm::V1_4::Status::PROVISIONING_CERTIFICATE_ERROR; - break; - case wvcdm::CERT_PROVISIONING_EMPTY_SERVICE_CERTIFICATE: - case wvcdm::PROVISIONING_4_RESPONSE_HAS_NO_CERTIFICATE: - case wvcdm::SERVICE_CERTIFICATE_PROVIDER_ID_EMPTY: - err = ::drm::V1_4::Status::PROVISIONING_CONFIGURATION_ERROR; - break; - case wvcdm::CERT_PROVISIONING_INVALID_CERT_TYPE: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_1: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_2: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_3: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_4: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_9: - case wvcdm::LOAD_PROVISIONING_ERROR: - err = ::drm::V1_4::Status::PROVISIONING_PARSE_ERROR; - break; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_10: - case wvcdm::PROVISIONING_4_RESPONSE_HAS_ERROR_STATUS: - err = ::drm::V1_4::Status::PROVISIONING_REQUEST_REJECTED; - break; - case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_1: - case wvcdm::EMPTY_PROVISIONING_CERTIFICATE_2: - err = ::drm::V1_4::Status::RETRYABLE_PROVISIONING_ERROR; - break; - case wvcdm::RELEASE_LICENSE_ERROR_2: - err = ::drm::V1_4::Status::SECURE_STOP_RELEASE_ERROR; - break; - case wvcdm::GET_LICENSE_ERROR: - case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_1: - case wvcdm::GET_OFFLINE_LICENSE_STATE_ERROR_2: - case wvcdm::GET_USAGE_INFO_ERROR_1: - case wvcdm::GET_USAGE_INFO_ERROR_2: - case wvcdm::GET_USAGE_INFO_ERROR_3: - case wvcdm::GET_USAGE_INFO_ERROR_4: - case wvcdm::LIST_LICENSE_ERROR_1: - case wvcdm::LIST_LICENSE_ERROR_2: - case wvcdm::LIST_USAGE_ERROR_1: - case wvcdm::LIST_USAGE_ERROR_2: - case wvcdm::LOAD_USAGE_INFO_FILE_ERROR: - case wvcdm::REMOVE_OFFLINE_LICENSE_ERROR_1: - case wvcdm::REMOVE_USAGE_INFO_ERROR_2: - case wvcdm::SESSION_FILE_HANDLE_INIT_ERROR: - case wvcdm::UNPROVISION_ERROR_1: - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_LICENSE_FAILED: - case wvcdm::USAGE_GET_ENTRY_RETRIEVE_USAGE_INFO_FAILED: - case wvcdm::USAGE_INFO_NOT_FOUND: - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_LICENSE_FAILED: - case wvcdm::USAGE_STORE_ENTRY_RETRIEVE_USAGE_INFO_FAILED: - err = ::drm::V1_4::Status::STORAGE_READ_FAILURE; - break; - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_7: - case wvcdm::CERT_PROVISIONING_RESPONSE_ERROR_8: - case wvcdm::DELETE_USAGE_ERROR_1: - case wvcdm::DELETE_USAGE_ERROR_2: - case wvcdm::PROVISIONING_4_FAILED_TO_INITIALIZE_DEVICE_FILES_2: - case wvcdm::PROVISIONING_4_FAILED_TO_STORE_DRM_CERTIFICATE: - case wvcdm::PROVISIONING_4_FAILED_TO_STORE_OEM_CERTIFICATE: - case wvcdm::RELEASE_KEY_REQUEST_ERROR: - case wvcdm::REMOVE_ALL_USAGE_INFO_ERROR_5: - case wvcdm::REMOVE_USAGE_INFO_ERROR_1: - case wvcdm::RENEW_KEY_ERROR_2: - case wvcdm::STORE_LICENSE_ERROR_1: - case wvcdm::STORE_USAGE_INFO_ERROR: - case wvcdm::UNPROVISION_ERROR_2: - case wvcdm::UNPROVISION_ERROR_3: - case wvcdm::USAGE_STORE_LICENSE_FAILED: - case wvcdm::USAGE_STORE_USAGE_INFO_FAILED: - err = ::drm::V1_4::Status::STORAGE_WRITE_FAILURE; - break; - default: - return static_cast(mapCdmResponseType_1_2(res)); - } - return static_cast(err); -} - -static inline bool isCdmResponseTypeSuccess(wvcdm::CdmResponseType res) { - return mapCdmResponseType(res) == Status::OK; -} - -} // namespace wvdrm - -#endif // WV_MAP_ERRORS_H_ diff --git a/libwvdrmengine/include_hidl/HidlTypes.h b/libwvdrmengine/include_hidl/HidlTypes.h deleted file mode 100644 index 62ce8c5d..00000000 --- a/libwvdrmengine/include_hidl/HidlTypes.h +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef HIDL_TYPES_H_ -#define HIDL_TYPES_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using ::android::hardware::configureRpcThreadpool; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_handle; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::joinRpcThreadpool; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::sp; - -namespace drm = ::android::hardware::drm; -using drm::V1_0::BufferType; -using drm::V1_0::DestinationBuffer; -using drm::V1_0::EventType; -using drm::V1_0::IDrmPluginListener; -using drm::V1_0::KeyRequestType; -using drm::V1_0::KeyStatus; -using drm::V1_0::KeyStatusType; -using drm::V1_0::KeyType; -using drm::V1_0::KeyValue; -using drm::V1_0::Mode; -using drm::V1_0::Pattern; -using drm::V1_0::SecureStop; -using drm::V1_0::SecureStopId; -using drm::V1_0::SharedBuffer; -using drm::V1_0::Status; -using drm::V1_0::SubSample; -using drm::V1_1::DrmMetricGroup; -using drm::V1_1::HdcpLevel; -using drm::V1_1::SecureStopRelease; -using drm::V1_1::SecurityLevel; -using drm::V1_2::ICryptoPlugin; -using drm::V1_2::IDrmPlugin; -using drm::V1_2::KeySetId; -using drm::V1_2::OfflineLicenseState; -using drm::V1_3::ICryptoFactory; -using drm::V1_3::IDrmFactory; - -typedef drm::V1_1::KeyRequestType KeyRequestType_V1_1; -typedef drm::V1_2::KeyStatus KeyStatus_V1_2; -typedef drm::V1_2::KeyStatusType KeyStatusType_V1_2; -typedef drm::V1_2::IDrmPluginListener IDrmPluginListener_V1_2; -typedef drm::V1_2::Status Status_V1_2; -typedef drm::V1_2::HdcpLevel HdcpLevel_V1_2; - -#endif diff --git a/libwvdrmengine/include_hidl/HidlWVCreatePluginFactories.h b/libwvdrmengine/include_hidl/HidlWVCreatePluginFactories.h deleted file mode 100644 index b358d2b4..00000000 --- a/libwvdrmengine/include_hidl/HidlWVCreatePluginFactories.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_CREATE_PLUGIN_FACTORIES_H_ -#define WV_CREATE_PLUGIN_FACTORIES_H_ - -#include "HidlTypes.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -extern "C" { - ::drm::V1_4::IDrmFactory* createDrmFactory(); - ::drm::V1_4::ICryptoFactory* createCryptoFactory(); -} - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm -#endif // WV_CREATE_PLUGIN_FACTORIES_H_ diff --git a/libwvdrmengine/include_hidl/HidlWVDrmFactory.h b/libwvdrmengine/include_hidl/HidlWVDrmFactory.h deleted file mode 100644 index 88e542d8..00000000 --- a/libwvdrmengine/include_hidl/HidlWVDrmFactory.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_DRM_FACTORY_H_ -#define WV_DRM_FACTORY_H_ - -#include "HidlTypes.h" -#include "HidlWVTypes.h" -#include "WVGenericCryptoInterface.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using ::android::hardware::hidl_handle; -using ::android::hardware::hidl_vec; - -struct WVDrmFactory : public ::drm::V1_4::IDrmFactory { - WVDrmFactory() {} - virtual ~WVDrmFactory() {} - - Return isCryptoSchemeSupported( - const hidl_array& uuid) override; - - Return isCryptoSchemeSupported_1_2(const hidl_array& uuid, - const hidl_string& mimeType, - SecurityLevel level) override; - - Return isContentTypeSupported(const hidl_string& mimeType) override; - - Return createPlugin(const hidl_array& uuid, - const hidl_string& appPackageName, - createPlugin_cb _hidl_cb) override; - - Return getSupportedCryptoSchemes( - getSupportedCryptoSchemes_cb _hidl_cb) override; - - Return debug(const hidl_handle& fd, const hidl_vec& args); - - private: - WVDRM_DISALLOW_COPY_AND_ASSIGN(WVDrmFactory); - - static WVGenericCryptoInterface sOemCryptoInterface; - - static bool areSpoidsEnabled(); - 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; -}; - -extern "C" IDrmFactory* HIDL_FETCH_IDrmFactory(const char* name); - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm - -#endif // WV_DRM_FACTORY_H_ diff --git a/libwvdrmengine/include_hidl/HidlWVTypes.h b/libwvdrmengine/include_hidl/HidlWVTypes.h deleted file mode 100644 index c3cb5167..00000000 --- a/libwvdrmengine/include_hidl/HidlWVTypes.h +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_TYPES_H_ -#define WV_TYPES_H_ - -namespace wvdrm { - -#define WVDRM_DISALLOW_COPY_AND_ASSIGN(TypeName) \ - TypeName(const TypeName&) = delete; \ - void operator=(const TypeName&) = delete; - -#define WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(TypeName) \ - TypeName() = delete; \ - TypeName(const TypeName&) = delete; \ - void operator=(const TypeName&) = delete; - -} // namespace wvdrm -#endif // WV_TYPES_H_ diff --git a/libwvdrmengine/include_hidl/TypeConvert.h b/libwvdrmengine/include_hidl/TypeConvert.h deleted file mode 100644 index 7d3fd659..00000000 --- a/libwvdrmengine/include_hidl/TypeConvert.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2017 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. - */ - -#ifndef WVDRM_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT -#define WVDRM_ANDROID_HARDWARE_DRM_V1_1_TYPECONVERT - -#include - -#include "HidlTypes.h" -#include "log.h" -#include "media/stagefright/MediaErrors.h" -#include "utils/Errors.h" - -namespace android { -namespace hardware { -namespace drm { -namespace V1_2 { -namespace widevine { - -inline ::drm::V1_4::LogPriority toHidlPriority(wvutil::LogPriority p) { - switch (p) { - case wvutil::LogPriority::CDM_LOG_ERROR: - return ::drm::V1_4::LogPriority::ERROR; - case wvutil::LogPriority::CDM_LOG_WARN: - return ::drm::V1_4::LogPriority::WARN; - case wvutil::LogPriority::CDM_LOG_INFO: - return ::drm::V1_4::LogPriority::INFO; - case wvutil::LogPriority::CDM_LOG_DEBUG: - return ::drm::V1_4::LogPriority::DEBUG; - case wvutil::LogPriority::CDM_LOG_VERBOSE: - return ::drm::V1_4::LogPriority::VERBOSE; - default: - return ::drm::V1_4::LogPriority::UNKNOWN; - } - return ::drm::V1_4::LogPriority::UNKNOWN; -} - -template -hidl_vec toHidlVec(const std::vector &vec); - -template<> -inline hidl_vec<::drm::V1_4::LogMessage> toHidlVec(const std::vector &vec) { - uint32_t uid = wvutil::GetIpcCallingUid(); - std::vector<::drm::V1_4::LogMessage> vec2; - for (auto msg : vec) { - if (uid == msg.uid_) { - vec2.push_back({ - msg.time_ms_, - toHidlPriority(msg.priority_), - msg.message_, - }); - } - } - - return hidl_vec<::drm::V1_4::LogMessage>(vec2); -} - -template -const hidl_vec toHidlVec(const std::vector &vec) { - hidl_vec hVec; - hVec.setToExternal(const_cast(vec.data()), vec.size()); - return hVec; -} - -template -hidl_vec toHidlVec(std::vector &vec) { - hidl_vec hVec; - hVec.setToExternal(vec.data(), vec.size()); - return hVec; -} - -template -const std::vector toVector(const hidl_vec &hVec) { - std::vector vec; - vec.assign(hVec.data(), hVec.data() + hVec.size()); - return *const_cast *>(&vec); -} - -template -std::vector toVector(hidl_vec &hVec) { - std::vector vec; - vec.assign(hVec.data(), hVec.data() + hVec.size()); - return vec; -} - -template -const std::vector toVector(const hidl_array &hArray) { - std::vector vec; - vec.assign(hArray.data(), hArray.data() + hArray.size()); - return vec; -} - -template -std::vector toVector(hidl_array &hArray) { - std::vector vec; - vec.assign(hArray.data(), hArray.data() + hArray.size()); - return vec; -} - -} // namespace widevine -} // namespace V1_2 -} // namespace drm -} // namespace hardware -} // namespace android - -#endif // WVDRM_ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT diff --git a/libwvdrmengine/include_hidl/WVCryptoFactory.h b/libwvdrmengine/include_hidl/WVCryptoFactory.h deleted file mode 100644 index 7a9f925c..00000000 --- a/libwvdrmengine/include_hidl/WVCryptoFactory.h +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_CRYPTO_FACTORY_H_ -#define WV_CRYPTO_FACTORY_H_ - -#include "HidlTypes.h" -#include "HidlWVTypes.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -struct WVCryptoFactory : public ::drm::V1_4::ICryptoFactory { - public: - WVCryptoFactory() {} - virtual ~WVCryptoFactory() {} - - Return isCryptoSchemeSupported(const hidl_array& uuid) - override; - - Return createPlugin( - const hidl_array& uuid, - const hidl_vec& initData, - createPlugin_cb _hidl_cb) override; - - private: - WVDRM_DISALLOW_COPY_AND_ASSIGN(WVCryptoFactory); -}; - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm - -#endif // WV_CRYPTO_FACTORY_H_ diff --git a/libwvdrmengine/manifest_android.hardware.drm@1.2-service.widevine.xml b/libwvdrmengine/manifest_android.hardware.drm@1.2-service.widevine.xml deleted file mode 100644 index 85cd44cf..00000000 --- a/libwvdrmengine/manifest_android.hardware.drm@1.2-service.widevine.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - android.hardware.drm - hwbinder - @1.2::ICryptoFactory/widevine - @1.2::IDrmFactory/widevine - - diff --git a/libwvdrmengine/manifest_android.hardware.drm@1.3-service.widevine.xml b/libwvdrmengine/manifest_android.hardware.drm@1.3-service.widevine.xml deleted file mode 100644 index f6f2d885..00000000 --- a/libwvdrmengine/manifest_android.hardware.drm@1.3-service.widevine.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - android.hardware.drm - hwbinder - @1.3::ICryptoFactory/widevine - @1.3::IDrmFactory/widevine - - diff --git a/libwvdrmengine/manifest_android.hardware.drm@1.4-service.widevine.xml b/libwvdrmengine/manifest_android.hardware.drm@1.4-service.widevine.xml deleted file mode 100644 index 78618dca..00000000 --- a/libwvdrmengine/manifest_android.hardware.drm@1.4-service.widevine.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - android.hardware.drm - hwbinder - @1.4::ICryptoFactory/widevine - @1.4::IDrmFactory/widevine - - diff --git a/libwvdrmengine/mediacrypto/Android.bp b/libwvdrmengine/mediacrypto/Android.bp index 3c288463..84540abd 100644 --- a/libwvdrmengine/mediacrypto/Android.bp +++ b/libwvdrmengine/mediacrypto/Android.bp @@ -22,50 +22,6 @@ package { default_applicable_licenses: ["vendor_widevine_license"], } -// Builds libwvdrmcryptoplugin_hidl -// -cc_library_static { - name: "libwvdrmcryptoplugin_hidl", - - srcs: ["src_hidl/WVCryptoPlugin.cpp"], - - include_dirs: [ - "frameworks/av/include", - "frameworks/native/include", - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/cdm/metrics/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/include", - "vendor/widevine/libwvdrmengine/include_hidl", - "vendor/widevine/libwvdrmengine/mediacrypto/include_hidl", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - header_libs: [ - "libstagefright_headers", - "libutils_headers", - ], - - static_libs: ["libcdm_protos"], - - shared_libs: [ - "android.hardware.drm@1.0", - "android.hardware.drm@1.1", - "android.hardware.drm@1.2", - "android.hardware.drm@1.3", - "android.hardware.drm@1.4", - "android.hidl.memory@1.0", - "libcrypto", - "libhidlmemory", - "liblog", - ], - - cflags: ["-Wthread-safety"], - - proprietary: true, -} - // Builds libwvdrmcryptoplugin_aidl // cc_library_static { diff --git a/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h b/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h deleted file mode 100644 index 5428d2e3..00000000 --- a/libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h +++ /dev/null @@ -1,97 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_CRYPTO_PLUGIN_H_ -#define WV_CRYPTO_PLUGIN_H_ - -#include -#include - -#include - -#include "HidlTypes.h" -#include "HidlWVTypes.h" -#include "log.h" -#include "wv_content_decryption_module.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using ::android::hidl::memory::V1_0::IMemory; - -struct WVCryptoPlugin : public ::drm::V1_4::ICryptoPlugin { - WVCryptoPlugin(const void* data, size_t size, - const sp& cdm); - virtual ~WVCryptoPlugin(); - - Return requiresSecureDecoderComponent(const hidl_string& mime) - override; - - Return notifyResolution(uint32_t width, uint32_t height) override; - - Return setMediaDrmSession(const hidl_vec& sessionId) - override; - - Return setSharedBufferBase(const hidl_memory& base, - uint32_t bufferId) override; - - Return decrypt( - bool secure, - const hidl_array& keyId, - const hidl_array& iv, - Mode mode, - const Pattern& pattern, - const hidl_vec& subSamples, - const SharedBuffer& source, - uint64_t offset, - const DestinationBuffer& destination, - decrypt_cb _hidl_cb) override; - - Return decrypt_1_2( - bool secure, - const hidl_array& keyId, - const hidl_array& iv, - Mode mode, - const Pattern& pattern, - const hidl_vec& subSamples, - const SharedBuffer& source, - uint64_t offset, - const DestinationBuffer& destination, - decrypt_1_2_cb _hidl_cb) override NO_THREAD_SAFETY_ANALYSIS; // use unique_lock - - Return getLogMessages( - getLogMessages_cb _hidl_cb) override; - - private: - WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WVCryptoPlugin); - - // List this field first so it is destructed last; ensure logging uid - // is cleared right before plugin is destructed. - wvutil::LoggingUidSetter mLoggingUidSetter; - - wvcdm::CdmSessionId mSessionId; - std::map > mSharedBufferMap GUARDED_BY(mSharedBufferLock); - - sp const mCDM; - uint32_t mUserId; - - Status_V1_2 attemptDecrypt( - const wvcdm::CdmDecryptionParametersV16& params, - bool haveEncryptedSubsamples, std::string* errorDetailMsg); - - std::mutex mSharedBufferLock; -}; - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm - -#endif // WV_CRYPTO_PLUGIN_H_ diff --git a/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp b/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp deleted file mode 100644 index 31e2b532..00000000 --- a/libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp +++ /dev/null @@ -1,372 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVCryptoPlugin.h" - -#include -#include -#include - -#include "HidlMapErrors-inl.h" -#include "HidlTypes.h" -#include "log.h" -#include "OEMCryptoCENC.h" -#include "openssl/sha.h" -#include "TypeConvert.h" -#include "wv_cdm_constants.h" -#include "WVErrors.h" - -namespace { - -inline Status toStatus_1_0(Status_V1_2 status) { - switch (status) { - case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY: - case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE: - case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE: - return Status::ERROR_DRM_UNKNOWN; - default: - return static_cast(status); - } -} - -} // namespace - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using android::hardware::drm::V1_2::widevine::toHidlVec; -using android::hardware::drm::V1_2::widevine::toVector; -using wvcdm::CdmDecryptionParametersV16; -using wvcdm::CdmDecryptionSample; -using wvcdm::CdmDecryptionSubsample; -using wvcdm::CdmQueryMap; -using wvcdm::CdmResponseType; -using wvcdm::CdmSessionId; -using wvcdm::KeyId; -using wvcdm::WvContentDecryptionModule; - -WVCryptoPlugin::WVCryptoPlugin(const void* data, size_t size, - const sp& cdm) - : mCDM(cdm), - mUserId(wvutil::UNKNOWN_UID) { - if (data != NULL) { - mSessionId.assign(static_cast(data), size); - } - if (!mCDM->IsOpenSession(mSessionId)) { - mSessionId.clear(); - } else { - mCDM->GetSessionUserId(mSessionId, &mUserId); - } -} - -WVCryptoPlugin::~WVCryptoPlugin() { - if (wvutil::UNKNOWN_UID != mUserId) { - wvutil::SetLoggingUid(mUserId); - } -} - -Return WVCryptoPlugin::requiresSecureDecoderComponent( - const hidl_string& mime) { - if (!strncasecmp(mime.c_str(), "video/", 6)) { - // Type is video, so query CDM to see if we require a secure decoder. - CdmQueryMap status; - - CdmResponseType res = mCDM->QuerySessionStatus(mSessionId, &status); - - if (!isCdmResponseTypeSuccess(res)) { - ALOGE("Error querying CDM status: %u", res); - return false; - } - - return status[wvcdm::QUERY_KEY_SECURITY_LEVEL] == - wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1; - } else { - // Type is not video, so never require a secure decoder. - return false; - } -} - -Return WVCryptoPlugin::notifyResolution( - uint32_t width, uint32_t height) { - mCDM->NotifyResolution(mSessionId, width, height); - return Void(); -} - -Return WVCryptoPlugin::setMediaDrmSession( - const hidl_vec& sessionId) { - if (sessionId.size() == 0) { - return Status::BAD_VALUE; - } - const std::vector sId = toVector(sessionId); - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCDM->IsOpenSession(cdmSessionId)) { - return Status::ERROR_DRM_SESSION_NOT_OPENED; - } else { - mSessionId = cdmSessionId; - return Status::OK; - } -} - -Return WVCryptoPlugin::setSharedBufferBase( - const hidl_memory& base, uint32_t bufferId) { - sp hidlMemory = mapMemory(base); - - std::lock_guard shared_buffer_lock(mSharedBufferLock); - - // allow mapMemory to return nullptr - mSharedBufferMap[bufferId] = hidlMemory; - return Void(); -} - -Return WVCryptoPlugin::decrypt( - bool secure, - const hidl_array& keyId, - const hidl_array& iv, - Mode mode, - const Pattern& pattern, - const hidl_vec& subSamples, - const SharedBuffer& source, - uint64_t offset, - const DestinationBuffer& destination, - decrypt_cb _hidl_cb) { - - Status status = Status::ERROR_DRM_UNKNOWN; - hidl_string detailedError; - uint32_t bytesWritten = 0; - - Return hResult = decrypt_1_2( - secure, keyId, iv, mode, pattern, subSamples, source, offset, destination, - [&](Status_V1_2 hStatus, uint32_t hBytesWritten, hidl_string hDetailedError) { - status = toStatus_1_0(hStatus); - if (status == Status::OK) { - bytesWritten = hBytesWritten; - detailedError = hDetailedError; - } - } - ); - - status = hResult.isOk() ? status : Status::ERROR_DRM_CANNOT_HANDLE; - _hidl_cb(status, bytesWritten, detailedError); - return Void(); -} - -Return WVCryptoPlugin::decrypt_1_2( - bool secure, - const hidl_array& keyId, - const hidl_array& iv, - Mode mode, - const Pattern& pattern, - const hidl_vec& subSamples, - const SharedBuffer& source, - uint64_t offset, - const DestinationBuffer& destination, - decrypt_1_2_cb _hidl_cb) { - std::unique_lock lock(mSharedBufferLock); - if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) { - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, - "source decrypt buffer base not set"); - return Void(); - } - - if (destination.type == BufferType::SHARED_MEMORY) { - const SharedBuffer& dest = destination.nonsecureMemory; - if (mSharedBufferMap.find(dest.bufferId) == mSharedBufferMap.end()) { - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, - "destination decrypt buffer base not set"); - return Void(); - } - } - - if (mode != Mode::UNENCRYPTED && - mode != Mode::AES_CTR && - mode != Mode::AES_CBC) { - _hidl_cb(Status_V1_2::BAD_VALUE, 0, - "The requested encryption mode is not supported by Widevine CDM."); - return Void(); - } else if (mode == Mode::AES_CTR && - (pattern.encryptBlocks != 0 || pattern.skipBlocks != 0)) { - _hidl_cb(Status_V1_2::BAD_VALUE, 0, - "The 'cens' schema is not supported by Widevine CDM."); - return Void(); - } - - // Convert parameters to the form the CDM wishes to consume them in. - const KeyId cryptoKey( - reinterpret_cast(keyId.data()), wvcdm::KEY_ID_SIZE); - std::vector ivVector(iv.data(), iv.data() + wvcdm::KEY_IV_SIZE); - - std::string errorDetailMsg; - sp sourceBase = mSharedBufferMap[source.bufferId]; - if (sourceBase == nullptr) { - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "source is a nullptr"); - return Void(); - } - - size_t totalSrcSize = 0; - if (__builtin_add_overflow(source.offset, offset, &totalSrcSize) || - __builtin_add_overflow(totalSrcSize, source.size, &totalSrcSize) || - totalSrcSize > sourceBase->getSize()) { - android_errorWriteLog(0x534e4554, "176496160"); - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size"); - return Void(); - } - - uint8_t *base = static_cast - (static_cast(sourceBase->getPointer())); - uint8_t* srcPtr = static_cast(base + source.offset + offset); - void* destPtr = NULL; - if (destination.type == BufferType::SHARED_MEMORY) { - const SharedBuffer& destBuffer = destination.nonsecureMemory; - sp destBase = mSharedBufferMap[destBuffer.bufferId]; - if (destBase == nullptr) { - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, "destination is a nullptr"); - return Void(); - } - - size_t totalDstSize = 0; - if (__builtin_add_overflow(destBuffer.offset, destBuffer.size, &totalDstSize) || - totalDstSize > destBase->getSize()) { - android_errorWriteLog(0x534e4554, "176444622"); - _hidl_cb(Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE, 0, "invalid buffer size"); - return Void(); - } - destPtr = static_cast(base + destination.nonsecureMemory.offset); - } else if (destination.type == BufferType::NATIVE_HANDLE) { - native_handle_t *handle = const_cast( - destination.secureMemory.getNativeHandle()); - destPtr = static_cast(handle); - } - - // release mSharedBufferLock - lock.unlock(); - - // Set up the decrypt params - CdmDecryptionParametersV16 params; - params.key_id = cryptoKey; - params.is_secure = secure; - if (mode == Mode::AES_CTR) { - params.cipher_mode = wvcdm::kCipherModeCtr; - } else if (mode == Mode::AES_CBC) { - params.cipher_mode = wvcdm::kCipherModeCbc; - } - params.pattern.encrypt_blocks = pattern.encryptBlocks; - params.pattern.skip_blocks = pattern.skipBlocks; - - // Set up the sample - // Android's API only supports one at a time - params.samples.emplace_back(); - CdmDecryptionSample& sample = params.samples.back(); - sample.encrypt_buffer = srcPtr; - sample.decrypt_buffer = destPtr; - sample.decrypt_buffer_offset = 0; - sample.iv = ivVector; - - // Set up the subsamples - // We abuse std::transform() here to also do some side-effects: Tallying the - // total size of the sample and checking if any of the data is protected. - size_t totalSize = 0; - bool hasProtectedData = false; - sample.subsamples.reserve(subSamples.size()); - std::transform(subSamples.data(), subSamples.data() + subSamples.size(), - std::back_inserter(sample.subsamples), - [&](const SubSample& subSample) -> CdmDecryptionSubsample { - totalSize += - subSample.numBytesOfClearData + subSample.numBytesOfEncryptedData; - hasProtectedData |= subSample.numBytesOfEncryptedData > 0; - return CdmDecryptionSubsample(subSample.numBytesOfClearData, - subSample.numBytesOfEncryptedData); - }); - - sample.encrypt_buffer_length = totalSize; - sample.decrypt_buffer_size = totalSize; - - if (mode == Mode::UNENCRYPTED && hasProtectedData) { - _hidl_cb(Status_V1_2::ERROR_DRM_CANNOT_HANDLE, 0, - "Protected ranges found in allegedly clear data."); - return Void(); - } - - // Decrypt - Status_V1_2 res = attemptDecrypt(params, hasProtectedData, &errorDetailMsg); - if (res != Status_V1_2::OK) { - _hidl_cb(res, 0, errorDetailMsg.c_str()); - return Void(); - } - - _hidl_cb(Status_V1_2::OK, totalSize, errorDetailMsg.c_str()); - return Void(); -} - -Status_V1_2 WVCryptoPlugin::attemptDecrypt( - const CdmDecryptionParametersV16& params, bool hasProtectedData, - std::string* errorDetailMsg) { - CdmResponseType res = mCDM->DecryptV16(mSessionId, hasProtectedData, - params); - - if (isCdmResponseTypeSuccess(res)) { - return Status_V1_2::OK; - } else { - ALOGE("Decrypt error in session %s during a sample %s protected data: %d", - mSessionId.c_str(), - hasProtectedData ? "with" : "without", - res); - switch (res) { - case wvcdm::INSUFFICIENT_CRYPTO_RESOURCES: - errorDetailMsg->assign( - "Error decrypting data: insufficient crypto resources"); - break; - case wvcdm::NEED_KEY: - case wvcdm::KEY_NOT_FOUND_IN_SESSION: - errorDetailMsg->assign( - "Error decrypting data: requested key has not been loaded"); - break; - case wvcdm::DECRYPT_NOT_READY: - errorDetailMsg->assign( - "Error decrypting data: license validity period is in the future"); - break; - case wvcdm::SESSION_NOT_FOUND_FOR_DECRYPT: - errorDetailMsg->assign( - "Error decrypting data: session not found, possibly reclaimed"); - break; - case wvcdm::DECRYPT_ERROR: - errorDetailMsg->assign( - "Error decrypting data: unspecified error"); - break; - case wvcdm::INSUFFICIENT_OUTPUT_PROTECTION: - case wvcdm::ANALOG_OUTPUT_ERROR: - errorDetailMsg->assign( - "Error decrypting data: insufficient output protection"); - break; - case wvcdm::KEY_PROHIBITED_FOR_SECURITY_LEVEL: - errorDetailMsg->assign( - "Error decrypting data: key prohibited for security level"); - break; - default: - break; - } - - return mapCdmResponseType(res); - } -} - -Return WVCryptoPlugin::getLogMessages(getLogMessages_cb _hidl_cb) { - const std::vector &logs(wvutil::g_logbuf.getLogs()); - _hidl_cb(::drm::V1_4::Status::OK, toHidlVec<::drm::V1_4::LogMessage>(logs)); - return Void(); -} - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm diff --git a/libwvdrmengine/mediacrypto/test/Android.mk b/libwvdrmengine/mediacrypto/test/Android.mk index fab60ef8..614055b0 100644 --- a/libwvdrmengine/mediacrypto/test/Android.mk +++ b/libwvdrmengine/mediacrypto/test/Android.mk @@ -4,56 +4,7 @@ LOCAL_PATH := $(call my-dir) # include $(CLEAR_VARS) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) - -LOCAL_SRC_FILES := \ - hidl/WVCryptoPlugin_test.cpp \ - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/native/include \ - vendor/widevine/libwvdrmengine/cdm/core/include \ - vendor/widevine/libwvdrmengine/cdm/include \ - vendor/widevine/libwvdrmengine/cdm/metrics/include \ - vendor/widevine/libwvdrmengine/cdm/util/include \ - vendor/widevine/libwvdrmengine/include_hidl \ - vendor/widevine/libwvdrmengine/mediacrypto/include_hidl \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - -LOCAL_STATIC_LIBRARIES := \ - libcdm \ - libcdm_protos \ - libcdm_utils_hidl \ - libjsmn \ - libgmock \ - libgmock_main \ - libgtest \ - libwvlevel3 \ - libwvdrmcryptoplugin_hidl \ - libwv_odk \ - -LOCAL_SHARED_LIBRARIES := \ - android.hardware.drm@1.0 \ - android.hardware.drm@1.1 \ - android.hardware.drm@1.2 \ - android.hardware.drm@1.3 \ - android.hardware.drm@1.4 \ - android.hidl.memory@1.0 \ - libbase \ - libbinder \ - libcrypto \ - libcutils \ - libdl \ - libhidlbase \ - libhidlmemory \ - liblog \ - libprotobuf-cpp-lite \ - libutils \ - # build unit tests for Aidl -else - LOCAL_SRC_FILES := \ WVCryptoPlugin_hal_test.cpp \ @@ -92,9 +43,6 @@ LOCAL_SHARED_LIBRARIES := \ libprotobuf-cpp-lite \ libutils \ -# endif $(WV_UNITTESTS_BUILD_TARGET) -endif - LOCAL_HEADER_LIBRARIES := \ libstagefright_headers \ diff --git a/libwvdrmengine/mediacrypto/test/hidl/WVCryptoPlugin_test.cpp b/libwvdrmengine/mediacrypto/test/hidl/WVCryptoPlugin_test.cpp deleted file mode 100644 index 15a048f4..00000000 --- a/libwvdrmengine/mediacrypto/test/hidl/WVCryptoPlugin_test.cpp +++ /dev/null @@ -1,643 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCryptoPluginTest" -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "wv_cdm_constants.h" -#include "wv_cdm_types.h" -#include "wv_content_decryption_module.h" -#include "HidlTypes.h" -#include "OEMCryptoCENC.h" -#include "TypeConvert.h" -#include "WVCryptoPlugin.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using ::android::MemoryDealer; - -using ::testing::_; -using ::testing::DefaultValue; -using ::testing::DoAll; -using ::testing::ElementsAreArray; -using ::testing::Field; -using ::testing::InSequence; -using ::testing::Matcher; -using ::testing::SetArgPointee; -using ::testing::StrictMock; -using ::testing::Test; -using ::testing::Truly; -using ::testing::Value; -using ::testing::internal::ElementsAreArrayMatcher; - -using wvcdm::kCipherModeCtr; -using wvcdm::kCipherModeCbc; -using wvcdm::CdmCipherMode; -using wvcdm::CdmDecryptionParametersV16; -using wvcdm::CdmDecryptionSample; -using wvcdm::CdmDecryptionSubsample; -using wvcdm::CdmQueryMap; -using wvcdm::CdmResponseType; -using wvcdm::CdmSessionId; -using wvcdm::KeyId; -using wvcdm::KEY_ID_SIZE; -using wvcdm::KEY_IV_SIZE; -using wvcdm::QUERY_KEY_SECURITY_LEVEL; -using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1; -using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3; - -class MockCDM : public wvcdm::WvContentDecryptionModule { - public: - MOCK_METHOD(bool, IsOpenSession, (const CdmSessionId&), (override)); - - MOCK_METHOD(CdmResponseType, DecryptV16, (const CdmSessionId&, bool, - const CdmDecryptionParametersV16&), (override)); - - MOCK_METHOD(CdmResponseType, QuerySessionStatus, (const CdmSessionId&, - CdmQueryMap*), (override)); -}; - -class WVCryptoPluginTest : public Test { - protected: - static const uint32_t kSessionIdSize = 16; - uint8_t* pDest = nullptr; - uint8_t* pSrc = nullptr; - uint8_t sessionId[kSessionIdSize]; - uint32_t nextBufferId = 0; - std::map heapBases; - - virtual void SetUp() { - FILE* fp = fopen("/dev/urandom", "r"); - fread(sessionId, sizeof(uint8_t), kSessionIdSize, fp); - fclose(fp); - - // Set default CdmResponseType value for gMock - DefaultValue::Set(wvcdm::NO_ERROR); - heapBases.clear(); - } - - void setHeapBase(WVCryptoPlugin& plugin, - const sp& heap) { - ASSERT_NE(heap, nullptr); - - void* heapBase = heap->getBase(); - ASSERT_NE(heapBase, nullptr); - - native_handle_t* nativeHandle = native_handle_create(1, 0); - ASSERT_NE(nativeHandle, nullptr); - - nativeHandle->data[0] = heap->getHeapID(); - - auto hidlHandle = hidl_handle(nativeHandle); - auto hidlMemory = hidl_memory("ashmem", hidlHandle, heap->getSize()); - heapBases.insert( - std::pair(heapBase, nextBufferId)); - Return hResult = - plugin.setSharedBufferBase(hidlMemory, nextBufferId++); - - ALOGE_IF(!hResult.isOk(), "setHeapBase failed setSharedBufferBase"); - } - - void toSharedBuffer(WVCryptoPlugin& plugin, - const sp& memory, - SharedBuffer* buffer) { - ssize_t offset; - size_t size; - - ASSERT_NE(memory, nullptr); - ASSERT_NE(buffer, nullptr); - - sp heap = memory->getMemory(&offset, &size); - ASSERT_NE(heap, nullptr); - - setHeapBase(plugin, heap); - buffer->bufferId = heapBases[heap->getBase()]; - buffer->offset = offset >= 0 ? offset : 0; - buffer->size = size; - } -}; - -TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) { - android::sp> cdm = new StrictMock(); - - CdmQueryMap l1Map; - l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; - CdmQueryMap l3Map; - l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(testing::Return(true)); - - // Specify the expected calls to QuerySessionStatus - EXPECT_CALL(*cdm, QuerySessionStatus(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(l1Map), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<1>(l3Map), - testing::Return(wvcdm::NO_ERROR))); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - - EXPECT_TRUE(plugin.requiresSecureDecoderComponent("video/mp4")) << - "WVCryptoPlugin incorrectly allows an insecure video decoder on L1"; - EXPECT_FALSE(plugin.requiresSecureDecoderComponent("video/mp4")) << - "WVCryptoPlugin incorrectly expects a secure video decoder on L3"; - EXPECT_FALSE(plugin.requiresSecureDecoderComponent("audio/aac")) << - "WVCryptoPlugin incorrectly expects a secure audio decoder"; -} - -// TODO(b/28295739): -// Add New MediaCrypto Unit Tests for CBC & Pattern Mode in cdmPatternDesc. - -// Predicate that validates that the fields of a passed-in -// CdmDecryptionParametersV16 match the values it was given at construction -// time. -// -// This could be done with a huge pile of gMock matchers, but it is ugly and -// unmaintainable, particularly once you get into validating the subsamples. The -// logic here is complex enough to warrant a custom matcher for this one test. -class CDPMatcher { - public: - // TODO(b/35259313): Uncomment the removed parameters once the matcher can - // convert them from HIDL accesses to physical addresses. - CDPMatcher(const uint8_t* keyId, bool isSecure, Mode cipherMode, - const Pattern& pattern, - const uint8_t* /* input */, size_t inputLength, - const uint8_t* /* output */, size_t outputLength, const uint8_t* iv, - const SubSample* subsamples, size_t subsamplesLength) - : mKeyId(keyId, keyId + KEY_ID_SIZE), mIsSecure(isSecure), - mCipherMode(cipherMode), mPattern(pattern), /* mInput(input), */ - mInputLength(inputLength), /* mOutput(output), */ - mOutputLength(outputLength), mIv(iv, iv + KEY_IV_SIZE), - mSubsamples(subsamples, subsamples + subsamplesLength) {} - - bool operator()(const CdmDecryptionParametersV16& params) const { - if (mCipherMode == Mode::AES_CTR && - params.cipher_mode != kCipherModeCtr) { - return false; - } else if (mCipherMode == Mode::AES_CBC && - params.cipher_mode != kCipherModeCbc) { - return false; - } - - if (params.key_id != mKeyId || - params.is_secure != mIsSecure || - params.pattern.encrypt_blocks != mPattern.encryptBlocks || - params.pattern.skip_blocks != mPattern.skipBlocks || - params.samples.size() != 1) { - return false; - } - - const CdmDecryptionSample& sample = params.samples[0]; - if (// TODO(b/35259313): Convert from a HIDL access to a physical address. - // sample.encrypt_buffer != mInput || - sample.encrypt_buffer_length != mInputLength || - // TODO(b/35259313): Convert from a HIDL access to a physical address. - // sample.decrypt_buffer != mOutput || - sample.decrypt_buffer_size != mOutputLength || - sample.decrypt_buffer_offset != 0 || - sample.iv != mIv || - sample.subsamples.size() != mSubsamples.size()) { - return false; - } - - for (size_t i = 0; i < mSubsamples.size(); ++i) { - const SubSample& androidSubsample = mSubsamples[i]; - const CdmDecryptionSubsample& cdmSubsample = sample.subsamples[i]; - - if (cdmSubsample.clear_bytes != androidSubsample.numBytesOfClearData || - cdmSubsample.protected_bytes != androidSubsample.numBytesOfEncryptedData) { - return false; - } - } - - return true; - } - - private: - const KeyId mKeyId; - const bool mIsSecure; - const Mode mCipherMode; - const Pattern mPattern; - // TODO(b/35259313): Uncomment this field once the matcher can convert this - // from a HIDL access to a physical address. - // const uint8_t* const mInput; - const size_t mInputLength; - // TODO(b/35259313): Uncomment this field once the matcher can convert this - // from a HIDL access to a physical address. - // const uint8_t* const mOutput; - const size_t mOutputLength; - const std::vector mIv; - const std::vector mSubsamples; -}; - -TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) { - android::sp> cdm = new StrictMock(); - - constexpr size_t kSubSampleCount = 6; - SubSample subSamples[kSubSampleCount]; - memset(subSamples, 0, sizeof(subSamples)); - subSamples[0].numBytesOfEncryptedData = 16; - subSamples[1].numBytesOfClearData = 16; - subSamples[1].numBytesOfEncryptedData = 16; - subSamples[2].numBytesOfEncryptedData = 8; - subSamples[3].numBytesOfClearData = 29; - subSamples[3].numBytesOfEncryptedData = 24; - subSamples[4].numBytesOfEncryptedData = 60; - subSamples[5].numBytesOfEncryptedData = 16; - - std::vector subSamplesVector( - subSamples, subSamples + sizeof(subSamples) / sizeof(subSamples[0])); - auto hSubSamples = hidl_vec(subSamplesVector); - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - - static const size_t kDataSize = 185; - uint8_t inputData[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(inputData, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - sp memDealer = new MemoryDealer( - kDataSize * 2, "WVCryptoPlugin_test"); - sp source = memDealer->allocate(kDataSize); - ASSERT_NE(source, nullptr); - pSrc = static_cast( - static_cast(source->unsecurePointer())); - ASSERT_NE(pSrc, nullptr); - memcpy(pSrc, inputData, source->size()); - - sp destination = memDealer->allocate(kDataSize); - ASSERT_NE(destination, nullptr); - pDest = static_cast( - static_cast(destination->unsecurePointer())); - ASSERT_NE(pDest, nullptr); - - Pattern noPattern = { 0, 0 }; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(testing::Return(true)); - - // Specify the expected calls to Decrypt - CDPMatcher paramsMatcher(keyId, false, Mode::AES_CTR, noPattern, pSrc, - kDataSize, pDest, kDataSize, iv, subSamples, - kSubSampleCount); - - EXPECT_CALL(*cdm, DecryptV16(ElementsAreArray(sessionId, kSessionIdSize), - true, - Truly(paramsMatcher))) - .Times(1); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - - uint32_t bytesWritten = 0; - std::string errorDetailMessage; - DestinationBuffer hDestination; - hDestination.type = BufferType::SHARED_MEMORY; - toSharedBuffer(plugin, destination, &hDestination.nonsecureMemory); - - SharedBuffer sourceBuffer; - toSharedBuffer(plugin, source, &sourceBuffer); - - plugin.decrypt( - false, hidl_array(keyId), hidl_array(iv), - Mode::AES_CTR, noPattern, hSubSamples, sourceBuffer, 0, hDestination, - [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) { - EXPECT_EQ(status, Status::OK); - - bytesWritten = hBytesWritten; - errorDetailMessage.assign(hDetailedError.c_str()); - }); - - EXPECT_EQ(kDataSize, bytesWritten) << - "WVCryptoPlugin decrypted the wrong number of bytes"; - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; -} - -TEST_F(WVCryptoPluginTest, RejectsCens) { - android::sp> cdm = new StrictMock(); - - constexpr size_t kSubSampleCount = 2; - SubSample subSamples[kSubSampleCount]; - memset(subSamples, 0, sizeof(subSamples)); - subSamples[0].numBytesOfEncryptedData = 16; - subSamples[1].numBytesOfClearData = 16; - subSamples[1].numBytesOfEncryptedData = 16; - - std::vector subSamplesVector( - subSamples, subSamples + sizeof(subSamples) / sizeof(subSamples[0])); - auto hSubSamples = hidl_vec(subSamplesVector); - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - - static const size_t kDataSize = 48; - uint8_t inputData[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(inputData, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - sp memDealer = new MemoryDealer( - kDataSize * 2, "WVCryptoPlugin_test"); - sp source = memDealer->allocate(kDataSize); - ASSERT_NE(source, nullptr); - pSrc = static_cast( - static_cast(source->unsecurePointer())); - ASSERT_NE(pSrc, nullptr); - memcpy(pSrc, inputData, source->size()); - - sp destination = memDealer->allocate(kDataSize); - ASSERT_NE(destination, nullptr); - pDest = static_cast( - static_cast(destination->unsecurePointer())); - ASSERT_NE(pDest, nullptr); - - Pattern recommendedPattern = { 1, 9 }; - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(testing::Return(true)); - - // Refuse calls to Decrypt - EXPECT_CALL(*cdm, DecryptV16(_, _, _)) - .Times(0); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - - DestinationBuffer hDestination; - hDestination.type = BufferType::SHARED_MEMORY; - toSharedBuffer(plugin, destination, &hDestination.nonsecureMemory); - - SharedBuffer sourceBuffer; - toSharedBuffer(plugin, source, &sourceBuffer); - - plugin.decrypt( - false, hidl_array(keyId), hidl_array(iv), - Mode::AES_CTR, recommendedPattern, hSubSamples, sourceBuffer, 0, - hDestination, - [&](Status status, uint32_t bytesWritten, - hidl_string /* errorDetailMessage */) { - EXPECT_EQ(status, Status::BAD_VALUE); - EXPECT_EQ(bytesWritten, 0); - }); -} - -TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) { - android::sp> cdm = new StrictMock(); - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - - static const size_t kDataSize = 32; - uint8_t in[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(in, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - SubSample subSample; - subSample.numBytesOfClearData = 16; - subSample.numBytesOfEncryptedData = 16; - std::vector subSampleVector; - subSampleVector.push_back(subSample); - auto hSubSamples = hidl_vec(subSampleVector); - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(testing::Return(true)); - - // Specify the expected calls to Decrypt - { - InSequence calls; - - typedef CdmDecryptionParametersV16 CDP; - - EXPECT_CALL(*cdm, DecryptV16(_, _, Field(&CDP::is_secure, false))) - .Times(1); - - EXPECT_CALL(*cdm, DecryptV16(_, _, Field(&CDP::is_secure, true))) - .Times(1); - } - - sp memDealer = new MemoryDealer( - kDataSize * 2, "WVCryptoPlugin_test"); - sp source = memDealer->allocate(kDataSize); - ASSERT_NE(source, nullptr); - pSrc = static_cast( - static_cast(source->unsecurePointer())); - ASSERT_NE(pSrc, nullptr); - memcpy(pSrc, in, source->size()); - - sp destination = memDealer->allocate(kDataSize); - ASSERT_NE(destination, nullptr); - pDest = static_cast( - static_cast(destination->unsecurePointer())); - ASSERT_NE(pDest, nullptr); - - WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get()); - - uint32_t bytesWritten = 0; - std::string errorDetailMessage; - DestinationBuffer hDestination; - hDestination.type = BufferType::SHARED_MEMORY; - toSharedBuffer(plugin, destination, &hDestination.nonsecureMemory); - Pattern noPattern = { 0, 0 }; - - SharedBuffer sourceBuffer; - toSharedBuffer(plugin, source, &sourceBuffer); - - plugin.decrypt( - false, hidl_array(keyId), hidl_array(iv), - Mode::AES_CTR, noPattern, hSubSamples, sourceBuffer, 0, hDestination, - [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) { - EXPECT_EQ(status, Status::OK); - - bytesWritten = hBytesWritten; - errorDetailMessage.assign(hDetailedError.c_str()); - }); - - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; - - plugin.decrypt( - true, hidl_array(keyId), hidl_array(iv), - Mode::AES_CTR, noPattern, hSubSamples, sourceBuffer, 0, hDestination, - [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) { - EXPECT_EQ(status, Status::OK); - - bytesWritten = hBytesWritten; - errorDetailMessage.assign(hDetailedError.c_str()); - }); - - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; -} - -TEST_F(WVCryptoPluginTest, AllowsSessionIdChanges) { - android::sp> cdm = new StrictMock(); - - uint8_t keyId[KEY_ID_SIZE]; - uint8_t iv[KEY_IV_SIZE]; - uint8_t sessionId2[kSessionIdSize]; - - static const size_t kDataSize = 32; - uint8_t in[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(iv, sizeof(uint8_t), KEY_IV_SIZE, fp); - fread(sessionId2, sizeof(uint8_t), kSessionIdSize, fp); - fread(in, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - SubSample subSample; - subSample.numBytesOfClearData = 16; - subSample.numBytesOfEncryptedData = 16; - std::vector subSampleVector; - subSampleVector.push_back(subSample); - auto hSubSamples = hidl_vec(subSampleVector); - - std::vector sessionIdVector(sessionId, sessionId + kSessionIdSize); - std::vector sessionId2Vector(sessionId2, - sessionId2 + kSessionIdSize); - - // Provide the expected behavior for IsOpenSession - EXPECT_CALL(*cdm, IsOpenSession(_)) - .WillRepeatedly(testing::Return(true)); - - // Specify the expected calls to Decrypt - { - InSequence calls; - - EXPECT_CALL(*cdm, - DecryptV16(ElementsAreArray(sessionId, kSessionIdSize), _, _)) - .Times(1); - - EXPECT_CALL(*cdm, - DecryptV16(ElementsAreArray(sessionId2, kSessionIdSize), _, _)) - .Times(1); - } - - sp memDealer = new MemoryDealer( - kDataSize * 2, "WVCryptoPlugin_test"); - sp source = memDealer->allocate(kDataSize); - ASSERT_NE(source, nullptr); - pSrc = static_cast( - static_cast(source->unsecurePointer())); - ASSERT_NE(pSrc, nullptr); - memcpy(pSrc, in, source->size()); - - sp destination = memDealer->allocate(kDataSize); - ASSERT_NE(destination, nullptr); - pDest = static_cast( - static_cast(destination->unsecurePointer())); - ASSERT_NE(pDest, nullptr); - - uint8_t blank[1]; // Some compilers will not accept 0. - WVCryptoPlugin plugin(blank, 0, cdm.get()); - - uint32_t bytesWritten = 0; - std::string errorDetailMessage; - DestinationBuffer hDestination; - hDestination.type = BufferType::SHARED_MEMORY; - toSharedBuffer(plugin, destination, &hDestination.nonsecureMemory); - Pattern noPattern = { 0, 0 }; - - SharedBuffer sourceBuffer; - toSharedBuffer(plugin, source, &sourceBuffer); - - Status status = plugin.setMediaDrmSession(sessionIdVector); - EXPECT_EQ(status, Status::OK); - - plugin.decrypt( - false, hidl_array(keyId), hidl_array(iv), - Mode::AES_CTR, noPattern, hSubSamples, sourceBuffer, 0, hDestination, - [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) { - EXPECT_EQ(status, Status::OK); - - bytesWritten = hBytesWritten; - errorDetailMessage.assign(hDetailedError.c_str()); - }); - - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; - - status = plugin.setMediaDrmSession(sessionId2Vector); - EXPECT_EQ(status, Status::OK); - - plugin.decrypt( - false, hidl_array(keyId), hidl_array(iv), - Mode::AES_CTR, noPattern, hSubSamples, sourceBuffer, 0, hDestination, - [&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) { - EXPECT_EQ(status, Status::OK); - - bytesWritten = hBytesWritten; - errorDetailMessage.assign(hDetailedError.c_str()); - }); - - EXPECT_EQ(0u, errorDetailMessage.size()) << - "WVCryptoPlugin reported a detailed error message."; -} - -TEST_F(WVCryptoPluginTest, DisallowsUnopenedSessionIdChanges) { - android::sp> cdm = new StrictMock(); - - uint8_t blank[1]; // Some compilers will not accept 0. - std::vector sessionIdVector(sessionId, sessionId + kSessionIdSize); - - // Specify the expected calls to IsOpenSession - { - InSequence calls; - - EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(blank, 0))) - .WillOnce(testing::Return(false)); - - EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(sessionId, kSessionIdSize))) - .WillOnce(testing::Return(false)) - .WillOnce(testing::Return(true)); - } - - WVCryptoPlugin plugin(blank, 0, cdm.get()); - - Status status = plugin.setMediaDrmSession(sessionIdVector); - EXPECT_EQ(status, Status::ERROR_DRM_SESSION_NOT_OPENED); - - status = plugin.setMediaDrmSession(sessionIdVector); - EXPECT_EQ(status, Status::OK); -} - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm diff --git a/libwvdrmengine/mediadrm/Android.bp b/libwvdrmengine/mediadrm/Android.bp index ef9664dd..9952518e 100644 --- a/libwvdrmengine/mediadrm/Android.bp +++ b/libwvdrmengine/mediadrm/Android.bp @@ -22,52 +22,6 @@ package { default_applicable_licenses: ["vendor_widevine_license"], } -// Builds libwvdrmdrmplugin_hidl -// -cc_library_static { - name: "libwvdrmdrmplugin_hidl", - - srcs: [ - "src_hidl/WVDrmPlugin.cpp", - "src_hidl/WVGenericCryptoInterface.cpp", - "src_hidl/hidl_metrics_adapter.cpp", - ], - - include_dirs: [ - "frameworks/av/include", - "frameworks/native/include", - "vendor/widevine/libwvdrmengine/cdm/core/include", - "vendor/widevine/libwvdrmengine/cdm/include", - "vendor/widevine/libwvdrmengine/cdm/metrics/include", - "vendor/widevine/libwvdrmengine/cdm/util/include", - "vendor/widevine/libwvdrmengine/include_hidl", - "vendor/widevine/libwvdrmengine/include", - "vendor/widevine/libwvdrmengine/mediadrm/include_hidl", - "vendor/widevine/libwvdrmengine/oemcrypto/include", - ], - - header_libs: [ - "libstagefright_headers", - "libstagefright_foundation_headers", - "libutils_headers", - ], - - static_libs: ["libcdm_protos"], - - shared_libs: [ - "android.hardware.drm@1.0", - "android.hardware.drm@1.1", - "android.hardware.drm@1.2", - "android.hardware.drm@1.3", - "android.hardware.drm@1.4", - "android.hidl.memory@1.0", - "libcrypto", - "liblog", - ], - - proprietary: true, -} - // Builds libwvdrmdrmplugin_aidl // cc_library_static { diff --git a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h index 5ace6611..c5fddb08 100644 --- a/libwvdrmengine/mediadrm/include/WVDrmPlugin.h +++ b/libwvdrmengine/mediadrm/include/WVDrmPlugin.h @@ -175,7 +175,7 @@ class WVDrmPlugin : public ::aidl::android::hardware::drm::BnDrmPlugin, const std::vector& in_signature, bool* _aidl_return) override; - // The following methods do not use hidl interface, it is used internally. + // The following methods do not use HAL interface, it is used internally. virtual Status unprovisionDevice(); virtual void OnSessionRenewalNeeded(const CdmSessionId& cdmSessionId); diff --git a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h b/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h deleted file mode 100644 index 5709960d..00000000 --- a/libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h +++ /dev/null @@ -1,510 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_DRM_PLUGIN_H_ -#define WV_DRM_PLUGIN_H_ - -#include - -#include -#include - -#include "HidlTypes.h" -#include "HidlWVTypes.h" -#include "OEMCryptoCENC.h" -#include "WVGenericCryptoInterface.h" -#include "cdm_client_property_set.h" -#include "cdm_identifier.h" -#include "log.h" -#include "wv_cdm_event_listener.h" -#include "wv_content_decryption_module.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using android::Mutex; -using std::map; -using wvcdm::CdmIdentifier; -using wvcdm::CdmKeyStatusMap; -using wvcdm::CdmResponseType; -using wvcdm::CdmSessionId; -using wvcdm::WvContentDecryptionModule; - -const OEMCrypto_Algorithm kInvalidCryptoAlgorithm = - static_cast(-1); - -struct WVDrmPlugin : public ::drm::V1_4::IDrmPlugin, - IDrmPluginListener, - wvcdm::WvCdmEventListener { - WVDrmPlugin(const sp& cdm, - const std::string& appPackageName, - WVGenericCryptoInterface* crypto, bool useSpoid); - - virtual ~WVDrmPlugin(); - - void Close(); - - Return openSession(openSession_cb _hidl_cb) override; - - Return openSession_1_1(SecurityLevel securityLevel, - openSession_1_1_cb _hidl_cb) override; - - Return closeSession(const hidl_vec& sessionId) override; - - Return getKeyRequest(const hidl_vec& scope, - const hidl_vec& initData, - const hidl_string& mimeType, KeyType keyType, - const hidl_vec& optionalParameters, - getKeyRequest_cb _hidl_cb) override; - - Return getKeyRequest_1_1(const hidl_vec& scope, - const hidl_vec& initData, - const hidl_string& mimeType, KeyType keyType, - const hidl_vec& optionalParameters, - getKeyRequest_1_1_cb _hidl_cb) override; - - Return getKeyRequest_1_2(const hidl_vec& scope, - const hidl_vec& initData, - const hidl_string& mimeType, KeyType keyType, - const hidl_vec& optionalParameters, - getKeyRequest_1_2_cb _hidl_cb) override; - - Return provideKeyResponse(const hidl_vec& scope, - const hidl_vec& response, - provideKeyResponse_cb _hidl_cb) override; - - Return removeKeys(const hidl_vec& sessionId) override; - - Return restoreKeys(const hidl_vec& sessionId, - const hidl_vec& keySetId) override; - - Return queryKeyStatus(const hidl_vec& sessionId, - queryKeyStatus_cb _hidl_cb) override; - - Return getProvisionRequest(const hidl_string& certificateType, - const hidl_string& certificateAuthority, - getProvisionRequest_cb _hidl_cb) override; - - Return getProvisionRequest_1_2( - const hidl_string& certificateType, - const hidl_string& certificateAuthority, - getProvisionRequest_1_2_cb _hidl_cb) override; - - Return provideProvisionResponse( - const hidl_vec& response, - provideProvisionResponse_cb _hidl_cb) override; - - Return getSecureStops(getSecureStops_cb _hidl_cb) override; - - Return getSecureStop(const hidl_vec& secureStopId, - getSecureStop_cb _hidl_cb) override; - - Return releaseAllSecureStops() override; - - Return releaseSecureStop( - const hidl_vec& secureStopId) override; - - Return getMetrics(getMetrics_cb _hidl_cb); - - Return getSecureStopIds(getSecureStopIds_cb _hidl_cb) override; - - Return releaseSecureStops( - const SecureStopRelease& ssRelease) override; - - Return removeSecureStop( - const hidl_vec& secureStopId) override; - - Return removeAllSecureStops() override; - - Return getHdcpLevels(getHdcpLevels_cb _hidl_cb) override; - Return getHdcpLevels_1_2(getHdcpLevels_1_2_cb _hidl_cb) override; - - Return getNumberOfSessions(getNumberOfSessions_cb _hidl_cb) override; - - Return getSecurityLevel(const hidl_vec& sessionId, - getSecurityLevel_cb _hidl_cb) override; - - Return getOfflineLicenseKeySetIds( - getOfflineLicenseKeySetIds_cb _hidl_cb) override; - - Return removeOfflineLicense(const KeySetId& keySetId) override; - - Return getOfflineLicenseState( - const KeySetId& keySetId, getOfflineLicenseState_cb _hidl_cb) override; - - Return getPropertyString(const hidl_string& propertyName, - getPropertyString_cb _hidl_cb) override; - - Return getPropertyByteArray(const hidl_string& propertyName, - getPropertyByteArray_cb _hidl_cb) override; - - Return setPropertyString(const hidl_string& propertyName, - const hidl_string& value) override; - - Return setPropertyByteArray(const hidl_string& propertyName, - const hidl_vec& value) override; - - Return setCipherAlgorithm(const hidl_vec& sessionId, - const hidl_string& algorithm) override; - - Return setMacAlgorithm(const hidl_vec& sessionId, - const hidl_string& algorithm) override; - - Return encrypt(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& input, - const hidl_vec& iv, - encrypt_cb _hidl_cb) override; - - Return decrypt(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& input, - const hidl_vec& iv, - decrypt_cb _hidl_cb) override; - - Return sign(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& message, - sign_cb _hidl_cb) override; - - Return verify(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& message, - const hidl_vec& signature, - verify_cb _hidl_cb) override; - - Return signRSA(const hidl_vec& sessionId, - const hidl_string& algorithm, - const hidl_vec& message, - const hidl_vec& wrappedkey, - signRSA_cb _hidl_cb) override; - - Return setListener(const sp& listener) override; - - Return sendEvent(EventType eventType, - const hidl_vec& sessionId, - const hidl_vec& data) override; - - Return sendExpirationUpdate(const hidl_vec& sessionId, - int64_t expiryTimeInMS) override; - - Return sendKeysChange(const hidl_vec& sessionId, - const hidl_vec& keyStatusList, - bool hasNewUsableKey) override; - - Return sendKeysChange_1_2(const hidl_vec& sessionId, - const hidl_vec& keyStatusList, - bool hasNewUsableKey) override; - - Return sendSessionLostState( - const hidl_vec& sessionId) override; - - Return getLogMessages(getLogMessages_cb _hidl_cb) override; - - Return requiresSecureDecoder(const hidl_string& mime, - SecurityLevel level) override; - - Return requiresSecureDecoderDefault(const hidl_string& mime) override; - - Return<::drm::V1_0::Status> setPlaybackId( - const hidl_vec& sessionId, - const hidl_string& playbackId) override; - - // The following methods do not use hidl interface, it is used internally. - virtual Status unprovisionDevice(); - - virtual void OnSessionRenewalNeeded(const CdmSessionId& cdmSessionId); - - template - void _sendKeysChange(const hidl_vec& sessionId, - const hidl_vec& keyStatusList, bool hasNewUsableKey); - - template - void _OnSessionKeysChange(const CdmSessionId&, const CdmKeyStatusMap&, - bool hasNewUsableKey); - - virtual void OnSessionKeysChange(const CdmSessionId& cdmSessionId, - const CdmKeyStatusMap& cdmKeysStatus, - bool hasNewUsableKey); - - virtual void OnExpirationUpdate(const CdmSessionId& cdmSessionId, - int64_t newExpiryTimeSeconds); - - virtual void OnSessionLostState(const CdmSessionId& cdmSessionId); - - private: - WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WVDrmPlugin); - - // List this field first so it is destructed last; ensure logging uid - // is cleared right before plugin is destructed. - wvutil::LoggingUidSetter mLoggingUidSetter; - - struct CryptoSession { - public: - CryptoSession() - : mOecSessionId(-1), - mCipherAlgorithm(kInvalidCryptoAlgorithm), - mMacAlgorithm(kInvalidCryptoAlgorithm) {} - - CryptoSession(OEMCrypto_SESSION sessionId) - : mOecSessionId(sessionId), - mCipherAlgorithm(kInvalidCryptoAlgorithm), - mMacAlgorithm(kInvalidCryptoAlgorithm) {} - - OEMCrypto_SESSION oecSessionId() const { return mOecSessionId; } - - OEMCrypto_Algorithm cipherAlgorithm() const { return mCipherAlgorithm; } - - void setCipherAlgorithm(OEMCrypto_Algorithm newAlgorithm) { - mCipherAlgorithm = newAlgorithm; - } - - OEMCrypto_Algorithm macAlgorithm() const { return mMacAlgorithm; } - - void setMacAlgorithm(OEMCrypto_Algorithm newAlgorithm) { - mMacAlgorithm = newAlgorithm; - } - - private: - OEMCrypto_SESSION mOecSessionId; - OEMCrypto_Algorithm mCipherAlgorithm; - OEMCrypto_Algorithm mMacAlgorithm; - }; - - class WVClientPropertySet : public wvcdm::CdmClientPropertySet { - public: - WVClientPropertySet() - : mUsePrivacyMode(false), - mShareKeys(false), - mSessionSharingId(0), - mUseAtscMode(false) {} - - virtual ~WVClientPropertySet() {} - - virtual const std::string& security_level() const { return mSecurityLevel; } - - void set_security_level(const std::string& securityLevel) { - mSecurityLevel = securityLevel; - } - - virtual bool use_privacy_mode() const { return mUsePrivacyMode; } - - void set_use_privacy_mode(bool usePrivacyMode) { - mUsePrivacyMode = usePrivacyMode; - } - - virtual const std::string& service_certificate() const { - return mServiceCertificate; - } - - virtual void set_service_certificate( - const std::string& serviceCertificate) { - mServiceCertificate = serviceCertificate; - } - - virtual const std::string& device_provisioning_service_certificate() const { - // Android does not support service certificates for provisioning. - return mEmptyString; - } - - virtual void set_device_provisioning_service_certificate( - const std::string&) { - // Ignore. Android does not support service certificates for provisioning - // TODO(b/69562876): Android SHOULD support service cert for provisioning - } - - virtual bool is_session_sharing_enabled() const { return mShareKeys; } - - void set_is_session_sharing_enabled(bool shareKeys) { - mShareKeys = shareKeys; - } - - virtual uint32_t session_sharing_id() const { return mSessionSharingId; } - - virtual void set_session_sharing_id(uint32_t id) { mSessionSharingId = id; } - - virtual const std::string& app_id() const { return mAppId; } - - void set_app_id(const std::string& appId) { mAppId = appId; } - - virtual bool use_atsc_mode() const { return mUseAtscMode; } - - void set_use_atsc_mode(bool useAtscMode) { mUseAtscMode = useAtscMode; } - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); - - std::string mSecurityLevel; - bool mUsePrivacyMode; - std::string mServiceCertificate; - bool mShareKeys; - uint32_t mSessionSharingId; - std::string mAppId; - bool mUseAtscMode; - const std::string mEmptyString; - } mPropertySet; - - class CdmIdentifierBuilder { - public: - CdmIdentifierBuilder(bool useSpoid, const WVDrmPlugin& parent, - const std::string& appPackageName); - - // Fills in the passed-in struct with the CDM Identifier for the current - // combination of Origin, Application, and Device. This is needed by some - // calls into the CDM in order to identify which CDM instance should receive - // the call. Calling this will seal the CDM Identifier Builder, thus making - // it an error to change the origin. - Status getCdmIdentifier(CdmIdentifier* identifier); - - // Gets the application-safe device-unique ID. On non-SPOID devices, this is - // the device-unique ID from OEMCrypto. On SPOID devices, this is the SPOID. - // On SPOID devices, calling this will seal the CDM Identifier Builder, thus - // making it an error to change the origin. - Status getDeviceUniqueId(std::string* id); - Status getProvisioningUniqueId(std::string* id); - - const std::string& origin() const { return mCdmIdentifier.origin; } - bool set_origin(const std::string& id); - - // This sets the app package name to allow apps to access ATSC licenses - bool set_use_atsc_mode(bool enable); - - // Indicates whether the builder can still be modified. This returns false - // until a call to getCdmIdentifier. - bool is_sealed() { return mIsIdentifierSealed; } - - uint32_t user_id() const { return mCdmIdentifier.user_id; } - - private: - WVDRM_DISALLOW_COPY_AND_ASSIGN(CdmIdentifierBuilder); - - CdmIdentifier mCdmIdentifier; - bool mIsIdentifierSealed; - - bool mUseSpoid; - std::string mAppPackageName; - const WVDrmPlugin& mParent; - - Status calculateSpoid(); - Status calculateSpoid(const std::string& deviceID, std::string* spoid); - - // Gets the device-unique ID from OEMCrypto. This must be private, since - // this value must not be exposed to applications on SPOID devices. Code - // outside this class should use getDeviceUniqueId() to get the - // application-safe device-unique ID. - Status getOemcryptoDeviceId(std::string* id); - Status getOemcryptoDeviceId(wvcdm::RequestedSecurityLevel securityLevel, - std::string* id); - - // The unique identifier is meant to ensure that two clients with the - // same spoid, origin and app package name still get different cdm engine - // instances. This is a stepping stone to simplifying the implementation. - // Note that we do not have a lock or mutex around this object. We assume - // that locking is handled external to this object. - uint32_t getNextUniqueId(); - } mCdmIdentifierBuilder; - - // Properly close plugins on SIGTERM then exit - class Terminator { - public: - static void Register(WVDrmPlugin* plugin) { instance().DoRegister(plugin); } - static void Forget(WVDrmPlugin* plugin) { instance().DoForget(plugin); } - static void Terminate(int /*signal*/) { instance().DoTerminate(); } - - private: - WVDRM_DISALLOW_COPY_AND_ASSIGN(Terminator); - - Terminator() { signal(SIGTERM, Terminate); } - - static Terminator& instance() { - static Terminator instance; - return instance; - } - - void DoRegister(WVDrmPlugin* plugin) { - Mutex::Autolock lock(mLock); - mPlugins.push_back(plugin); - } - - void DoForget(WVDrmPlugin* plugin) { - Mutex::Autolock lock(mLock); - mPlugins.remove(plugin); - } - - void DoTerminate() { - Mutex::Autolock lock(mLock); - for_each(mPlugins.begin(), mPlugins.end(), [] (WVDrmPlugin* plugin) { - ALOGI("WVDrmPlugin::Terminating plugin %p", (void*)plugin); - plugin->Close(); - }); - exit(0); - } - - std::list mPlugins; - Mutex mLock; - }; - - sp const mCDM; - WVGenericCryptoInterface* mCrypto; - map mCryptoSessions; - sp mListener; - sp mListenerV1_2; - - std::string mProvisioningServiceCertificate; - - wvcdm::CdmSessionId mDecryptHashSessionId; - - std::string mAppPackageName; - - Status queryProperty(const std::string& property, - std::string& stringValue) const; - - Status queryProperty(wvcdm::RequestedSecurityLevel securityLevel, - const std::string& property, - std::string& stringValue) const; - - Status queryProperty(const std::string& property, - std::vector& vector_value) const; - - bool isProvisioned(wvcdm::CdmSecurityLevel securityLevel, - const std::string& origin, const std::string& spoid, - bool atsc_mode_enabled) const; - - Status mapAndNotifyOfCdmResponseType(const std::vector& sessionId, - CdmResponseType res); - - Status_V1_2 mapAndNotifyOfCdmResponseType_1_2( - const std::vector& sessionId, CdmResponseType res); - - void notifyOfCdmResponseType(const std::vector& sessionId, - CdmResponseType res); - - Status mapAndNotifyOfOEMCryptoResult(const std::vector& sessionId, - OEMCryptoResult res); - - Status mapOEMCryptoResult(OEMCryptoResult res); - - SecurityLevel mapSecurityLevel(const std::string& level); - - wvcdm::RequestedSecurityLevel getRequestedSecurityLevel() const; - - Status openSessionCommon(std::vector& sessionId); - - bool initDataResemblesPSSH(const std::vector& initData); - - Status unprovision(const CdmIdentifier& identifier); -}; - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm - -#endif // WV_DRM_PLUGIN_H_ diff --git a/libwvdrmengine/mediadrm/include_hidl/WVGenericCryptoInterface.h b/libwvdrmengine/mediadrm/include_hidl/WVGenericCryptoInterface.h deleted file mode 100644 index 989fc991..00000000 --- a/libwvdrmengine/mediadrm/include_hidl/WVGenericCryptoInterface.h +++ /dev/null @@ -1,98 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef WV_GENERIC_CRYPTO_INTERFACE_H_ -#define WV_GENERIC_CRYPTO_INTERFACE_H_ - -#include -#include - -#include "OEMCryptoCENC.h" -#include "media/stagefright/foundation/ABase.h" - -namespace wvdrm { - -class WVGenericCryptoInterface { - public: - WVGenericCryptoInterface() {} - virtual ~WVGenericCryptoInterface() {} - - virtual OEMCryptoResult selectKey(const OEMCrypto_SESSION session, - const uint8_t* key_id, - size_t key_id_length) { - return OEMCrypto_SelectKey(session, key_id, key_id_length, - OEMCrypto_CipherMode_CBCS); - } - - virtual OEMCryptoResult encrypt(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - return OEMCrypto_Generic_Encrypt(session, in_buffer, buffer_length, iv, - algorithm, out_buffer); - } - - virtual OEMCryptoResult decrypt(OEMCrypto_SESSION session, - const uint8_t* in_buffer, - size_t buffer_length, const uint8_t* iv, - OEMCrypto_Algorithm algorithm, - uint8_t* out_buffer) { - return OEMCrypto_Generic_Decrypt(session, in_buffer, buffer_length, iv, - algorithm, out_buffer); - } - - virtual OEMCryptoResult sign(OEMCrypto_SESSION session, - const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, - uint8_t* signature, size_t* signature_length) { - return OEMCrypto_Generic_Sign(session, in_buffer, buffer_length, algorithm, - signature, signature_length); - } - - virtual OEMCryptoResult verify(OEMCrypto_SESSION session, - const uint8_t* in_buffer, size_t buffer_length, - OEMCrypto_Algorithm algorithm, - const uint8_t* signature, - size_t signature_length) { - return OEMCrypto_Generic_Verify(session, in_buffer, buffer_length, - algorithm, signature, signature_length); - } - - virtual OEMCryptoResult signRSA(const uint8_t* wrapped_rsa_key, - size_t wrapped_rsa_key_length, - const uint8_t* message, - size_t message_length, - std::vector& signature, - RSA_Padding_Scheme padding_scheme); - - - virtual OEMCryptoResult loadDeviceRSAKey(OEMCrypto_SESSION session, - const uint8_t* wrapped_rsa_key, - size_t wrapped_rsa_key_length) { - return OEMCrypto_LoadDRMPrivateKey(session, OEMCrypto_RSA_Private_Key, - wrapped_rsa_key, wrapped_rsa_key_length); - } - - virtual OEMCryptoResult generateRSASignature( - OEMCrypto_SESSION session, - const uint8_t* message, - size_t message_length, - uint8_t* signature, - size_t* signature_length, - RSA_Padding_Scheme padding_scheme) { - return OEMCrypto_GenerateRSASignature(session, message, message_length, - signature, signature_length, - padding_scheme); -} - - private: - DISALLOW_EVIL_CONSTRUCTORS(WVGenericCryptoInterface); -}; - -} // namespace wvdrm - -#endif // WV_GENERIC_CRYPTO_INTERFACE_H_ diff --git a/libwvdrmengine/mediadrm/include_hidl/hidl_metrics_adapter.h b/libwvdrmengine/mediadrm/include_hidl/hidl_metrics_adapter.h deleted file mode 100644 index f35b4589..00000000 --- a/libwvdrmengine/mediadrm/include_hidl/hidl_metrics_adapter.h +++ /dev/null @@ -1,113 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#ifndef CDM_HIDL_METRICS_ADAPTER_H_ -#define CDM_HIDL_METRICS_ADAPTER_H_ - -#include - -#include - -#include "wv_metrics.pb.h" - -namespace wvcdm { - -// Convenience alias. Used only in the declaration of HidlMetricsGroup. -namespace internal { -using DrmMetricGroup = android::hardware::drm::V1_1::DrmMetricGroup; -} // namespace internal - -class HidlMetricsAdapter; - -// This class is used to convert from the metrics.proto format for metrics -// to the format specified in the android.hardware.drm@1.1 DrmMetricGroup -// type. This class converts the common metric types into a single group. -// -// Example: -// drm_metrics::DistributionMetric distribution; -// distribution.set_operation_count(1); -// HidlMetricsGroupBuilder builder; -// builder.AddDistributions("test distribution", { distribution }); -// -// DrmMetricGroup group = builder.Build(); -class HidlMetricsGroupBuilder { - public: - // Adds a group of distributions with the given base name. - void AddDistributions( - const std::string& name, - const google::protobuf::RepeatedPtrField< - drm_metrics::DistributionMetric>& distributions); - - // Adds a group of counter metrics with the given base name. - void AddCounters( - const std::string& name, - const google::protobuf::RepeatedPtrField< - drm_metrics::CounterMetric>& counters); - - // Adds a value metric. - void AddValue(const std::string& name, - const drm_metrics::ValueMetric& value_or_error); - - // Builds the metric group containing all of the previously added metrics. - internal::DrmMetricGroup Build(); - - private: - friend class HidlMetricsAdapter; - std::vector metrics_; - - HidlMetricsGroupBuilder(); - // Adds a distribution with the given name and distribution values. - void AddDistribution(const std::string& name, - const drm_metrics::DistributionMetric& distribution); - // Adds a counter metric - void AddCounter(const std::string& name, - const drm_metrics::CounterMetric& counter); - void AddAttributes( - const drm_metrics::Attributes& attributes_proto, - ::android::hardware::hidl_vec* - attributes); -}; - -// This class handles adding the engine and session metric collections. This -// will generate one DrmMetricGroup for each EngineMetric added and one for -// each SessionMetric added. This class also supports a static utility method to -// convert a WvCdmMetrics proto to a vector of DrmMetricGroup instances. -class HidlMetricsAdapter { - public: - // Utility method to quickly convert a WvCdmMetrics proto to a DrmMetricGroup - // vector. - static void ToHidlMetrics( - const drm_metrics::WvCdmMetrics& proto_metrics, - android::hardware::hidl_vec* hidl_metrics); - - HidlMetricsAdapter(); - ~HidlMetricsAdapter(); - - // Adds the EngineMetrics instance to the Adapter. It will be converted and - // stored. The converted metrics can be fetched via GetHidlGroupVector. - void AddEngineMetrics( - const drm_metrics::WvCdmMetrics::EngineMetrics& proto_metrics); - - // Adds the SessionMetrics instance to the Adapter. It will be converted and - // stored. The converted metrics can be fetched via GetHidlGroupVector. - void AddSessionMetrics( - const drm_metrics::WvCdmMetrics::SessionMetrics& proto_metrics); - - // Returns the converted DrmMetricGroup vector containing all of the - // previously added engine and session metrics collections. - const android::hardware::hidl_vec - GetHidlGroupVector(); - - private: - void AddCryptoMetrics( - const drm_metrics::WvCdmMetrics::CryptoMetrics& proto_metrics, - HidlMetricsGroupBuilder* group_builder); - std::vector group_vector_; -}; - -} // namespace wvcdm - -#endif // CDM_HIDL_METRICS_ADAPTER_H_ diff --git a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp b/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp deleted file mode 100644 index 39073f42..00000000 --- a/libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp +++ /dev/null @@ -1,2364 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include "WVDrmPlugin.h" - -#include -#include -#include - -#include -#include -#include -#include - -#include "HidlMapErrors-inl.h" -#include "HidlTypes.h" -#include "TypeConvert.h" -#include "android-base/macros.h" -#include "hidl_metrics_adapter.h" -#include "log.h" -#include "media/stagefright/MediaErrors.h" -#include "openssl/sha.h" -#include "wv_cdm_constants.h" -#include "wv_metrics.pb.h" - -namespace { - -static const char* const kResetSecurityLevel = ""; -static const char* const kEnable = "enable"; -static const char* const kDisable = "disable"; -static const std::string kPsshTag = "pssh"; -static const char* const kSpecialUnprovisionResponse = "unprovision"; -static const std::string kKeyAppPackageName = "application_name"; -static const std::string kKeyOrigin = "origin"; - -} // namespace - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using android::hardware::drm::V1_2::widevine::toHidlVec; -using android::hardware::drm::V1_2::widevine::toVector; -using wvcdm::CdmAppParameterMap; -using wvcdm::CdmCertificateType; -using wvcdm::CdmInitData; -using wvcdm::CdmKeyRequest; -using wvcdm::CdmKeyRequestType; -using wvcdm::CdmKeyResponse; -using wvcdm::CdmKeySetId; -using wvcdm::CdmKeyStatus; -using wvcdm::CdmLicenseType; -using wvcdm::CdmProvisioningRequest; -using wvcdm::CdmProvisioningResponse; -using wvcdm::CdmQueryMap; -using wvcdm::CdmSecureStopId; -using wvcdm::CdmSecurityLevel; -using wvcdm::CdmUsageInfo; -using wvcdm::CdmUsageInfoReleaseMessage; -using wvcdm::kDefaultCdmIdentifier; -using wvcdm::KeyId; - -namespace { - -std::vector StrToVector(const std::string& str) { - std::vector vec(str.begin(), str.end()); - return vec; -} - -KeyRequestType ConvertFromCdmKeyRequestType(CdmKeyRequestType keyRequestType) { - switch (keyRequestType) { - case wvcdm::kKeyRequestTypeInitial: - return KeyRequestType::INITIAL; - case wvcdm::kKeyRequestTypeRenewal: - return KeyRequestType::RENEWAL; - case wvcdm::kKeyRequestTypeRelease: - return KeyRequestType::RELEASE; - default: - return KeyRequestType::UNKNOWN; - } -} - -KeyRequestType_V1_1 ConvertFromCdmKeyRequestType_1_1( - CdmKeyRequestType keyRequestType) { - switch (keyRequestType) { - case wvcdm::kKeyRequestTypeNone: - return KeyRequestType_V1_1::NONE; - case wvcdm::kKeyRequestTypeUpdate: - return KeyRequestType_V1_1::UPDATE; - default: - return static_cast( - ConvertFromCdmKeyRequestType(keyRequestType)); - } -} - -KeyRequestType toKeyRequestType_V1_0(KeyRequestType_V1_1 keyRequestType) { - switch (keyRequestType) { - case KeyRequestType_V1_1::NONE: - case KeyRequestType_V1_1::UPDATE: - return KeyRequestType::UNKNOWN; - default: - return static_cast(keyRequestType); - } -} - -Status toStatus_1_0(Status_V1_2 status) { - switch (status) { - case Status_V1_2::ERROR_DRM_INSUFFICIENT_SECURITY: - case Status_V1_2::ERROR_DRM_FRAME_TOO_LARGE: - case Status_V1_2::ERROR_DRM_SESSION_LOST_STATE: - case Status_V1_2::ERROR_DRM_RESOURCE_CONTENTION: - return Status::ERROR_DRM_UNKNOWN; - default: - return static_cast(status); - } -} - -template -KST ConvertFromCdmKeyStatus(CdmKeyStatus keyStatus); - -template <> -KeyStatusType ConvertFromCdmKeyStatus(CdmKeyStatus keyStatus) { - switch (keyStatus) { - case wvcdm::kKeyStatusUsable: - return KeyStatusType::USABLE; - case wvcdm::kKeyStatusExpired: - return KeyStatusType::EXPIRED; - case wvcdm::kKeyStatusOutputNotAllowed: - return KeyStatusType::OUTPUTNOTALLOWED; - case wvcdm::kKeyStatusPending: - case wvcdm::kKeyStatusUsableInFuture: - return KeyStatusType::STATUSPENDING; - case wvcdm::kKeyStatusInternalError: - default: - return KeyStatusType::INTERNALERROR; - } -} - -template <> -KeyStatusType_V1_2 ConvertFromCdmKeyStatus( - CdmKeyStatus keyStatus) { - switch (keyStatus) { - case wvcdm::kKeyStatusUsableInFuture: - return KeyStatusType_V1_2::USABLEINFUTURE; - default: - return static_cast( - ConvertFromCdmKeyStatus(keyStatus)); - } -} - -HdcpLevel mapHdcpLevel(const std::string& level) { - if (level == wvcdm::QUERY_VALUE_HDCP_V1) - return HdcpLevel::HDCP_V1; - else if (level == wvcdm::QUERY_VALUE_HDCP_V2_0) - return HdcpLevel::HDCP_V2; - else if (level == wvcdm::QUERY_VALUE_HDCP_V2_1) - return HdcpLevel::HDCP_V2_1; - else if (level == wvcdm::QUERY_VALUE_HDCP_V2_2) - return HdcpLevel::HDCP_V2_2; - else if (level == wvcdm::QUERY_VALUE_HDCP_NONE) - return HdcpLevel::HDCP_NONE; - else if (level == wvcdm::QUERY_VALUE_HDCP_NO_DIGITAL_OUTPUT) - return HdcpLevel::HDCP_NO_OUTPUT; - else { - ALOGE("Invalid HDCP level=%s", level.c_str()); - return HdcpLevel::HDCP_NONE; - } -} - -HdcpLevel_V1_2 mapHdcpLevel_1_2(const std::string level) { - if (level == wvcdm::QUERY_VALUE_HDCP_V2_3) { - return HdcpLevel_V1_2::HDCP_V2_3; - } - return static_cast(mapHdcpLevel(level)); -} - -HdcpLevel toHdcpLevel_1_1(HdcpLevel_V1_2 level) { - if (level == HdcpLevel_V1_2::HDCP_V2_3) { - return HdcpLevel::HDCP_NONE; - } - return static_cast(level); -} - -} // namespace - -WVDrmPlugin::WVDrmPlugin(const sp& cdm, - const std::string& appPackageName, - WVGenericCryptoInterface* crypto, bool useSpoid) - : mCdmIdentifierBuilder(useSpoid, *this, appPackageName), - mCDM(cdm), - mCrypto(crypto), - mCryptoSessions(), - mAppPackageName(appPackageName) { - Terminator::Register(this); -} - -WVDrmPlugin::~WVDrmPlugin() { - wvutil::SetLoggingUid(mCdmIdentifierBuilder.user_id()); - Terminator::Forget(this); - Close(); -} - -void WVDrmPlugin::Close() { - typedef map::iterator mapIterator; - for (mapIterator iter = mCryptoSessions.begin(); - iter != mCryptoSessions.end(); ++iter) { - CdmResponseType res = mCDM->CloseSession(iter->first); - if (!isCdmResponseTypeSuccess(res)) { - ALOGE("Failed to close session while destroying WVDrmPlugin"); - } - } - mCryptoSessions.clear(); - if (mCdmIdentifierBuilder.is_sealed()) { - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - ALOGE("Failed to get cdm identifier %d", status); - } else { - status = mapCdmResponseType(mCDM->CloseCdm(identifier)); - if (status != Status::OK) { - ALOGE("Failed to close cdm. status %d", status); - } - } - } -} - -Status WVDrmPlugin::openSessionCommon(std::vector& sessionId) { - Status status = Status::OK; - - CdmIdentifier identifier; - status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - return status; - } - - CdmSessionId cdmSessionId; - CdmResponseType res = mCDM->OpenSession("com.widevine", &mPropertySet, - identifier, this, &cdmSessionId); - - if (!isCdmResponseTypeSuccess(res)) { - status = mapAndNotifyOfCdmResponseType(sessionId, res); - return status; - } - - bool success = false; - - // Construct a CryptoSession - CdmQueryMap info; - res = mCDM->QueryOemCryptoSessionId(cdmSessionId, &info); - - if (isCdmResponseTypeSuccess(res) && - info.count(wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID)) { - OEMCrypto_SESSION oecSessionId = - std::stoul(info[wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID]); - mCryptoSessions[cdmSessionId] = CryptoSession(oecSessionId); - success = true; - } else { - ALOGE("Unable to query key control info."); - } - - if (success) { - // Marshal Session ID - sessionId = StrToVector(cdmSessionId); - return Status::OK; - } else { - mCDM->CloseSession(cdmSessionId); - - if (!isCdmResponseTypeSuccess(res)) { - // We got an error code we can return. - status = mapAndNotifyOfCdmResponseType(sessionId, res); - } else { - // We got a failure that did not give us an error code, such as a failure - // of AttachEventListener() or the key being missing from the map. - ALOGW("Returns UNKNOWN error for legacy status kErrorCDMGeneric"); - status = Status::ERROR_DRM_UNKNOWN; - } - } - - return status; -} - -Return WVDrmPlugin::openSession(openSession_cb _hidl_cb) { - std::vector sessionId; - Status status = openSessionCommon(sessionId); - - _hidl_cb(status, toHidlVec(sessionId)); - return Void(); -} - -SecurityLevel WVDrmPlugin::mapSecurityLevel(const std::string& level) { - SecurityLevel hSecurityLevel = SecurityLevel::UNKNOWN; - - if (wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1 == level) { - hSecurityLevel = SecurityLevel::HW_SECURE_ALL; - } else if (wvcdm::QUERY_VALUE_SECURITY_LEVEL_L2 == level) { - hSecurityLevel = SecurityLevel::HW_SECURE_CRYPTO; - } else if (wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3 == level) { - hSecurityLevel = SecurityLevel::SW_SECURE_CRYPTO; - } // else QUERY_VALUE_SECURITY_LEVEL_UNKNOWN returns Security::UNKNOWN - - return hSecurityLevel; -} - -Return WVDrmPlugin::openSession_1_1(SecurityLevel requestedLevel, - openSession_1_1_cb _hidl_cb) { - std::vector sessionId; - sessionId.clear(); - - if (SecurityLevel::UNKNOWN == requestedLevel) { - _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, toHidlVec(sessionId)); - return Void(); - } - - std::string native_security_level; - Status status = - queryProperty(wvcdm::kLevelDefault, wvcdm::QUERY_KEY_SECURITY_LEVEL, - native_security_level); - if (Status::OK != status) { - _hidl_cb(status, toHidlVec(sessionId)); - return Void(); - } - - if (wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3 == native_security_level && - requestedLevel >= SecurityLevel::SW_SECURE_DECODE) { - _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, toHidlVec(sessionId)); - return Void(); - } - - std::string wvcdm_security_level = - (SecurityLevel::SW_SECURE_CRYPTO == requestedLevel) - ? wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3 - : wvcdm::QUERY_VALUE_SECURITY_LEVEL_DEFAULT; - - setPropertyString("securityLevel", hidl_string(wvcdm_security_level)); - - status = openSessionCommon(sessionId); - hidl_vec hSessionId = toHidlVec(sessionId); - if (Status::OK == status) { - SecurityLevel currentSecurityLevel = SecurityLevel::UNKNOWN; - Return hResult = getSecurityLevel( - hSessionId, [&](Status gslStatus, SecurityLevel hSecurityLevel) { - currentSecurityLevel = hSecurityLevel; - if (Status::OK != gslStatus || requestedLevel != hSecurityLevel) { - ALOGE("Failed to open session with the requested security level=%d", - requestedLevel); - closeSession(hSessionId); - sessionId.clear(); - } - }); - if (!hResult.isOk() || (requestedLevel != currentSecurityLevel)) { - status = Status::ERROR_DRM_INVALID_STATE; - } - } - _hidl_cb(status, toHidlVec(sessionId)); - return Void(); -} - -Return WVDrmPlugin::closeSession(const hidl_vec& sessionId) { - if (!sessionId.size()) { - return Status::BAD_VALUE; - } - const std::vector sId = toVector(sessionId); - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - CdmResponseType res = mCDM->CloseSession(cdmSessionId); - mCryptoSessions.erase(cdmSessionId); - if (!isCdmResponseTypeSuccess(res)) { - return Status::ERROR_DRM_SESSION_NOT_OPENED; - } - return Status::OK; -} - -Return WVDrmPlugin::getKeyRequest( - const hidl_vec& scope, const hidl_vec& initData, - const hidl_string& mimeType, KeyType keyType, - const hidl_vec& optionalParameters, getKeyRequest_cb _hidl_cb) { - hidl_string defaultUrl; - hidl_vec request; - KeyRequestType requestType = KeyRequestType::UNKNOWN; - Status status = Status::ERROR_DRM_UNKNOWN; - - defaultUrl.clear(); - Return hResult = getKeyRequest_1_1( - scope, initData, mimeType, keyType, optionalParameters, - [&](Status statusCode, const hidl_vec& hRequest, - KeyRequestType_V1_1 hKeyRequestType, const hidl_string& hDefaultUrl) { - defaultUrl = hDefaultUrl; - request = hRequest; - requestType = toKeyRequestType_V1_0(hKeyRequestType); - status = statusCode; - }); - if (!hResult.isOk()) { - status = Status::ERROR_DRM_INVALID_STATE; - } - _hidl_cb(status, request, requestType, defaultUrl); - return Void(); -} - -Return WVDrmPlugin::getKeyRequest_1_1( - const hidl_vec& scope, const hidl_vec& initData, - const hidl_string& mimeType, KeyType keyType, - const hidl_vec& optionalParameters, - getKeyRequest_1_1_cb _hidl_cb) { - hidl_string defaultUrl; - hidl_vec request; - KeyRequestType_V1_1 requestType = KeyRequestType_V1_1::UNKNOWN; - Status status = Status::ERROR_DRM_UNKNOWN; - - defaultUrl.clear(); - Return hResult = getKeyRequest_1_2( - scope, initData, mimeType, keyType, optionalParameters, - [&](Status_V1_2 statusCode, const hidl_vec& hRequest, - KeyRequestType_V1_1 hKeyRequestType, const hidl_string& hDefaultUrl) { - defaultUrl = hDefaultUrl; - request = hRequest; - requestType = hKeyRequestType; - status = toStatus_1_0(statusCode); - }); - if (!hResult.isOk()) { - status = Status::ERROR_DRM_INVALID_STATE; - } - _hidl_cb(status, request, requestType, defaultUrl); - return Void(); -} - -Return WVDrmPlugin::getKeyRequest_1_2( - const hidl_vec& scope, const hidl_vec& initData, - const hidl_string& mimeType, KeyType keyType, - const hidl_vec& optionalParameters, - getKeyRequest_1_2_cb _hidl_cb) { - if (!scope.size()) { - _hidl_cb(Status_V1_2::BAD_VALUE, hidl_vec(), - KeyRequestType_V1_1::UNKNOWN, ""); - return Void(); - } - KeyRequestType_V1_1 requestType = KeyRequestType_V1_1::UNKNOWN; - Status_V1_2 status = Status_V1_2::OK; - std::string defaultUrl; - std::vector request; - const std::vector scopeId = toVector(scope); - - CdmIdentifier identifier; - status = static_cast( - mCdmIdentifierBuilder.getCdmIdentifier(&identifier)); - if (status != Status_V1_2::OK) { - _hidl_cb(status, toHidlVec(request), requestType, defaultUrl.c_str()); - return Void(); - } - - CdmLicenseType cdmLicenseType; - CdmSessionId cdmSessionId; - CdmKeySetId cdmKeySetId; - if (keyType == KeyType::OFFLINE) { - cdmLicenseType = wvcdm::kLicenseTypeOffline; - cdmSessionId.assign(scopeId.begin(), scopeId.end()); - } else if (keyType == KeyType::STREAMING) { - cdmLicenseType = wvcdm::kLicenseTypeStreaming; - cdmSessionId.assign(scopeId.begin(), scopeId.end()); - } else if (keyType == KeyType::RELEASE) { - cdmLicenseType = wvcdm::kLicenseTypeRelease; - cdmKeySetId.assign(scopeId.begin(), scopeId.end()); - } else { - _hidl_cb(Status_V1_2::BAD_VALUE, toHidlVec(request), - KeyRequestType_V1_1::UNKNOWN, defaultUrl.c_str()); - return Void(); - } - - std::string cdmInitDataType = mimeType; - // Provide backwards-compatibility for apps that pass non-EME-compatible MIME - // types. - if (!WvContentDecryptionModule::IsSupported(cdmInitDataType)) { - cdmInitDataType = wvcdm::ISO_BMFF_VIDEO_MIME_TYPE; - } - - CdmInitData processedInitData; - if (initData.size() > 0 && - WvContentDecryptionModule::IsCenc(cdmInitDataType) && - !initDataResemblesPSSH(toVector(initData))) { - // This data was passed in the old format, pre-unwrapped. We need to wrap - // the init data in a new PSSH header. - static const uint8_t psshPrefix[] = { - 0, 0, 0, 0, // Total size - 'p', 's', 's', 'h', // "PSSH" - 0, 0, 0, 0, // Flags - must be zero - 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, // Widevine UUID - 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED, - 0, 0, 0, 0 // Size of initData - }; - processedInitData.assign(reinterpret_cast(psshPrefix), - sizeof(psshPrefix) / sizeof(uint8_t)); - processedInitData.append(reinterpret_cast(initData.data()), - initData.size()); - const size_t kPsshBoxSizeLocation = 0; - const size_t kInitDataSizeLocation = sizeof(psshPrefix) - sizeof(uint32_t); - uint32_t psshBoxSize = htonl(processedInitData.size()); - uint32_t initDataSize = htonl(initData.size()); - memcpy(&processedInitData[kPsshBoxSizeLocation], &psshBoxSize, - sizeof(uint32_t)); - memcpy(&processedInitData[kInitDataSizeLocation], &initDataSize, - sizeof(uint32_t)); - } else { - // For other formats, we can pass the init data through unmodified. - processedInitData.assign(reinterpret_cast(initData.data()), - initData.size()); - } - - CdmAppParameterMap cdmParameters; - for (size_t i = 0; i < optionalParameters.size(); ++i) { - const std::string& key(optionalParameters[i].key); - const std::string& value(optionalParameters[i].value); - - std::string cdmKey(key.c_str(), key.size()); - std::string cdmValue(value.c_str(), value.size()); - - cdmParameters[cdmKey] = cdmValue; - } - - // Inserting additional client ID parameters here, this will appear - // in the license request. - // Note: This will overwrite user parameters of the same key. - cdmParameters[kKeyAppPackageName] = mAppPackageName; - cdmParameters[kKeyOrigin] = mCdmIdentifierBuilder.origin(); - - CdmKeyRequest keyRequest; - CdmResponseType res = mCDM->GenerateKeyRequest( - cdmSessionId, cdmKeySetId, cdmInitDataType, processedInitData, - cdmLicenseType, cdmParameters, &mPropertySet, identifier, &keyRequest); - - requestType = ConvertFromCdmKeyRequestType_1_1(keyRequest.type); - - if (isCdmResponseTypeSuccess(res)) { - defaultUrl.clear(); - defaultUrl.assign(keyRequest.url.data(), keyRequest.url.size()); - - request = StrToVector(keyRequest.message); - } - - if (keyType == KeyType::RELEASE) { - // When releasing keys, we do not have a session ID. - status = mapCdmResponseType(res); - } else { - // For all other requests, we have a session ID. - status = mapAndNotifyOfCdmResponseType_1_2(scopeId, res); - } - _hidl_cb(status, toHidlVec(request), requestType, defaultUrl.c_str()); - return Void(); -} - -Return WVDrmPlugin::provideKeyResponse(const hidl_vec& scope, - const hidl_vec& response, - provideKeyResponse_cb _hidl_cb) { - if (scope.size() == 0 || response.size() == 0) { - _hidl_cb(Status::BAD_VALUE, hidl_vec()); - return Void(); - } - const std::vector resp = toVector(response); - const std::vector scopeId = toVector(scope); - - CdmKeySetId cdmKeySetId; - CdmSessionId cdmSessionId; - CdmKeyResponse cdmResponse(resp.begin(), resp.end()); - - bool isRequest = (memcmp(scopeId.data(), wvcdm::SESSION_ID_PREFIX, - sizeof(wvcdm::SESSION_ID_PREFIX) - 1) == 0); - bool isRelease = (memcmp(scopeId.data(), wvcdm::KEY_SET_ID_PREFIX, - sizeof(wvcdm::KEY_SET_ID_PREFIX) - 1) == 0); - - std::vector keySetId; - - if (isRequest) { - cdmSessionId.assign(scopeId.begin(), scopeId.end()); - } else if (isRelease) { - cdmKeySetId.assign(scopeId.begin(), scopeId.end()); - } else { - _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, toHidlVec(keySetId)); - return Void(); - } - - CdmResponseType res = mCDM->AddKey(cdmSessionId, cdmResponse, &cdmKeySetId); - - if (isRequest && isCdmResponseTypeSuccess(res)) { - keySetId = StrToVector(cdmKeySetId); - } - - Status status = Status::OK; - if (isRelease) { - // When releasing keys, we do not have a session ID. - status = mapCdmResponseType(res); - } else { - // For all other requests, we have a session ID. - status = mapAndNotifyOfCdmResponseType(scopeId, res); - // For "NEED_KEY," we still want to send the notifcation, but then we don't - // return the error. This is because "NEED_KEY" from AddKey() is an - // expected behavior when sending a privacy certificate. - if (res == wvcdm::NEED_KEY && mPropertySet.use_privacy_mode()) { - status = Status::OK; - } - } - _hidl_cb(status, toHidlVec(keySetId)); - return Void(); -} - -Return WVDrmPlugin::removeKeys(const hidl_vec& sessionId) { - if (!sessionId.size()) { - return Status::BAD_VALUE; - } - const std::vector sId = toVector(sessionId); - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - - CdmResponseType res = mCDM->RemoveKeys(cdmSessionId); - - return mapAndNotifyOfCdmResponseType(sId, res); -} - -Return WVDrmPlugin::restoreKeys(const hidl_vec& sessionId, - const hidl_vec& keySetId) { - if (!sessionId.size() || !keySetId.size()) { - return Status::BAD_VALUE; - } - const std::vector kId = toVector(keySetId); - const std::vector sId = toVector(sessionId); - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - CdmKeySetId cdmKeySetId(kId.begin(), kId.end()); - - CdmResponseType res = mCDM->RestoreKey(cdmSessionId, cdmKeySetId); - - return mapAndNotifyOfCdmResponseType(sId, res); -} - -Return WVDrmPlugin::queryKeyStatus(const hidl_vec& sessionId, - queryKeyStatus_cb _hidl_cb) { - if (sessionId.size() == 0) { - _hidl_cb(Status::BAD_VALUE, hidl_vec()); - return Void(); - } - const std::vector sId = toVector(sessionId); - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - CdmQueryMap cdmLicenseInfo; - - CdmResponseType res = mCDM->QueryKeyStatus(cdmSessionId, &cdmLicenseInfo); - - std::vector infoMapVec; - if (isCdmResponseTypeSuccess(res)) { - infoMapVec.clear(); - - KeyValue keyValuePair; - for (CdmQueryMap::const_iterator iter = cdmLicenseInfo.begin(); - iter != cdmLicenseInfo.end(); ++iter) { - const std::string& cdmKey = iter->first; - const std::string& cdmValue = iter->second; - keyValuePair.key = std::string(cdmKey.data(), cdmKey.size()); - keyValuePair.value = std::string(cdmValue.data(), cdmValue.size()); - infoMapVec.push_back(keyValuePair); - } - } - - _hidl_cb(mapCdmResponseType(res), toHidlVec(infoMapVec)); - return Void(); -} - -Return WVDrmPlugin::getProvisionRequest( - const hidl_string& certificateType, const hidl_string& certificateAuthority, - getProvisionRequest_cb _hidl_cb) { - Status status = Status::OK; - std::string defaultUrl; - std::vector request; - - Return hResult = getProvisionRequest_1_2( - certificateType, certificateAuthority, - [&](Status_V1_2 statusCode, const hidl_vec& hRequest, - const hidl_string& hDefaultUrl) { - request = hRequest; - status = toStatus_1_0(statusCode); - defaultUrl = hDefaultUrl; - }); - if (!hResult.isOk()) { - status = Status::ERROR_DRM_INVALID_STATE; - } - - _hidl_cb(status, toHidlVec(request), hidl_string(defaultUrl)); - return Void(); -} - -Return WVDrmPlugin::getProvisionRequest_1_2( - const hidl_string& certificateType, const hidl_string& certificateAuthority, - getProvisionRequest_1_2_cb _hidl_cb) { - Status_V1_2 status = Status_V1_2::OK; - std::string defaultUrl; - std::vector request; - - if (mPropertySet.use_atsc_mode()) { - _hidl_cb(mapCdmResponseType( - wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC), - toHidlVec(request), hidl_string(defaultUrl)); - return Void(); - } - - CdmIdentifier identifier; - status = static_cast( - mCdmIdentifierBuilder.getCdmIdentifier(&identifier)); - if (status != Status_V1_2::OK) { - _hidl_cb(status, toHidlVec(request), hidl_string(defaultUrl)); - return Void(); - } - - CdmProvisioningRequest cdmProvisionRequest; - std::string cdmDefaultUrl; - - CdmCertificateType cdmCertType = wvcdm::kCertificateWidevine; - if (certificateType == "X.509") { - cdmCertType = wvcdm::kCertificateX509; - } - - std::string cdmCertAuthority = certificateAuthority; - - CdmResponseType res = mCDM->GetProvisioningRequest( - cdmCertType, cdmCertAuthority, identifier, - mProvisioningServiceCertificate, getRequestedSecurityLevel(), - &cdmProvisionRequest, &cdmDefaultUrl); - if (isCdmResponseTypeSuccess(res)) { - request = StrToVector(cdmProvisionRequest); - defaultUrl.clear(); - defaultUrl.assign(cdmDefaultUrl.data(), cdmDefaultUrl.size()); - } - - _hidl_cb(mapCdmResponseType(res), toHidlVec(request), - hidl_string(defaultUrl)); - return Void(); -} - -Return WVDrmPlugin::provideProvisionResponse( - const hidl_vec& response, provideProvisionResponse_cb _hidl_cb) { - if (!response.size()) { - _hidl_cb(Status::BAD_VALUE, hidl_vec(), hidl_vec()); - return Void(); - } - const std::vector resp = toVector(response); - std::vector certificate; - std::vector wrappedKey; - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, toHidlVec(certificate), toHidlVec(wrappedKey)); - } - - CdmProvisioningResponse cdmResponse(resp.begin(), resp.end()); - if (cdmResponse == kSpecialUnprovisionResponse) { - if (identifier.IsEquivalentToDefault()) { - ALOGW("Returns UNKNOWN error for legacy status kErrorNoOriginSpecified"); - _hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(certificate), - toHidlVec(wrappedKey)); - return Void(); - } - _hidl_cb(unprovision(identifier), toHidlVec(certificate), - toHidlVec(wrappedKey)); - return Void(); - } else { - std::string cdmCertificate; - std::string cdmWrappedKey; - CdmResponseType res = mCDM->HandleProvisioningResponse( - identifier, cdmResponse, getRequestedSecurityLevel(), &cdmCertificate, - &cdmWrappedKey); - if (isCdmResponseTypeSuccess(res)) { - certificate = StrToVector(cdmCertificate); - wrappedKey = StrToVector(cdmWrappedKey); - } - - _hidl_cb(mapCdmResponseType(res), toHidlVec(certificate), - toHidlVec(wrappedKey)); - return Void(); - } -} - -Status WVDrmPlugin::unprovisionDevice() { - return unprovision(kDefaultCdmIdentifier); -} - -Return WVDrmPlugin::getSecureStop(const hidl_vec& secureStopId, - getSecureStop_cb _hidl_cb) { - if (!secureStopId.size()) { - _hidl_cb(Status::BAD_VALUE, SecureStop()); - return Void(); - } - - const std::vector id = toVector(secureStopId); - std::vector cdmStopVec; - SecureStop secureStop; - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, secureStop); - return Void(); - } - - CdmUsageInfo cdmUsageInfo; - CdmSecureStopId cdmSsId(id.begin(), id.end()); - CdmResponseType res = mCDM->GetUsageInfo(mPropertySet.app_id(), cdmSsId, - identifier, &cdmUsageInfo); - - if (isCdmResponseTypeSuccess(res)) { - for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); - iter != cdmUsageInfo.end(); ++iter) { - const std::string& cdmStop = *iter; - cdmStopVec = StrToVector(cdmStop); - } - secureStop.opaqueData = toHidlVec(cdmStopVec); - } - - _hidl_cb(mapCdmResponseType(res), secureStop); - return Void(); -} - -Return WVDrmPlugin::getSecureStops(getSecureStops_cb _hidl_cb) { - std::list> secureStops; - std::vector secureStopsVec; - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, toHidlVec(secureStopsVec)); - return Void(); - } - - CdmUsageInfo cdmUsageInfo; - CdmResponseType res = - mCDM->GetUsageInfo(mPropertySet.app_id(), identifier, &cdmUsageInfo); - - if (isCdmResponseTypeSuccess(res)) { - secureStops.clear(); - for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); - iter != cdmUsageInfo.end(); ++iter) { - const std::string& cdmStop = *iter; - secureStops.push_back(StrToVector(cdmStop)); - } - } - - std::list>::iterator iter = secureStops.begin(); - while (iter != secureStops.end()) { - SecureStop secureStop; - secureStop.opaqueData = toHidlVec(*iter++); - secureStopsVec.push_back(secureStop); - } - - _hidl_cb(mapCdmResponseType(res), toHidlVec(secureStopsVec)); - return Void(); -} - -Return WVDrmPlugin::releaseAllSecureStops() { - return removeAllSecureStops(); -} - -Return WVDrmPlugin::releaseSecureStop( - const hidl_vec& secureStopId) { - if (!secureStopId.size()) { - return Status::BAD_VALUE; - } - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - return status; - } - - const std::vector ssRelease = toVector(secureStopId); - CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end()); - CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, identifier); - return mapCdmResponseType(res); -} - -Return WVDrmPlugin::getMetrics(getMetrics_cb _hidl_cb) { - hidl_vec hidl_metrics; - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, hidl_metrics); - return Void(); - } - - drm_metrics::WvCdmMetrics proto_metrics; - CdmResponseType result = mCDM->GetMetrics(identifier, &proto_metrics); - if (result != wvcdm::NO_ERROR) { - status = mapCdmResponseType(result); - _hidl_cb(status, hidl_metrics); - return Void(); - } - - ::wvcdm::HidlMetricsAdapter adapter; - ::wvcdm::HidlMetricsAdapter::ToHidlMetrics(proto_metrics, &hidl_metrics); - _hidl_cb(Status::OK, hidl_metrics); - return Void(); -} - -Return WVDrmPlugin::getSecureStopIds(getSecureStopIds_cb _hidl_cb) { - std::vector secureStopIds; - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, toHidlVec(secureStopIds)); - return Void(); - } - - std::vector ssids; - CdmResponseType res = - mCDM->GetSecureStopIds(mPropertySet.app_id(), identifier, &ssids); - - if (isCdmResponseTypeSuccess(res)) { - for (auto itr = ssids.begin(); itr != ssids.end(); ++itr) { - const CdmSecureStopId& ssid = *itr; - secureStopIds.push_back(StrToVector(ssid)); - } - } - - _hidl_cb(mapCdmResponseType(res), toHidlVec(secureStopIds)); - return Void(); -} - -Return WVDrmPlugin::releaseSecureStops( - const SecureStopRelease& ssRelease) { - if (ssRelease.opaqueData.size() == 0) { - return Status::BAD_VALUE; - } - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - return status; - } - - const std::vector data = toVector(ssRelease.opaqueData); - CdmUsageInfoReleaseMessage cdmMessage(data.begin(), data.end()); - CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage, identifier); - return mapCdmResponseType(res); -} - -Return WVDrmPlugin::removeSecureStop( - const hidl_vec& secureStopId) { - if (!secureStopId.size()) { - return Status::BAD_VALUE; - } - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - return status; - } - - const std::vector idVec = toVector(secureStopId); - CdmSecureStopId id(idVec.begin(), idVec.end()); - CdmResponseType res = - mCDM->RemoveUsageInfo(mPropertySet.app_id(), identifier, id); - return mapCdmResponseType(res); -} - -Return WVDrmPlugin::removeAllSecureStops() { - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - return status; - } - - CdmResponseType res = - mCDM->RemoveAllUsageInfo(mPropertySet.app_id(), identifier); - return mapCdmResponseType(res); -} - -Return WVDrmPlugin::getHdcpLevels(getHdcpLevels_cb _hidl_cb) { - HdcpLevel connectedLevel = HdcpLevel::HDCP_NONE; - HdcpLevel maxLevel = HdcpLevel::HDCP_NO_OUTPUT; - - Return hResult = getHdcpLevels_1_2([&](Status_V1_2 status, - const HdcpLevel_V1_2& hConnected, - const HdcpLevel_V1_2& hMax) { - if (status == Status_V1_2::OK) { - connectedLevel = toHdcpLevel_1_1(hConnected); - maxLevel = toHdcpLevel_1_1(hMax); - } - }); - - _hidl_cb(Status::OK, connectedLevel, maxLevel); - return Void(); -} - -Return WVDrmPlugin::getHdcpLevels_1_2(getHdcpLevels_1_2_cb _hidl_cb) { - HdcpLevel_V1_2 connectedLevel = HdcpLevel_V1_2::HDCP_NONE; - HdcpLevel_V1_2 maxLevel = HdcpLevel_V1_2::HDCP_NO_OUTPUT; - - std::string level; - Status status = queryProperty(wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL, level); - if (status == Status::OK) { - connectedLevel = mapHdcpLevel_1_2(level); - } else { - ALOGE("Failed to query current hdcp level."); - _hidl_cb(Status_V1_2::ERROR_DRM_INVALID_STATE, connectedLevel, maxLevel); - return Void(); - } - - status = queryProperty(wvcdm::QUERY_KEY_MAX_HDCP_LEVEL, level); - if (status == Status::OK) { - maxLevel = mapHdcpLevel_1_2(level); - } else { - ALOGE("Failed to query maximum hdcp level."); - _hidl_cb(Status_V1_2::ERROR_DRM_INVALID_STATE, connectedLevel, maxLevel); - return Void(); - } - - _hidl_cb(Status_V1_2::OK, connectedLevel, maxLevel); - return Void(); -} - -Return WVDrmPlugin::getNumberOfSessions(getNumberOfSessions_cb _hidl_cb) { - uint32_t currentSessions = 0; - uint32_t maxSessions = 1; - - std::string value; - Status status = - queryProperty(wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, value); - if (status == Status::OK) { - currentSessions = std::strtoul(value.c_str(), nullptr, 10); - } else { - ALOGE("Failed to query currently opened sessions."); - _hidl_cb(Status::ERROR_DRM_INVALID_STATE, currentSessions, maxSessions); - return Void(); - } - - status = queryProperty(wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS, value); - if (status == Status::OK) { - maxSessions = std::strtoul(value.c_str(), nullptr, 10); - } else { - ALOGE( - "Failed to query maximum number of sessions that the device can " - "support."); - _hidl_cb(Status::ERROR_DRM_INVALID_STATE, currentSessions, maxSessions); - return Void(); - } - - _hidl_cb(Status::OK, currentSessions, maxSessions); - return Void(); -} - -Return WVDrmPlugin::getSecurityLevel(const hidl_vec& sessionId, - getSecurityLevel_cb _hidl_cb) { - if (sessionId.size() == 0) { - _hidl_cb(Status::BAD_VALUE, SecurityLevel::UNKNOWN); - return Void(); - } - - std::vector sid = toVector(sessionId); - CdmQueryMap info; - SecurityLevel hSecurityLevel = SecurityLevel::UNKNOWN; - - CdmResponseType status = - mCDM->QuerySessionStatus(std::string(sid.begin(), sid.end()), &info); - if (wvcdm::NO_ERROR == status) { - std::string level = info[wvcdm::QUERY_KEY_SECURITY_LEVEL]; - hSecurityLevel = mapSecurityLevel(level); - } else { - ALOGE("Failed to query security level, status=%d", status); - } - - _hidl_cb(mapCdmResponseType(status), hSecurityLevel); - return Void(); -} - -Return WVDrmPlugin::getOfflineLicenseKeySetIds( - getOfflineLicenseKeySetIds_cb _hidl_cb) { - std::vector> keySetIds; - std::vector keySetIdsVec; - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, toHidlVec(keySetIdsVec)); - return Void(); - } - - std::vector levels = {wvcdm::kSecurityLevelL1, - wvcdm::kSecurityLevelL3}; - - CdmResponseType res = wvcdm::UNKNOWN_ERROR; - - for (auto level : levels) { - std::vector cdmKeySetIds; - res = mCDM->ListStoredLicenses(level, identifier, &cdmKeySetIds); - - if (isCdmResponseTypeSuccess(res)) { - keySetIds.clear(); - for (auto id : cdmKeySetIds) { - keySetIds.push_back(StrToVector(id)); - } - for (auto id : keySetIds) { - keySetIdsVec.push_back(id); - } - } - } - _hidl_cb(mapCdmResponseType(res), toHidlVec(keySetIdsVec)); - return Void(); -} - -Return WVDrmPlugin::getOfflineLicenseState( - const KeySetId& keySetId, getOfflineLicenseState_cb _hidl_cb) { - OfflineLicenseState licenseState = OfflineLicenseState::UNKNOWN; - - if (!keySetId.size()) { - _hidl_cb(Status::BAD_VALUE, licenseState); - return Void(); - } - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - _hidl_cb(status, licenseState); - return Void(); - } - - CdmResponseType res = wvcdm::UNKNOWN_ERROR; - CdmKeySetId keySetIdStr(keySetId.begin(), keySetId.end()); - - wvcdm::CdmOfflineLicenseState state = wvcdm::kLicenseStateUnknown; - res = mCDM->GetOfflineLicenseState(keySetIdStr, wvcdm::kSecurityLevelL1, - identifier, &state); - if (!isCdmResponseTypeSuccess(res)) { - // try L3 - res = mCDM->GetOfflineLicenseState(keySetIdStr, wvcdm::kSecurityLevelL3, - identifier, &state); - if (!isCdmResponseTypeSuccess(res)) { - _hidl_cb(Status::BAD_VALUE, licenseState); - return Void(); - } - } - - switch (state) { - case wvcdm::kLicenseStateActive: - licenseState = OfflineLicenseState::USABLE; - break; - case wvcdm::kLicenseStateReleasing: - licenseState = OfflineLicenseState::INACTIVE; - break; - default: - licenseState = OfflineLicenseState::UNKNOWN; - ALOGE("Return unknown offline license state for %s", keySetIdStr.c_str()); - break; - } - - _hidl_cb(mapCdmResponseType(res), licenseState); - return Void(); -} - -Return WVDrmPlugin::removeOfflineLicense(const KeySetId& keySetId) { - if (!keySetId.size()) { - return Status::BAD_VALUE; - } - - CdmIdentifier identifier; - Status status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - return status; - } - - CdmResponseType res = wvcdm::UNKNOWN_ERROR; - - res = - mCDM->RemoveOfflineLicense(std::string(keySetId.begin(), keySetId.end()), - wvcdm::kSecurityLevelL1, identifier); - if (!isCdmResponseTypeSuccess(res)) { - CdmResponseType res = mCDM->RemoveOfflineLicense( - std::string(keySetId.begin(), keySetId.end()), wvcdm::kSecurityLevelL3, - identifier); - status = mapCdmResponseType(res); - } - - return status; -} - -Return WVDrmPlugin::getPropertyString(const hidl_string& propertyName, - getPropertyString_cb _hidl_cb) { - Status status = Status::OK; - std::string name(propertyName.c_str()); - std::string value; - - if (name == "vendor") { - value = "Google"; - } else if (name == "version") { - status = queryProperty(wvcdm::QUERY_KEY_WVCDM_VERSION, value); - } else if (name == "description") { - value = "Widevine CDM"; - } else if (name == "algorithms") { - value = "AES/CBC/NoPadding,HmacSHA256"; - } else if (name == "securityLevel") { - std::string requestedLevel = mPropertySet.security_level(); - - if (requestedLevel.length() > 0) { - value = requestedLevel.c_str(); - } else { - status = queryProperty(wvcdm::QUERY_KEY_SECURITY_LEVEL, value); - } - } else if (name == "systemId") { - status = queryProperty(wvcdm::QUERY_KEY_SYSTEM_ID, value); - } else if (name == "privacyMode") { - if (mPropertySet.use_privacy_mode()) { - value = kEnable; - } else { - value = kDisable; - } - } else if (name == "sessionSharing") { - if (mPropertySet.is_session_sharing_enabled()) { - value = kEnable; - } else { - value = kDisable; - } - } else if (name == "hdcpLevel") { - status = queryProperty(wvcdm::QUERY_KEY_CURRENT_HDCP_LEVEL, value); - } else if (name == "maxHdcpLevel") { - status = queryProperty(wvcdm::QUERY_KEY_MAX_HDCP_LEVEL, value); - } else if (name == "usageReportingSupport") { - status = queryProperty(wvcdm::QUERY_KEY_USAGE_SUPPORT, value); - } else if (name == "numberOfOpenSessions") { - status = queryProperty(wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, value); - } else if (name == "maxNumberOfSessions") { - status = queryProperty(wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS, value); - } else if (name == "oemCryptoApiVersion") { - status = queryProperty(wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION, value); - } else if (name == "appId") { - value = mPropertySet.app_id().c_str(); - } else if (name == "origin") { - value = mCdmIdentifierBuilder.origin().c_str(); - } else if (name == "CurrentSRMVersion") { - status = queryProperty(wvcdm::QUERY_KEY_CURRENT_SRM_VERSION, value); - } else if (name == "SRMUpdateSupport") { - status = queryProperty(wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT, value); - } else if (name == "resourceRatingTier") { - status = queryProperty(wvcdm::QUERY_KEY_RESOURCE_RATING_TIER, value); - } else if (name == "oemCryptoBuildInformation") { - status = queryProperty(wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, value); - } else if (name == "decryptHashSupport") { - status = queryProperty(wvcdm::QUERY_KEY_DECRYPT_HASH_SUPPORT, value); - } else if (name == "decryptHashError") { - status = mapCdmResponseType( - mCDM->GetDecryptHashError(mDecryptHashSessionId, &value)); - } else if (name == "maxUsageEntriesSupported") { - status = queryProperty(wvcdm::QUERY_KEY_MAX_USAGE_TABLE_ENTRIES, value); - } else if (name == "oemCryptoApiMinorVersion") { - status = queryProperty(wvcdm::QUERY_KEY_OEMCRYPTO_API_MINOR_VERSION, value); - } else if (name == "analogOutputCapabilities") { - status = queryProperty(wvcdm::QUERY_KEY_ANALOG_OUTPUT_CAPABILITIES, value); - } else if (name == "canDisableAnalogOutput") { - status = queryProperty(wvcdm::QUERY_KEY_CAN_DISABLE_ANALOG_OUTPUT, value); - } else if (name == "atscMode") { - if (mPropertySet.use_atsc_mode()) { - value = kEnable; - } else { - value = kDisable; - } - } else if (name == "watermarkingSupport") { - status = queryProperty(wvcdm::QUERY_KEY_WATERMARKING_SUPPORT, value); - } else if (name == "productionReady") { - status = queryProperty(wvcdm::QUERY_KEY_PRODUCTION_READY, value); - } else if (name == "provisioningModel") { - status = queryProperty(wvcdm::QUERY_KEY_PROVISIONING_MODEL, value); - } else { - ALOGE("App requested unknown string property %s", name.c_str()); - status = Status::ERROR_DRM_CANNOT_HANDLE; - } - - _hidl_cb(status, value.c_str()); - return Void(); -} - -Return WVDrmPlugin::getPropertyByteArray( - const hidl_string& propertyName, getPropertyByteArray_cb _hidl_cb) { - Status status = Status::OK; - std::string name(propertyName.c_str()); - std::vector value; - - if (name == "deviceUniqueId") { - std::string id; - status = mCdmIdentifierBuilder.getDeviceUniqueId(&id); - if (status == Status::OK) { - value = StrToVector(id); - } - } else if (name == "provisioningUniqueId") { - std::string id; - status = mCdmIdentifierBuilder.getProvisioningUniqueId(&id); - if (status == Status::OK) { - value = StrToVector(id); - } - } else if (name == "serviceCertificate") { - value = StrToVector(mPropertySet.service_certificate()); - } else if (name == "provisioningServiceCertificate") { - value = StrToVector(mProvisioningServiceCertificate); - } else if (name == "metrics") { - drm_metrics::WvCdmMetrics metrics; - // If the cdm identifier is not yet sealed, then there are no metrics - // for that cdm engine. Avoid calling getCdmIdentifier and sealing - // the identifier builder. - if (mCdmIdentifierBuilder.is_sealed()) { - CdmIdentifier identifier; - status = mCdmIdentifierBuilder.getCdmIdentifier(&identifier); - if (status != Status::OK) { - ALOGE("Unexpected error retrieving cdm identifier: %d", status); - } else { - status = mapCdmResponseType(mCDM->GetMetrics(identifier, &metrics)); - } - } - if (status == Status::OK) { - std::string serialized_metrics; - if (!metrics.SerializeToString(&serialized_metrics)) { - status = Status::ERROR_DRM_UNKNOWN; - } else { - value = StrToVector(serialized_metrics); - } - } - } else { - ALOGE("App requested unknown byte array property %s", name.c_str()); - status = Status::ERROR_DRM_CANNOT_HANDLE; - } - - _hidl_cb(status, toHidlVec(value)); - return Void(); -} - -Return WVDrmPlugin::setPropertyString(const hidl_string& propertyName, - const hidl_string& value) { - std::string name(propertyName.c_str()); - std::string _value(value.c_str()); - - if (name == "securityLevel") { - if (mCryptoSessions.size() == 0) { - if (_value == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) { - mPropertySet.set_security_level(wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3); - } else if (_value == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1.c_str()) { - // We must be sure we CAN set the security level to L1. - std::string current_security_level; - Status status = - queryProperty(wvcdm::kLevelDefault, wvcdm::QUERY_KEY_SECURITY_LEVEL, - current_security_level); - if (status != Status::OK) { - return status; - } - if (current_security_level != wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1) { - ALOGE("App requested L1 security on a non-L1 device."); - return Status::BAD_VALUE; - } else { - mPropertySet.set_security_level(kResetSecurityLevel); - } - } else if (_value == kResetSecurityLevel || - _value == wvcdm::QUERY_VALUE_SECURITY_LEVEL_DEFAULT) { - mPropertySet.set_security_level(kResetSecurityLevel); - } else { - ALOGE("App requested invalid security level %s", _value.c_str()); - return Status::BAD_VALUE; - } - } else { - ALOGE("App tried to change security level while sessions are open."); - ALOGW("Returns UNKNOWN error for legacy status kErrorSessionIsOpen"); - return Status::ERROR_DRM_UNKNOWN; - } - } else if (name == "privacyMode") { - if (_value == kEnable) { - mPropertySet.set_use_privacy_mode(true); - } else if (_value == kDisable) { - mPropertySet.set_use_privacy_mode(false); - } else { - ALOGE("App requested unknown privacy mode %s", _value.c_str()); - return Status::BAD_VALUE; - } - } else if (name == "sessionSharing") { - if (mCryptoSessions.size() == 0) { - if (_value == kEnable) { - mPropertySet.set_is_session_sharing_enabled(true); - } else if (_value == kDisable) { - mPropertySet.set_is_session_sharing_enabled(false); - } else { - ALOGE("App requested unknown sharing type %s", _value.c_str()); - return Status::BAD_VALUE; - } - } else { - ALOGE("App tried to change key sharing while sessions are open."); - ALOGW("Returns UNKNOWN error for legacy status kErrorSessionIsOpen"); - return Status::ERROR_DRM_UNKNOWN; - } - } else if (name == "appId") { - if (mCryptoSessions.size() == 0) { - mPropertySet.set_app_id(_value.c_str()); - } else { - ALOGE("App tried to set the application id while sessions are opened."); - ALOGW("Returns UNKNOWN error for legacy status kErrorSessionIsOpen"); - return Status::ERROR_DRM_UNKNOWN; - } - } else if (name == "origin") { - if (mCryptoSessions.size() != 0) { - ALOGE("App tried to set the origin while sessions are opened."); - ALOGW("Returns UNKNOWN error for legacy status kErrorSessionIsOpen"); - return Status::ERROR_DRM_UNKNOWN; - } else { - if (!mCdmIdentifierBuilder.set_origin(_value.c_str())) { - return Status::BAD_VALUE; - } - } - } else if (name == "debugIgnoreKeyboxCount") { - std::istringstream ss(_value); - uint32_t count = 0; - ss >> count; - if (ss.fail()) { - ALOGE("Could not parse an integer from '%s'", _value.c_str()); - count = 0; - return Status::BAD_VALUE; - } - CdmResponseType res = mCDM->SetDebugIgnoreKeyboxCount(count); - return mapCdmResponseType(res); - } else if (name == "allowTestKeybox") { - bool allow; - if (_value == kEnable) { - allow = true; - } else if (_value == kDisable) { - allow = false; - } else { - ALOGE("App requested unknown allowTestKeybox %s", _value.c_str()); - return Status::BAD_VALUE; - } - CdmResponseType res = mCDM->SetAllowTestKeybox(allow); - return mapCdmResponseType(res); - } else if (name == "decryptHash") { - wvcdm::CdmSessionId sessionId; - CdmResponseType res = mCDM->SetDecryptHash(_value.c_str(), &sessionId); - - if (wvcdm::NO_ERROR == res) mDecryptHashSessionId = sessionId; - - return mapCdmResponseType(res); - } else if (name == "decryptHashSessionId") { - mDecryptHashSessionId = _value.c_str(); - } else if (name == "atscMode") { - if (_value == kEnable) { - if (!mCdmIdentifierBuilder.set_use_atsc_mode(true)) { - ALOGE("Cdm identifier builder is sealed. Setting ATSC mode prohibited"); - return Status::BAD_VALUE; - } - mPropertySet.set_use_atsc_mode(true); - } else if (_value == kDisable) { - if (!mCdmIdentifierBuilder.set_use_atsc_mode(false)) { - ALOGE("Cdm identifier builder is sealed. Setting ATSC mode prohibited"); - return Status::BAD_VALUE; - } - mPropertySet.set_use_atsc_mode(false); - } else { - ALOGE("App requested unknown ATSC mode %s", _value.c_str()); - return Status::BAD_VALUE; - } - } else if (name == "debugOtaKeyboxFallbackDuration") { - bool success = false; - if (value == "default") { - success = mCDM->SetDefaultOtaKeyboxFallbackDurationRules(); - } else if (value == "fast") { - success = mCDM->SetFastOtaKeyboxFallbackDurationRules(); - } else { - ALOGE("Unknown OTA fallback duration value %s", _value.c_str()); - return Status::BAD_VALUE; - } - if (!success) { - return Status::ERROR_DRM_UNKNOWN; - } - } else { - ALOGE("App set unknown string property %s", name.c_str()); - return Status::ERROR_DRM_CANNOT_HANDLE; - } - - return Status::OK; -} - -Return WVDrmPlugin::setPropertyByteArray( - const hidl_string& propertyName, const hidl_vec& value) { - std::string name(propertyName.c_str()); - std::vector _value = toVector(value); - - if (name == "serviceCertificate") { - std::string cert(_value.begin(), _value.end()); - if (_value.empty() || mCDM->IsValidServiceCertificate(cert)) { - mPropertySet.set_service_certificate(cert); - } else { - return Status::BAD_VALUE; - } - } else if (name == "provisioningServiceCertificate") { - std::string cert(_value.begin(), _value.end()); - if (_value.empty() || mCDM->IsValidServiceCertificate(cert)) { - mProvisioningServiceCertificate = cert; - } else { - return Status::BAD_VALUE; - } - } else { - ALOGE("App set unknown byte array property %s", name.c_str()); - return Status::ERROR_DRM_CANNOT_HANDLE; - } - - return Status::OK; -} - -Return WVDrmPlugin::setCipherAlgorithm( - const hidl_vec& sessionId, const hidl_string& algorithm) { - if (sessionId.size() == 0 || algorithm.size() == 0) { - return Status::BAD_VALUE; - } - std::string algo(algorithm.c_str()); - std::vector sId = toVector(sessionId); - - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return Status::ERROR_DRM_SESSION_NOT_OPENED; - } - - CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (algo == "AES/CBC/NoPadding") { - cryptoSession.setCipherAlgorithm(OEMCrypto_AES_CBC_128_NO_PADDING); - } else { - return Status::ERROR_DRM_CANNOT_HANDLE; - } - - return Status::OK; -} - -Return WVDrmPlugin::setMacAlgorithm(const hidl_vec& sessionId, - const hidl_string& algorithm) { - if (sessionId.size() == 0 || algorithm.size() == 0) { - return Status::BAD_VALUE; - } - std::string algo(algorithm.c_str()); - std::vector sId = toVector(sessionId); - - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - return Status::ERROR_DRM_SESSION_NOT_OPENED; - } - - CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (algo == "HmacSHA256") { - cryptoSession.setMacAlgorithm(OEMCrypto_HMAC_SHA256); - } else { - return Status::ERROR_DRM_CANNOT_HANDLE; - } - - return Status::OK; -} - -Return WVDrmPlugin::encrypt(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& input, - const hidl_vec& iv, - encrypt_cb _hidl_cb) { - const std::vector sId = toVector(sessionId); - std::vector output; - - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, toHidlVec(output)); - return Void(); - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) { - ALOGW("Returns UNKNOWN error for legacy status NO_INIT"); - _hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(output)); - return Void(); - } - - const std::vector _keyId = toVector(keyId); - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - _keyId.data(), _keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(output)); - return Void(); - } - - const std::vector _input = toVector(input); - const std::vector _iv = toVector(iv); - output.resize(_input.size()); - - res = mCrypto->encrypt(cryptoSession.oecSessionId(), _input.data(), - _input.size(), _iv.data(), - cryptoSession.cipherAlgorithm(), output.data()); - - if (res == OEMCrypto_SUCCESS) { - _hidl_cb(Status::OK, toHidlVec(output)); - } else { - ALOGE("OEMCrypto_Generic_Encrypt failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(output)); - } - return Void(); -} - -Return WVDrmPlugin::decrypt(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& input, - const hidl_vec& iv, - decrypt_cb _hidl_cb) { - const std::vector sId = toVector(sessionId); - std::vector output; - - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, toHidlVec(output)); - return Void(); - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.cipherAlgorithm() == kInvalidCryptoAlgorithm) { - ALOGW("Returns UNKNOWN error for legacy status NO_INIT"); - _hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(output)); - return Void(); - } - - const std::vector _keyId = toVector(keyId); - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - _keyId.data(), _keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(output)); - return Void(); - } - - const std::vector _input = toVector(input); - const std::vector _iv = toVector(iv); - output.resize(_input.size()); - - res = mCrypto->decrypt(cryptoSession.oecSessionId(), _input.data(), - _input.size(), _iv.data(), - cryptoSession.cipherAlgorithm(), output.data()); - - if (res == OEMCrypto_SUCCESS) { - _hidl_cb(Status::OK, toHidlVec(output)); - } else { - ALOGE("OEMCrypto_Generic_Decrypt failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(output)); - } - return Void(); -} - -Return WVDrmPlugin::sign(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& message, - sign_cb _hidl_cb) { - const std::vector sId = toVector(sessionId); - std::vector signature; - - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, toHidlVec(signature)); - return Void(); - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) { - ALOGW("Returns UNKNOWN error for legacy status NO_INIT"); - _hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(signature)); - return Void(); - } - - const std::vector _keyId = toVector(keyId); - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - _keyId.data(), _keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(signature)); - return Void(); - } - - size_t signatureSize = 0; - - const std::vector msg = toVector(message); - res = mCrypto->sign(cryptoSession.oecSessionId(), msg.data(), msg.size(), - cryptoSession.macAlgorithm(), NULL, &signatureSize); - - if (res != OEMCrypto_ERROR_SHORT_BUFFER) { - ALOGE( - "OEMCrypto_Generic_Sign failed with %u when requesting signature " - "size", - res); - if (res != OEMCrypto_SUCCESS) { - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(signature)); - } else { - _hidl_cb(Status::ERROR_DRM_UNKNOWN, toHidlVec(signature)); - } - return Void(); - } - - signature.resize(signatureSize); - - res = mCrypto->sign(cryptoSession.oecSessionId(), msg.data(), msg.size(), - cryptoSession.macAlgorithm(), signature.data(), - &signatureSize); - - if (res == OEMCrypto_SUCCESS) { - _hidl_cb(Status::OK, toHidlVec(signature)); - } else { - ALOGE("OEMCrypto_Generic_Sign failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), toHidlVec(signature)); - } - return Void(); -} - -Return WVDrmPlugin::verify(const hidl_vec& sessionId, - const hidl_vec& keyId, - const hidl_vec& message, - const hidl_vec& signature, - verify_cb _hidl_cb) { - bool match = false; - const std::vector sId = toVector(sessionId); - - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - if (!mCryptoSessions.count(cdmSessionId)) { - _hidl_cb(Status::ERROR_DRM_SESSION_NOT_OPENED, match); - return Void(); - } - - const CryptoSession& cryptoSession = mCryptoSessions[cdmSessionId]; - - if (cryptoSession.macAlgorithm() == kInvalidCryptoAlgorithm) { - ALOGW("Returns UNKNOWN error for legacy status NO_INIT"); - _hidl_cb(Status::ERROR_DRM_UNKNOWN, match); - return Void(); - } - - const std::vector _keyId = toVector(keyId); - OEMCryptoResult res = mCrypto->selectKey(cryptoSession.oecSessionId(), - _keyId.data(), _keyId.size()); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_SelectKey failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), match); - return Void(); - } - - const std::vector _message = toVector(message); - const std::vector _signature = toVector(signature); - res = mCrypto->verify(cryptoSession.oecSessionId(), _message.data(), - _message.size(), cryptoSession.macAlgorithm(), - _signature.data(), _signature.size()); - - if (res == OEMCrypto_SUCCESS) { - match = true; - _hidl_cb(Status::OK, match); - } else if (res == OEMCrypto_ERROR_SIGNATURE_FAILURE) { - match = false; - _hidl_cb(Status::OK, match); - } else { - ALOGE("OEMCrypto_Generic_Verify failed with %u", res); - _hidl_cb(mapAndNotifyOfOEMCryptoResult(sId, res), match); - } - return Void(); -} - -Return WVDrmPlugin::signRSA(const hidl_vec& sessionId, - const hidl_string& algorithm, - const hidl_vec& message, - const hidl_vec& wrappedKey, - signRSA_cb _hidl_cb) { - if (sessionId.size() == 0 || algorithm.size() == 0 || message.size() == 0 || - wrappedKey.size() == 0) { - _hidl_cb(Status::BAD_VALUE, hidl_vec()); - return Void(); - } - - const auto& self = android::hardware::IPCThreadState::self(); - const char* sid = self->getCallingSid(); - if (!sid || - (!strstr(sid, ":mediashell_app:") && !strstr(sid, ":mediadrmserver:") && - !strstr(sid, ":setupwraith_app:"))) { - ALOGE( - "Only mediashell/mediadrmserver/setupwraith_app can call signRSA, " - "but actually: %s", - sid); - _hidl_cb(Status::ERROR_DRM_UNKNOWN, hidl_vec()); - return Void(); - } - - const std::string algo(algorithm.c_str()); - std::vector signature; - - RSA_Padding_Scheme padding_scheme; - if (algo == "RSASSA-PSS-SHA1") { - padding_scheme = kSign_RSASSA_PSS; - } else if (algo == "PKCS1-BlockType1") { - padding_scheme = kSign_PKCS1_Block1; - } else { - ALOGE("Unknown RSA Algorithm %s", algo.c_str()); - _hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, toHidlVec(signature)); - return Void(); - } - - const std::vector msg = toVector(message); - const std::vector _wrappedKey = toVector(wrappedKey); - OEMCryptoResult res = - mCrypto->signRSA(_wrappedKey.data(), _wrappedKey.size(), msg.data(), - msg.size(), signature, padding_scheme); - - if (res != OEMCrypto_SUCCESS) { - ALOGE("OEMCrypto_GenerateRSASignature failed with %u", res); - _hidl_cb(mapOEMCryptoResult(res), toHidlVec(signature)); - return Void(); - } - - _hidl_cb(Status::OK, toHidlVec(signature)); - return Void(); -} - -Return WVDrmPlugin::setListener(const sp& listener) { - mListener = listener; - mListenerV1_2 = IDrmPluginListener_V1_2::castFrom(listener); - return Void(); -} - -Return WVDrmPlugin::sendEvent(EventType eventType, - const hidl_vec& sessionId, - const hidl_vec& data) { - Return err{}; - if (mListenerV1_2 != NULL) { - err = mListenerV1_2->sendEvent(eventType, sessionId, data); - } else if (mListener != NULL) { - err = mListener->sendEvent(eventType, sessionId, data); - } else { - ALOGE("Null event listener, event not sent"); - } - if (!err.isOk()) { - ALOGW("sendEvent failed %s", err.description().c_str()); - } - return err; -} - -Return WVDrmPlugin::sendExpirationUpdate( - const hidl_vec& sessionId, int64_t expiryTimeInMS) { - Return err{}; - if (mListenerV1_2 != NULL) { - err = mListenerV1_2->sendExpirationUpdate(sessionId, expiryTimeInMS); - } else if (mListener != NULL) { - err = mListener->sendExpirationUpdate(sessionId, expiryTimeInMS); - } else { - ALOGE("Null event listener, event not sent"); - } - if (!err.isOk()) { - ALOGW("sendExpirationUpdate failed %s", err.description().c_str()); - } - return err; -} - -template <> -void WVDrmPlugin::_sendKeysChange(const hidl_vec& sessionId, - const hidl_vec& keyStatusList, - bool hasNewUsableKey) { - auto err = - mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey); - if (!err.isOk()) { - ALOGW("sendKeysChange failed %s", err.description().c_str()); - } -} - -template <> -void WVDrmPlugin::_sendKeysChange(const hidl_vec& sessionId, - const hidl_vec& keyStatusList, - bool hasNewUsableKey) { - auto err = mListenerV1_2->sendKeysChange_1_2(sessionId, keyStatusList, - hasNewUsableKey); - if (!err.isOk()) { - ALOGW("sendKeysChange_1_2 failed %s", err.description().c_str()); - } -} - -Return WVDrmPlugin::sendKeysChange( - const hidl_vec& sessionId, - const hidl_vec& keyStatusList, bool hasNewUsableKey) { - Return err{}; - if (mListenerV1_2 != NULL) { - err = mListenerV1_2->sendKeysChange(sessionId, keyStatusList, - hasNewUsableKey); - } else if (mListener != NULL) { - err = mListener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey); - } else { - ALOGE("Null event listener, event not sent"); - } - if (!err.isOk()) { - ALOGW("sendKeysChange failed %s", err.description().c_str()); - } - return err; -} - -Return WVDrmPlugin::sendKeysChange_1_2( - const hidl_vec& sessionId, - const hidl_vec& keyStatusList, bool hasNewUsableKey) { - Return err{}; - if (mListenerV1_2 != NULL) { - err = mListenerV1_2->sendKeysChange_1_2(sessionId, keyStatusList, - hasNewUsableKey); - } else { - ALOGE("Null event listener, event not sent"); - } - if (!err.isOk()) { - ALOGW("sendKeysChange_1_2 failed %s", err.description().c_str()); - } - return err; -} - -Return WVDrmPlugin::sendSessionLostState( - const hidl_vec& sessionId) { - Return err{}; - if (mListenerV1_2 != NULL) { - err = mListenerV1_2->sendSessionLostState(sessionId); - } else { - ALOGE("Null event listener, event not sent"); - } - if (!err.isOk()) { - ALOGW("sendSessionLostState failed %s", err.description().c_str()); - } - return err; -} - -Return WVDrmPlugin::getLogMessages(getLogMessages_cb _hidl_cb) { - const std::vector &logs(wvutil::g_logbuf.getLogs()); - _hidl_cb(::drm::V1_4::Status::OK, toHidlVec<::drm::V1_4::LogMessage>(logs)); - return Void(); -} - -Return WVDrmPlugin::requiresSecureDecoder(const hidl_string& mime, - SecurityLevel level) { - if (!strncasecmp(mime.c_str(), "video/", 6)) { - // Type is video, so check level to see if we require a secure decoder. - return level == SecurityLevel::HW_SECURE_ALL || - level == SecurityLevel::HW_SECURE_DECODE; - } else { - // Type is not video, so never require a secure decoder. - return false; - } -} - -Return WVDrmPlugin::requiresSecureDecoderDefault( - const hidl_string& mime) { - if (!strncasecmp(mime.c_str(), "video/", 6)) { - // Type is video, so check level to see if we require a secure decoder. - std::string level(mPropertySet.security_level()); - - if (level == kResetSecurityLevel) { - mCDM->QueryStatus(wvcdm::kLevelDefault, wvcdm::QUERY_KEY_SECURITY_LEVEL, - &level); - } - - return level == wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1; - } else { - // Type is not video, so never require a secure decoder. - return false; - } -} - -Return<::drm::V1_0::Status> WVDrmPlugin::setPlaybackId( - const hidl_vec& sessionId, const hidl_string& playbackId) { - const std::vector sId = toVector(sessionId); - CdmSessionId cdmSessionId(sId.begin(), sId.end()); - std::string cdmPlaybackId = playbackId; - CdmResponseType res = mCDM->SetPlaybackId(cdmSessionId, cdmPlaybackId); - return mapCdmResponseType(res); -} - -void WVDrmPlugin::OnSessionRenewalNeeded(const CdmSessionId& cdmSessionId) { - const std::vector sessionId = StrToVector(cdmSessionId); - const hidl_vec data; // data is ignored - const hidl_vec sid = toHidlVec(sessionId); - sendEvent(EventType::KEY_NEEDED, sid, data); -} - -void WVDrmPlugin::OnSessionKeysChange(const CdmSessionId& cdmSessionId, - const CdmKeyStatusMap& cdmKeysStatus, - bool hasNewUsableKey) { - if (mListenerV1_2 != NULL) { - _OnSessionKeysChange(cdmSessionId, cdmKeysStatus, - hasNewUsableKey); - } else if (mListener != NULL) { - _OnSessionKeysChange(cdmSessionId, cdmKeysStatus, - hasNewUsableKey); - } else { - ALOGE("Null event listener, event not sent"); - } -} - -template -void WVDrmPlugin::_OnSessionKeysChange(const CdmSessionId& cdmSessionId, - const CdmKeyStatusMap& cdmKeysStatus, - bool hasNewUsableKey) { - bool expired = false; - std::vector keyStatusList; - for (CdmKeyStatusMap::const_iterator it = cdmKeysStatus.begin(); - it != cdmKeysStatus.end(); ++it) { - const KeyId& keyId = it->first; - const CdmKeyStatus cdmKeyStatus = it->second; - if (cdmKeyStatus == wvcdm::kKeyStatusExpired) expired = true; - - KS keyStatus; - keyStatus.keyId = toHidlVec(StrToVector(keyId)); - keyStatus.type = - ConvertFromCdmKeyStatus(cdmKeyStatus); - keyStatusList.push_back(keyStatus); - } - - const std::vector sessionId = StrToVector(cdmSessionId); - const hidl_vec data; // data is ignored - const hidl_vec sid = toHidlVec(sessionId); - _sendKeysChange(sid, toHidlVec(keyStatusList), hasNewUsableKey); - // For backward compatibility. - if (expired) { - sendEvent(EventType::KEY_EXPIRED, sid, data); - } -} - -void WVDrmPlugin::OnExpirationUpdate(const CdmSessionId& cdmSessionId, - int64_t newExpiryTimeSeconds) { - const std::vector sessionId = StrToVector(cdmSessionId); - int64_t newExpiryTimeMilliseconds = - newExpiryTimeSeconds == wvcdm::NEVER_EXPIRES - ? newExpiryTimeSeconds - : newExpiryTimeSeconds * 1000; - - sendExpirationUpdate(toHidlVec(sessionId), newExpiryTimeMilliseconds); -} - -void WVDrmPlugin::OnSessionLostState(const CdmSessionId& cdmSessionId) { - const std::vector sessionId = StrToVector(cdmSessionId); - sendSessionLostState(toHidlVec(sessionId)); -} - -Status WVDrmPlugin::queryProperty(const std::string& property, - std::string& stringValue) const { - return queryProperty(getRequestedSecurityLevel(), property, stringValue); -} - -Status WVDrmPlugin::queryProperty(wvcdm::RequestedSecurityLevel securityLevel, - const std::string& property, - std::string& stringValue) const { - CdmResponseType res = - mCDM->QueryStatus(securityLevel, property, &stringValue); - - if (res != wvcdm::NO_ERROR) { - ALOGE("Error querying CDM status: %u", res); - } - return mapCdmResponseType(res); -} - -Status WVDrmPlugin::queryProperty(const std::string& property, - std::vector& vector_value) const { - std::string string_value; - Status status = queryProperty(property, string_value); - if (status != Status::OK) return status; - vector_value = StrToVector(string_value); - return Status::OK; -} - -bool WVDrmPlugin::isProvisioned(wvcdm::CdmSecurityLevel securityLevel, - const std::string& origin, - const std::string& spoid, - bool atsc_mode_enabled) const { - return mCDM->IsProvisioned(securityLevel, origin, spoid, atsc_mode_enabled); -} - -Status WVDrmPlugin::mapAndNotifyOfCdmResponseType( - const std::vector& sessionId, CdmResponseType res) { - notifyOfCdmResponseType(sessionId, res); - return mapCdmResponseType(res); -} - -Status_V1_2 WVDrmPlugin::mapAndNotifyOfCdmResponseType_1_2( - const std::vector& sessionId, CdmResponseType res) { - notifyOfCdmResponseType(sessionId, res); - return mapCdmResponseType(res); -} - -void WVDrmPlugin::notifyOfCdmResponseType(const std::vector& sessionId, - CdmResponseType res) { - const hidl_vec data; // data is ignored - if (res == wvcdm::NEED_PROVISIONING) { - sendEvent(EventType::PROVISION_REQUIRED, toHidlVec(sessionId), data); - } else if (res == wvcdm::NEED_KEY) { - sendEvent(EventType::KEY_NEEDED, toHidlVec(sessionId), data); - } -} - -Status WVDrmPlugin::mapAndNotifyOfOEMCryptoResult( - const std::vector& sessionId, OEMCryptoResult res) { - const hidl_vec data; // data is ignored - if (res == OEMCrypto_ERROR_NO_DEVICE_KEY) { - sendEvent(EventType::PROVISION_REQUIRED, toHidlVec(sessionId), data); - } - return mapOEMCryptoResult(res); -} - -Status WVDrmPlugin::mapOEMCryptoResult(OEMCryptoResult res) { - switch (res) { - case OEMCrypto_SUCCESS: - return Status::OK; - - case OEMCrypto_ERROR_SIGNATURE_FAILURE: - return Status::ERROR_DRM_INVALID_STATE; - - case OEMCrypto_ERROR_NO_DEVICE_KEY: - return Status::ERROR_DRM_NOT_PROVISIONED; - - case OEMCrypto_ERROR_INVALID_SESSION: - return Status::ERROR_DRM_SESSION_NOT_OPENED; - - case OEMCrypto_ERROR_TOO_MANY_SESSIONS: - case OEMCrypto_ERROR_INSUFFICIENT_RESOURCES: - return Status::ERROR_DRM_RESOURCE_BUSY; - - case OEMCrypto_ERROR_NOT_IMPLEMENTED: - return Status::ERROR_DRM_CANNOT_HANDLE; - - case OEMCrypto_ERROR_INVALID_RSA_KEY: - case OEMCrypto_ERROR_SHORT_BUFFER: - case OEMCrypto_ERROR_UNKNOWN_FAILURE: - case OEMCrypto_ERROR_OPEN_SESSION_FAILED: - FALLTHROUGH_INTENDED; /* FALLTHROUGH */ - default: - ALOGW("Returns UNKNOWN error for legacy status: %d", res); - return static_cast(::drm::V1_4::Status::GENERAL_OEM_ERROR); - } -} - -wvcdm::RequestedSecurityLevel WVDrmPlugin::getRequestedSecurityLevel() const { - return mPropertySet.security_level().compare( - wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0 - ? wvcdm::kLevel3 - : wvcdm::kLevelDefault; -} - -bool WVDrmPlugin::initDataResemblesPSSH(const std::vector& initData) { - const uint8_t* const initDataArray = initData.data(); - - if (sizeof(uint32_t) + kPsshTag.size() > initData.size()) { - // The init data is so small that it couldn't contain a size and PSSH tag. - return false; - } - - // Extract the size field - const uint8_t* const sizeField = &initDataArray[0]; - uint32_t nboSize; - memcpy(&nboSize, sizeField, sizeof(nboSize)); - uint32_t size = ntohl(nboSize); - - if (size > initData.size()) { - return false; - } - - // Extract the ID field - const char* const idField = - reinterpret_cast(&initDataArray[sizeof(nboSize)]); - std::string id(idField, kPsshTag.size()); - return id == kPsshTag; -} - -Status WVDrmPlugin::unprovision(const CdmIdentifier& identifier) { - if (mPropertySet.use_atsc_mode()) - return mapCdmResponseType(wvcdm::PROVISIONING_NOT_ALLOWED_FOR_ATSC); - - CdmResponseType res1 = mCDM->Unprovision(wvcdm::kSecurityLevelL1, identifier); - CdmResponseType res3 = mCDM->Unprovision(wvcdm::kSecurityLevelL3, identifier); - if (!isCdmResponseTypeSuccess(res1)) { - return mapCdmResponseType(res1); - } else { - return mapCdmResponseType(res3); - } -} - -// Implementation for the CdmIdentifierBuilder inner class -WVDrmPlugin::CdmIdentifierBuilder::CdmIdentifierBuilder( - bool useSpoid, const WVDrmPlugin& parent, const std::string& appPackageName) - : mCdmIdentifier(), - mIsIdentifierSealed(false), - mUseSpoid(useSpoid), - mAppPackageName(appPackageName), - mParent(parent) { - mCdmIdentifier.app_package_name = mAppPackageName; - mCdmIdentifier.unique_id = getNextUniqueId(); - mCdmIdentifier.user_id = wvutil::GetIpcCallingUid(); -} - -Status WVDrmPlugin::CdmIdentifierBuilder::getCdmIdentifier( - CdmIdentifier* identifier) { - if (!mIsIdentifierSealed) { - Status res = calculateSpoid(); - if (res != Status::OK) return res; - mIsIdentifierSealed = true; - } - *identifier = mCdmIdentifier; - return Status::OK; -} - -Status WVDrmPlugin::CdmIdentifierBuilder::getDeviceUniqueId(std::string* id) { - if (mUseSpoid) { - CdmIdentifier identifier; - Status res = getCdmIdentifier(&identifier); - if (res != Status::OK) return res; - - *id = identifier.spoid; - return Status::OK; - } else { - return getOemcryptoDeviceId(id); - } -} - -Status WVDrmPlugin::CdmIdentifierBuilder::getProvisioningUniqueId( - std::string* id) { - if (mUseSpoid) { - // To fake a provisioning-unique ID on SPOID devices where we can't expose - // the real provisioning-unique ID, we just use the SPOID and invert all the - // bits. - Status res = getDeviceUniqueId(id); - if (res != Status::OK) return res; - - for (char& c : *id) { - c = ~c; - } - - return Status::OK; - } else { - return mParent.queryProperty(wvcdm::QUERY_KEY_PROVISIONING_ID, *id); - } -} - -bool WVDrmPlugin::CdmIdentifierBuilder::set_origin(const std::string& id) { - if (mIsIdentifierSealed) return false; - mCdmIdentifier.origin = id; - return true; -} - -bool WVDrmPlugin::CdmIdentifierBuilder::set_use_atsc_mode(bool enable) { - if (is_sealed()) return false; - mCdmIdentifier.app_package_name = - enable ? wvcdm::ATSC_APP_PACKAGE_NAME : mAppPackageName; - return true; -} - -Status WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid() { - if (!mUseSpoid) return Status::OK; - - // Calculate SPOID for default security level if appropriate - std::string deviceId; - if (mParent.getRequestedSecurityLevel() == wvcdm::kLevelDefault) { - Status res = getOemcryptoDeviceId(&deviceId); - if (res != Status::OK) return res; - - return calculateSpoid(deviceId, &mCdmIdentifier.spoid); - } - - // If requested security level is L3, possibilities are - // (a) L3 has not been provisioned - // (b) L3 was provisioned with L3 device ID in the CdmIdentifier - // (c) L3 was provisioned (incorrectly) with L1 device ID in the CdmIdentifier - // Check (b) first. Get L3 device ID, calculate SPOID and if provisioned - // with this SPOID, return this SPOID. - // Check (c) next. Get L1 device ID, calculate SPOID and if provisioned - // with this SPOID, return this SPOID. - // On any errors in (c) or not provisioned return L3 SPOID. - Status res = getOemcryptoDeviceId(wvcdm::kLevel3, &deviceId); - if (res != Status::OK) return res; - - std::string spoidL3; - res = calculateSpoid(deviceId, &spoidL3); - if (res != Status::OK) return res; - - bool atsc_mode_enabled = - mCdmIdentifier.app_package_name == wvcdm::ATSC_APP_PACKAGE_NAME; - - if (mParent.isProvisioned(wvcdm::kSecurityLevelL3, origin(), spoidL3, - atsc_mode_enabled)) { - mCdmIdentifier.spoid = spoidL3; - return Status::OK; - } - - // Not provisioned with CdmIdentifier containing SPOID with L3 device ID. - // Try SPOID with L1 device ID. - std::string deviceIdLevelDefault; - res = getOemcryptoDeviceId(wvcdm::kLevelDefault, &deviceIdLevelDefault); - if (res != Status::OK) { - mCdmIdentifier.spoid = spoidL3; - return Status::OK; - } - - // If the L3 and default security level IDs are identical then the - // device does not support L1. - if (deviceId == deviceIdLevelDefault) { - mCdmIdentifier.spoid = spoidL3; - return Status::OK; - } - - std::string spoidLevelDefault; - res = calculateSpoid(deviceIdLevelDefault, &spoidLevelDefault); - if (res != Status::OK) { - mCdmIdentifier.spoid = spoidL3; - return Status::OK; - } - - if (mParent.isProvisioned(wvcdm::kSecurityLevelL1, origin(), - spoidLevelDefault, atsc_mode_enabled)) { - mCdmIdentifier.spoid = spoidLevelDefault; - return Status::OK; - } - - // Not provisioned with CdmIdentifier containing SPOID with L1 or L3 - // device ID. Return L3 SPOID. - mCdmIdentifier.spoid = spoidL3; - return Status::OK; -} - -Status WVDrmPlugin::CdmIdentifierBuilder::calculateSpoid( - const std::string& deviceId, std::string* spoid) { - if (spoid == nullptr) return Status::ERROR_DRM_CANNOT_HANDLE; - - if (!mUseSpoid) { - spoid->clear(); - return Status::OK; - } - - uint8_t hash[SHA256_DIGEST_LENGTH]; - SHA256_CTX ctx; - SHA256_Init(&ctx); - SHA256_Update(&ctx, deviceId.data(), deviceId.length()); - SHA256_Update(&ctx, mAppPackageName.data(), mAppPackageName.length()); - SHA256_Update(&ctx, origin().data(), origin().length()); - SHA256_Final(hash, &ctx); - - *spoid = std::string(reinterpret_cast(hash), SHA256_DIGEST_LENGTH); - return Status::OK; -} - -Status WVDrmPlugin::CdmIdentifierBuilder::getOemcryptoDeviceId( - std::string* id) { - return mParent.queryProperty(wvcdm::QUERY_KEY_DEVICE_ID, *id); -} - -Status WVDrmPlugin::CdmIdentifierBuilder::getOemcryptoDeviceId( - wvcdm::RequestedSecurityLevel securityLevel, std::string* id) { - return mParent.queryProperty(securityLevel, wvcdm::QUERY_KEY_DEVICE_ID, *id); -} - -uint32_t WVDrmPlugin::CdmIdentifierBuilder::getNextUniqueId() { - // Start with 1. 0 is reserved for the default cdm identifier. - static uint32_t unique_id = 1; - return ++unique_id; -} - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm diff --git a/libwvdrmengine/mediadrm/src_hidl/WVGenericCryptoInterface.cpp b/libwvdrmengine/mediadrm/src_hidl/WVGenericCryptoInterface.cpp deleted file mode 100644 index 9c788fb1..00000000 --- a/libwvdrmengine/mediadrm/src_hidl/WVGenericCryptoInterface.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVCdm" -#include - -#include "WVGenericCryptoInterface.h" - -#include "wv_cdm_constants.h" - -namespace wvdrm { - -using namespace std; -using namespace wvcdm; - -OEMCryptoResult WVGenericCryptoInterface::signRSA(const uint8_t* wrapped_rsa_key, - size_t wrapped_rsa_key_length, - const uint8_t* message, - size_t message_length, - std::vector& signature, - RSA_Padding_Scheme padding_scheme) { - OEMCrypto_SESSION session; - OEMCryptoResult sts = OEMCrypto_OpenSession(&session); - if (sts != OEMCrypto_SUCCESS) return sts; - sts = OEMCrypto_LoadDRMPrivateKey(session, OEMCrypto_RSA_Private_Key, - wrapped_rsa_key, wrapped_rsa_key_length); - if (sts == OEMCrypto_SUCCESS) { - size_t signatureSize = 0; - sts = OEMCrypto_GenerateRSASignature(session, message, message_length, - NULL, &signatureSize, - padding_scheme); - if (sts == OEMCrypto_SUCCESS) { - // Should be short buffer. - sts = OEMCrypto_ERROR_UNKNOWN_FAILURE; - } else if (sts == OEMCrypto_ERROR_SHORT_BUFFER) { - signature.resize(signatureSize); - sts = OEMCrypto_GenerateRSASignature(session, message, message_length, - signature.data(), &signatureSize, - padding_scheme); - } - } - OEMCrypto_CloseSession(session); - return sts; -} - -} // namespace wvdrm diff --git a/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp b/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp deleted file mode 100644 index c770a669..00000000 --- a/libwvdrmengine/mediadrm/src_hidl/hidl_metrics_adapter.cpp +++ /dev/null @@ -1,650 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -#include "hidl_metrics_adapter.h" - -#include -#include "wv_metrics.pb.h" - -using android::hardware::hidl_vec; -using android::hardware::drm::V1_1::DrmMetricGroup; -using drm_metrics::CounterMetric; -using drm_metrics::DistributionMetric; -using google::protobuf::RepeatedPtrField; - -namespace wvcdm { - -namespace { - -const char kAttributeErrorCode[] = "error_code"; -const char kAttributeErrorCodeBool[] = "error_code_bool"; -const char kAttributeCdmSecurityLevel[] = "cdm_security_level"; -const char kAttributeSecurityLevel[] = "security_level"; -const char kAttributeLength[] = "length"; -const char kAttributeEncryptionAlgorithm[] = "encryption_algorithm"; -const char kAttributeSigningAlgorithm[] = "signing_algorithm"; -const char kAttributeOemCryptoResult[] = "oem_crypto_result"; -const char kAttributeKeyStatusType[] = "key_status_type"; -const char kAttributeEventType[] = "event_type"; -const char kAttributeKeyRequestType[] = "key_request_type"; -const char kAttributeLicenseType[] = "license_type"; - -template -void SetValue(const T& value, DrmMetricGroup::Attribute* attribute); - -template<> -void SetValue(const int& value, DrmMetricGroup::Attribute* attribute) { - attribute->int64Value = value; -} -template<> -void SetValue(const bool& value, DrmMetricGroup::Attribute* attribute) { - attribute->int64Value = value; -} -template<> -void SetValue(const unsigned int& value, - DrmMetricGroup::Attribute* attribute) { - attribute->int64Value = value; -} -template<> -__attribute__((unused)) -void SetValue(const unsigned long& value, - DrmMetricGroup::Attribute* attribute) { - attribute->int64Value = value; -} -template<> -__attribute__((unused)) -void SetValue(const unsigned long long& value, - DrmMetricGroup::Attribute* attribute) { - attribute->int64Value = value; -} - -template -void AddAttribute( - const std::string& name, DrmMetricGroup::ValueType vt, T value, - std::vector* attribute_vector) { - // Set the default values. - DrmMetricGroup::Attribute attribute = { name, vt, 0, 0, "" }; - SetValue(value, &attribute); - attribute_vector->push_back(attribute); -} - -} // anonymous namespace - -void HidlMetricsGroupBuilder::AddDistributions( - const std::string& name, - const RepeatedPtrField& distributions) { - for (const auto& metric : distributions) { - AddDistribution(name, metric); - } -} - -void HidlMetricsGroupBuilder::AddCounters( - const std::string& name, - const RepeatedPtrField& counters) { - for (const auto& counter : counters) { - AddCounter(name, counter); - } -} - -void HidlMetricsGroupBuilder::AddDistribution( - const std::string& name, const drm_metrics::DistributionMetric& distribution) { - DrmMetricGroup::Metric metric; - metric.name = name; - AddAttributes(distribution.attributes(), &(metric.attributes)); - - DrmMetricGroup::Value mean = { - "mean", DrmMetricGroup::ValueType::DOUBLE_TYPE, - 0, distribution.mean(), "" }; - DrmMetricGroup::Value count = { - "count", DrmMetricGroup::ValueType::INT64_TYPE, - (int64_t) distribution.operation_count(), 0, "" }; - - if (distribution.operation_count() == 1) { - metric.values.resize(2); - metric.values[0] = mean; - metric.values[1] = count; - } else { - DrmMetricGroup::Value min = { - "min", DrmMetricGroup::ValueType::DOUBLE_TYPE, - 0, distribution.min(), "" }; - DrmMetricGroup::Value max = { - "max", DrmMetricGroup::ValueType::DOUBLE_TYPE, - 0, distribution.max(), "" }; - DrmMetricGroup::Value variance { - "variance", DrmMetricGroup::ValueType::DOUBLE_TYPE, - 0, distribution.variance(), "" }; - metric.values.resize(5); - metric.values[0] = mean; - metric.values[1] = count; - metric.values[2] = min; - metric.values[3] = max; - metric.values[4] = variance; - } - metrics_.push_back(metric); -} - -void HidlMetricsGroupBuilder::AddCounter( - const std::string& name, const drm_metrics::CounterMetric& counter) { - DrmMetricGroup::Metric metric; - metric.name = name; - AddAttributes(counter.attributes(), &(metric.attributes)); - - DrmMetricGroup::Value value = { - "count", DrmMetricGroup::ValueType::INT64_TYPE, counter.count(), 0, "" }; - metric.values.resize(1); - metric.values[0] = value; - metrics_.push_back(metric); -} - -void HidlMetricsGroupBuilder::AddValue( - const std::string& name, const drm_metrics::ValueMetric& value_or_error) { - DrmMetricGroup::Metric metric; - DrmMetricGroup::Value value; - - metric.name = name; - if (value_or_error.has_error_code()) { - value = { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, - value_or_error.error_code(), 0, "" }; - } else if (value_or_error.has_int_value()) { - value = { "value", DrmMetricGroup::ValueType::INT64_TYPE, - value_or_error.int_value(), 0, "" }; - } else if (value_or_error.has_double_value()) { - value = { "value", DrmMetricGroup::ValueType::DOUBLE_TYPE, - 0, value_or_error.double_value(), "" }; - } else if (value_or_error.has_string_value()) { - value = { "value", DrmMetricGroup::ValueType::STRING_TYPE, - 0, 0, value_or_error.string_value() }; - } else { - value = { "error", DrmMetricGroup::ValueType::STRING_TYPE, - 0, 0, "Unexpected value type." }; - } - metric.values.resize(1); - metric.values[0] = value; - metrics_.push_back(metric); -} - -void HidlMetricsGroupBuilder::AddAttributes( - const drm_metrics::Attributes& attributes_proto, - hidl_vec* - attributes) { - std::vector - attribute_vector; - if (attributes_proto.has_error_code()) { - AddAttribute( - kAttributeErrorCode, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.error_code(), &attribute_vector); - } - if (attributes_proto.has_error_code_bool()) { - AddAttribute( - kAttributeErrorCodeBool, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.error_code_bool(), &attribute_vector); - } - if (attributes_proto.has_cdm_security_level()) { - AddAttribute( - kAttributeCdmSecurityLevel, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.cdm_security_level(), &attribute_vector); - } - if (attributes_proto.has_security_level()) { - AddAttribute( - kAttributeSecurityLevel, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.security_level(), &attribute_vector); - } - if (attributes_proto.has_length()) { - AddAttribute( - kAttributeLength, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.length(), &attribute_vector); - } - if (attributes_proto.has_encryption_algorithm()) { - AddAttribute( - kAttributeEncryptionAlgorithm, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.encryption_algorithm(), &attribute_vector); - } - if (attributes_proto.has_signing_algorithm()) { - AddAttribute( - kAttributeSigningAlgorithm, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.signing_algorithm(), &attribute_vector); - } - if (attributes_proto.has_oem_crypto_result()) { - AddAttribute( - kAttributeOemCryptoResult, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.oem_crypto_result(), &attribute_vector); - } - if (attributes_proto.has_key_status_type()) { - AddAttribute( - kAttributeKeyStatusType, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.key_status_type(), &attribute_vector); - } - if (attributes_proto.has_event_type()) { - AddAttribute( - kAttributeEventType, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.event_type(), &attribute_vector); - } - if (attributes_proto.has_key_request_type()) { - AddAttribute( - kAttributeKeyRequestType, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.key_request_type(), &attribute_vector); - } - if (attributes_proto.has_license_type()) { - AddAttribute( - kAttributeLicenseType, - DrmMetricGroup::ValueType::INT64_TYPE, - attributes_proto.license_type(), &attribute_vector); - } - - *attributes = attribute_vector; -} - -DrmMetricGroup HidlMetricsGroupBuilder::Build() { - DrmMetricGroup metric_group; - metric_group.metrics = metrics_; - return metric_group; -} - -HidlMetricsGroupBuilder::HidlMetricsGroupBuilder() {} - -HidlMetricsAdapter::HidlMetricsAdapter() {} -HidlMetricsAdapter::~HidlMetricsAdapter() {} - -void HidlMetricsAdapter::AddEngineMetrics( - const drm_metrics::WvCdmMetrics::EngineMetrics& proto_metrics) { - HidlMetricsGroupBuilder group_builder; - AddCryptoMetrics(proto_metrics.crypto_metrics(), &group_builder); - - if (proto_metrics.has_oemcrypto_initialization_mode()) { - group_builder.AddValue( - "oemcrypto_initialization_mode", - proto_metrics.oemcrypto_initialization_mode()); - } - if (proto_metrics.has_oemcrypto_l1_api_version()) { - group_builder.AddValue( - "oemcrypto_l1_api_version", - proto_metrics.oemcrypto_l1_api_version()); - } - if (proto_metrics.has_oemcrypto_l1_min_api_version()) { - group_builder.AddValue( - "oemcrypto_l1_min_api_version", - proto_metrics.oemcrypto_l1_min_api_version()); - } - if (proto_metrics.has_app_package_name()) { - group_builder.AddValue( - "app_package_name", - proto_metrics.app_package_name()); - } - group_builder.AddDistributions( - "cdm_engine_add_key_time_us", - proto_metrics.cdm_engine_add_key_time_us()); - if (proto_metrics.has_cdm_engine_cdm_version()) { - group_builder.AddValue( - "cdm_engine_cdm_version", - proto_metrics.cdm_engine_cdm_version()); - } - group_builder.AddCounters( - "cdm_engine_close_session", - proto_metrics.cdm_engine_close_session()); - if (proto_metrics.has_cdm_engine_creation_time_millis()) { - group_builder.AddValue( - "cdm_engine_creation_time_millis", - proto_metrics.cdm_engine_creation_time_millis()); - } - group_builder.AddDistributions( - "cdm_engine_decrypt_time_us", - proto_metrics.cdm_engine_decrypt_time_us()); - group_builder.AddCounters( - "cdm_engine_find_session_for_key", - proto_metrics.cdm_engine_find_session_for_key()); - group_builder.AddDistributions( - "cdm_engine_generate_key_request_time_us", - proto_metrics.cdm_engine_generate_key_request_time_us()); - group_builder.AddDistributions( - "cdm_engine_get_provisioning_request_time_us", - proto_metrics.cdm_engine_get_provisioning_request_time_us()); - group_builder.AddCounters( - "cdm_engine_get_secure_stop_ids", - proto_metrics.cdm_engine_get_secure_stop_ids()); - group_builder.AddDistributions( - "cdm_engine_get_usage_info_time_us", - proto_metrics.cdm_engine_get_usage_info_time_us()); - group_builder.AddDistributions( - "cdm_engine_handle_provisioning_response_time_us", - proto_metrics.cdm_engine_handle_provisioning_response_time_us()); - if (proto_metrics.has_cdm_engine_life_span_ms()) { - group_builder.AddValue( - "cdm_engine_life_span_ms", - proto_metrics.cdm_engine_life_span_ms()); - } - group_builder.AddCounters( - "cdm_engine_open_key_set_session", - proto_metrics.cdm_engine_open_key_set_session()); - group_builder.AddCounters( - "cdm_engine_open_session", - proto_metrics.cdm_engine_open_session()); - group_builder.AddDistributions( - "cdm_engine_query_key_status_time_us", - proto_metrics.cdm_engine_query_key_status_time_us()); - group_builder.AddCounters( - "cdm_engine_release_all_usage_info", - proto_metrics.cdm_engine_release_all_usage_info()); - group_builder.AddCounters( - "cdm_engine_release_usage_info", - proto_metrics.cdm_engine_release_usage_info()); - group_builder.AddCounters( - "cdm_engine_remove_all_usage_info", - proto_metrics.cdm_engine_remove_all_usage_info()); - group_builder.AddCounters( - "cdm_engine_remove_keys", - proto_metrics.cdm_engine_remove_keys()); - group_builder.AddCounters( - "cdm_engine_remove_usage_info", - proto_metrics.cdm_engine_remove_usage_info()); - group_builder.AddDistributions( - "cdm_engine_restore_key_time_us", - proto_metrics.cdm_engine_restore_key_time_us()); - group_builder.AddCounters( - "cdm_engine_unprovision", - proto_metrics.cdm_engine_unprovision()); - if (proto_metrics.has_level3_oemcrypto_initialization_error()) { - group_builder.AddValue( - "level3_oemcrypto_initialization_error", - proto_metrics.level3_oemcrypto_initialization_error()); - } - if (proto_metrics.has_previous_oemcrypto_initialization_failure()) { - group_builder.AddValue( - "previous_oemcrypto_initialization_failure", - proto_metrics.previous_oemcrypto_initialization_failure()); - } - - group_vector_.emplace_back(group_builder.Build()); -} - -void HidlMetricsAdapter::AddSessionMetrics( - const drm_metrics::WvCdmMetrics::SessionMetrics& proto_metrics) { - HidlMetricsGroupBuilder group_builder; - AddCryptoMetrics(proto_metrics.crypto_metrics(), &group_builder); - - if (proto_metrics.has_session_id()) { - group_builder.AddValue( - "session_id", - proto_metrics.session_id()); - } - if (proto_metrics.has_cdm_session_life_span_ms()) { - group_builder.AddValue( - "cdm_session_life_span_ms", - proto_metrics.cdm_session_life_span_ms()); - } - group_builder.AddDistributions( - "cdm_session_renew_key_time_us", - proto_metrics.cdm_session_renew_key_time_us()); - group_builder.AddCounters( - "cdm_session_restore_offline_session", - proto_metrics.cdm_session_restore_offline_session()); - group_builder.AddCounters( - "cdm_session_restore_usage_session", - proto_metrics.cdm_session_restore_usage_session()); - group_builder.AddDistributions( - "cdm_session_license_request_latency_ms", - proto_metrics.cdm_session_license_request_latency_ms()); - if (proto_metrics.has_oemcrypto_build_info()) { - group_builder.AddValue( - "oemcrypto_build_info", - proto_metrics.oemcrypto_build_info()); - } - if (proto_metrics.has_license_sdk_version()) { - group_builder.AddValue( - "license_sdk_version", - proto_metrics.license_sdk_version()); - } - if (proto_metrics.has_license_service_version()) { - group_builder.AddValue( - "license_service_version", - proto_metrics.license_service_version()); - } - if (proto_metrics.has_playback_id()) { - group_builder.AddValue( - "playback_id", - proto_metrics.playback_id()); - } - group_vector_.emplace_back(group_builder.Build()); -} - -void HidlMetricsAdapter::AddCryptoMetrics( - const drm_metrics::WvCdmMetrics::CryptoMetrics& proto_metrics, - HidlMetricsGroupBuilder* group_builder) { - if (proto_metrics.has_crypto_session_security_level()) { - group_builder->AddValue( - "crypto_session_security_level", - proto_metrics.crypto_session_security_level()); - } - group_builder->AddCounters( - "crypto_session_delete_all_usage_reports", - proto_metrics.crypto_session_delete_all_usage_reports()); - group_builder->AddCounters( - "crypto_session_delete_multiple_usage_information", - proto_metrics.crypto_session_delete_multiple_usage_information()); - group_builder->AddDistributions( - "crypto_session_generic_decrypt_time_us", - proto_metrics.crypto_session_generic_decrypt_time_us()); - group_builder->AddDistributions( - "crypto_session_generic_encrypt_time_us", - proto_metrics.crypto_session_generic_encrypt_time_us()); - group_builder->AddDistributions( - "crypto_session_generic_sign_time_us", - proto_metrics.crypto_session_generic_sign_time_us()); - group_builder->AddDistributions( - "crypto_session_generic_verify_time_us", - proto_metrics.crypto_session_generic_verify_time_us()); - group_builder->AddCounters( - "crypto_session_get_device_unique_id", - proto_metrics.crypto_session_get_device_unique_id()); - group_builder->AddCounters( - "crypto_session_get_token", - proto_metrics.crypto_session_get_token()); - if (proto_metrics.has_crypto_session_life_span()) { - group_builder->AddValue("crypto_session_life_span", - proto_metrics.crypto_session_life_span()); - } - group_builder->AddDistributions( - "crypto_session_load_certificate_private_key_time_us", - proto_metrics.crypto_session_load_certificate_private_key_time_us()); - group_builder->AddDistributions( - "crypto_session_open_time_us", - proto_metrics.crypto_session_open_time_us()); - if (proto_metrics.has_crypto_session_system_id()) { - group_builder->AddValue("crypto_session_system_id", - proto_metrics.crypto_session_system_id()); - } - group_builder->AddDistributions( - "crypto_session_update_usage_information_time_us", - proto_metrics.crypto_session_update_usage_information_time_us()); - if (proto_metrics.has_crypto_session_usage_information_support()) { - group_builder->AddValue("crypto_session_usage_information_support", - proto_metrics.crypto_session_usage_information_support()); - } - if (proto_metrics.has_usage_table_header_initial_size()) { - group_builder->AddValue("usage_table_header_initial_size", - proto_metrics.usage_table_header_initial_size()); - } - group_builder->AddCounters( - "usage_table_header_add_entry", - proto_metrics.usage_table_header_add_entry()); - group_builder->AddCounters( - "usage_table_header_delete_entry", - proto_metrics.usage_table_header_delete_entry()); - group_builder->AddDistributions( - "usage_table_header_update_entry_time_us", - proto_metrics.usage_table_header_update_entry_time_us()); - group_builder->AddCounters( - "usage_table_header_load_entry", - proto_metrics.usage_table_header_load_entry()); - if (proto_metrics.has_oemcrypto_api_version()) { - group_builder->AddValue("oemcrypto_api_version", - proto_metrics.oemcrypto_api_version()); - } - group_builder->AddCounters( - "oemcrypto_close_session", - proto_metrics.oemcrypto_close_session()); - group_builder->AddDistributions( - "oemcrypto_copy_buffer_time_us", - proto_metrics.oemcrypto_copy_buffer_time_us()); - if (proto_metrics.has_oemcrypto_current_hdcp_capability()) { - group_builder->AddValue("oemcrypto_current_hdcp_capability", - proto_metrics.oemcrypto_current_hdcp_capability()); - } - group_builder->AddCounters( - "oemcrypto_deactivate_usage_entry", - proto_metrics.oemcrypto_deactivate_usage_entry()); - group_builder->AddDistributions( - "oemcrypto_decrypt_cenc_time_us", - proto_metrics.oemcrypto_decrypt_cenc_time_us()); - group_builder->AddCounters( - "oemcrypto_delete_usage_entry", - proto_metrics.oemcrypto_delete_usage_entry()); - group_builder->AddCounters( - "oemcrypto_delete_usage_table", - proto_metrics.oemcrypto_delete_usage_table()); - group_builder->AddDistributions( - "oemcrypto_derive_keys_from_session_key_time_us", - proto_metrics.oemcrypto_derive_keys_from_session_key_time_us()); - group_builder->AddCounters( - "oemcrypto_force_delete_usage_entry", - proto_metrics.oemcrypto_force_delete_usage_entry()); - group_builder->AddDistributions( - "oemcrypto_generate_derived_keys_time_us", - proto_metrics.oemcrypto_generate_derived_keys_time_us()); - group_builder->AddCounters( - "oemcrypto_generate_nonce", - proto_metrics.oemcrypto_generate_nonce()); - group_builder->AddDistributions( - "oemcrypto_generate_rsa_signature_time_us", - proto_metrics.oemcrypto_generate_rsa_signature_time_us()); - group_builder->AddDistributions( - "oemcrypto_generate_signature_time_us", - proto_metrics.oemcrypto_generate_signature_time_us()); - group_builder->AddDistributions( - "oemcrypto_generic_decrypt_time_us", - proto_metrics.oemcrypto_generic_decrypt_time_us()); - group_builder->AddDistributions( - "oemcrypto_generic_encrypt_time_us", - proto_metrics.oemcrypto_generic_encrypt_time_us()); - group_builder->AddDistributions( - "oemcrypto_generic_sign_time_us", - proto_metrics.oemcrypto_generic_sign_time_us()); - group_builder->AddDistributions( - "oemcrypto_generic_verify_time_us", - proto_metrics.oemcrypto_generic_verify_time_us()); - group_builder->AddCounters( - "oemcrypto_get_device_id", - proto_metrics.oemcrypto_get_device_id()); - group_builder->AddDistributions( - "oemcrypto_get_key_data_time_us", - proto_metrics.oemcrypto_get_key_data_time_us()); - group_builder->AddCounters( - "oemcrypto_get_oem_public_certificate", - proto_metrics.oemcrypto_get_oem_public_certificate()); - group_builder->AddCounters( - "oemcrypto_get_random", - proto_metrics.oemcrypto_get_random()); - group_builder->AddDistributions( - "oemcrypto_initialize_time_us", - proto_metrics.oemcrypto_initialize_time_us()); - if (proto_metrics.has_oemcrypto_is_anti_rollback_hw_present()) { - group_builder->AddValue( - "oemcrypto_is_anti_rollback_hw_present", - proto_metrics.oemcrypto_is_anti_rollback_hw_present()); - } - if (proto_metrics.has_oemcrypto_is_keybox_valid()) { - group_builder->AddValue("oemcrypto_is_keybox_valid", - proto_metrics.oemcrypto_is_keybox_valid()); - } - group_builder->AddDistributions( - "oemcrypto_load_device_drm_key_time_us", - proto_metrics.oemcrypto_load_device_drm_key_time_us()); - group_builder->AddDistributions( - "oemcrypto_load_entitled_keys_time_us", - proto_metrics.oemcrypto_load_entitled_keys_time_us()); - group_builder->AddDistributions( - "oemcrypto_load_keys_time_us", - proto_metrics.oemcrypto_load_keys_time_us()); - if (proto_metrics.has_oemcrypto_max_hdcp_capability()) { - group_builder->AddValue("oemcrypto_max_hdcp_capability", - proto_metrics.oemcrypto_max_hdcp_capability()); - } - if (proto_metrics.has_oemcrypto_max_number_of_sessions()) { - group_builder->AddValue("oemcrypto_max_number_of_sessions", - proto_metrics.oemcrypto_max_number_of_sessions()); - } - if (proto_metrics.has_oemcrypto_number_of_open_sessions()) { - group_builder->AddValue("oemcrypto_number_of_open_sessions", - proto_metrics.oemcrypto_number_of_open_sessions()); - } - if (proto_metrics.has_oemcrypto_provisioning_method()) { - group_builder->AddValue("oemcrypto_provisioning_method", - proto_metrics.oemcrypto_provisioning_method()); - } - group_builder->AddDistributions( - "oemcrypto_refresh_keys_time_us", - proto_metrics.oemcrypto_refresh_keys_time_us()); - group_builder->AddCounters( - "oemcrypto_report_usage", - proto_metrics.oemcrypto_report_usage()); - group_builder->AddDistributions( - "oemcrypto_rewrap_device_rsa_key_time_us", - proto_metrics.oemcrypto_rewrap_device_rsa_key_time_us()); - group_builder->AddDistributions( - "oemcrypto_rewrap_device_rsa_key_30_time_us", - proto_metrics.oemcrypto_rewrap_device_rsa_key_30_time_us()); - if (proto_metrics.has_oemcrypto_security_patch_level()) { - group_builder->AddValue("oemcrypto_security_patch_level", - proto_metrics.oemcrypto_security_patch_level()); - } - group_builder->AddDistributions( - "oemcrypto_select_key_time_us", - proto_metrics.oemcrypto_select_key_time_us()); - if (proto_metrics.has_oemcrypto_usage_table_support()) { - group_builder->AddValue("oemcrypto_usage_table_support", - proto_metrics.oemcrypto_usage_table_support()); - } - group_builder->AddCounters( - "oemcrypto_update_usage_table", - proto_metrics.oemcrypto_update_usage_table()); - group_builder->AddCounters( - "oemcrypto_update_usage_entry", - proto_metrics.oemcrypto_update_usage_entry()); -} - -const android::hardware::hidl_vec< - DrmMetricGroup> -HidlMetricsAdapter::GetHidlGroupVector() { - return group_vector_; -} - -void HidlMetricsAdapter::ToHidlMetrics( - const drm_metrics::WvCdmMetrics& proto_metrics, - hidl_vec* hidl_metrics) { - // Convert the engine level metrics - HidlMetricsAdapter adapter; - - if (proto_metrics.has_engine_metrics()) { - adapter.AddEngineMetrics(proto_metrics.engine_metrics()); - } - for (const auto& session_metrics : proto_metrics.session_metrics()) { - adapter.AddSessionMetrics(session_metrics); - } - - *hidl_metrics = adapter.GetHidlGroupVector(); -} - -} // namespace wvcdm diff --git a/libwvdrmengine/mediadrm/test/Android.mk b/libwvdrmengine/mediadrm/test/Android.mk index 428e652f..45a91b57 100644 --- a/libwvdrmengine/mediadrm/test/Android.mk +++ b/libwvdrmengine/mediadrm/test/Android.mk @@ -5,56 +5,7 @@ LOCAL_PATH := $(call my-dir) # include $(CLEAR_VARS) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) - -LOCAL_SRC_FILES := \ - hidl/WVDrmPlugin_test.cpp \ - -LOCAL_C_INCLUDES := \ - frameworks/av/include \ - frameworks/native/include \ - vendor/widevine/libwvdrmengine/cdm/core/include \ - vendor/widevine/libwvdrmengine/cdm/include \ - vendor/widevine/libwvdrmengine/cdm/metrics/include \ - vendor/widevine/libwvdrmengine/cdm/util/include \ - vendor/widevine/libwvdrmengine/include_hidl \ - vendor/widevine/libwvdrmengine/include \ - vendor/widevine/libwvdrmengine/mediadrm/include_hidl \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - -LOCAL_STATIC_LIBRARIES := \ - libcdm \ - libcdm_protos \ - libcdm_utils \ - libjsmn \ - libgmock \ - libgmock_main \ - libgtest \ - libwvlevel3 \ - libwvdrmdrmplugin_hidl \ - libwv_odk \ - -LOCAL_SHARED_LIBRARIES := \ - android.hardware.drm@1.0 \ - android.hardware.drm@1.1 \ - android.hardware.drm@1.2 \ - android.hardware.drm@1.3 \ - android.hardware.drm@1.4 \ - android.hidl.memory@1.0 \ - libbinder_ndk \ - libbase \ - libcrypto \ - libdl \ - libhidlbase \ - libhidlmemory \ - liblog \ - libprotobuf-cpp-lite \ - libutils \ - # build unit tests for Aidl -else - LOCAL_SRC_FILES := \ WVDrmPlugin_hal_test.cpp \ @@ -90,8 +41,6 @@ LOCAL_SHARED_LIBRARIES := \ liblog \ libprotobuf-cpp-lite \ libutils \ -# endif $(WV_UNITTESTS_BUILD_TARGET) -endif LOCAL_HEADER_LIBRARIES := \ libstagefright_headers \ @@ -119,53 +68,10 @@ endif include $(BUILD_EXECUTABLE) # ----------------------------------------------------------------------------- -# Builds hidl hal_metrics_adapter_unittest +# Builds hal_metrics_adapter_unittest # include $(CLEAR_VARS) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) - -LOCAL_SRC_FILES := \ - hidl/hidl_metrics_adapter_unittest.cpp \ - -LOCAL_C_INCLUDES := \ - vendor/widevine/libwvdrmengine/cdm/core/include \ - vendor/widevine/libwvdrmengine/cdm/include \ - vendor/widevine/libwvdrmengine/cdm/metrics/include \ - vendor/widevine/libwvdrmengine/cdm/util/include \ - vendor/widevine/libwvdrmengine/include_hidl \ - vendor/widevine/libwvdrmengine/include \ - vendor/widevine/libwvdrmengine/mediadrm/include_hidl \ - vendor/widevine/libwvdrmengine/oemcrypto/include \ - -LOCAL_STATIC_LIBRARIES := \ - libcdm \ - libcdm_protos \ - libcdm_utils \ - libgtest \ - libgtest_main \ - libjsmn \ - libwvdrmdrmplugin_hidl \ - libwvlevel3 \ - libwv_odk \ - -LOCAL_SHARED_LIBRARIES := \ - android.hardware.drm@1.0 \ - android.hardware.drm@1.1 \ - android.hardware.drm@1.2 \ - android.hidl.memory@1.0 \ - libcrypto \ - libhidlbase \ - libhidlmemory \ - liblog \ - libprotobuf-cpp-lite \ - -LOCAL_C_INCLUDES += \ - external/protobuf/src \ - -# build unit tests for Aidl -else LOCAL_SRC_FILES := \ hal_metrics_adapter_unittest.cpp \ @@ -199,9 +105,6 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_C_INCLUDES += \ external/protobuf/src \ -# endif $(WV_UNITTESTS_BUILD_TARGET) -endif - LOCAL_MODULE := hal_metrics_adapter_unittest LOCAL_LICENSE_KINDS := legacy_by_exception_only LOCAL_LICENSE_CONDITIONS := by_exception_only diff --git a/libwvdrmengine/mediadrm/test/hal_metrics_adapter_unittest.cpp b/libwvdrmengine/mediadrm/test/hal_metrics_adapter_unittest.cpp index a81be10b..af438b33 100644 --- a/libwvdrmengine/mediadrm/test/hal_metrics_adapter_unittest.cpp +++ b/libwvdrmengine/mediadrm/test/hal_metrics_adapter_unittest.cpp @@ -305,7 +305,7 @@ TEST(HalMetricsAdapterTest, AddAllAttrbitues) { {DrmMetricValue::make(59)}}}, {{"count", {DrmMetricValue::make(13)}}}}; - // Confirm that all of the attributes exist in the hidl data. + // Confirm that all of the attributes exist in the HAL data. std::vector metrics; WvMetricsAdapter::ToWvMetrics(metrics_proto, &metrics); EXPECT_TRUE(HasMetric(expected_counter_metric, metrics[0])) diff --git a/libwvdrmengine/mediadrm/test/hidl/WVDrmPlugin_test.cpp b/libwvdrmengine/mediadrm/test/hidl/WVDrmPlugin_test.cpp deleted file mode 100644 index 95215a9c..00000000 --- a/libwvdrmengine/mediadrm/test/hidl/WVDrmPlugin_test.cpp +++ /dev/null @@ -1,3264 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// -//#define LOG_NDEBUG 0 -#define LOG_TAG "WVDrmPluginTest" -#include "WVDrmPlugin.h" - -#include -#include - -#include -#include -#include -#include - -#include "HidlTypes.h" -#include "TypeConvert.h" -#include "WVErrors.h" -#include "cdm_client_property_set.h" -#include "gmock/gmock.h" -#include "gtest/gtest.h" -#include "media/stagefright/MediaErrors.h" -#include "media/stagefright/foundation/ABase.h" -#include "string_conversions.h" -#include "wv_cdm_constants.h" -#include "wv_cdm_types.h" -#include "wv_content_decryption_module.h" - -namespace wvdrm { -namespace hardware { -namespace drm { -namespace V1_4 { -namespace widevine { - -using android::hardware::drm::V1_2::widevine::toHidlVec; -using ::testing::_; -using ::testing::AllOf; -using ::testing::Args; -using ::testing::AtLeast; -using ::testing::DefaultValue; -using ::testing::DoAll; -using ::testing::ElementsAreArray; -using ::testing::Field; -using ::testing::InSequence; -using ::testing::Invoke; -using ::testing::IsEmpty; -using ::testing::Matcher; -using ::testing::NotNull; -using ::testing::Pointee; -using ::testing::SaveArg; -using ::testing::SetArgPointee; -using ::testing::SetArrayArgument; -using ::testing::StrEq; -using ::testing::StrictMock; -using ::testing::Test; -using ::testing::Values; -using ::testing::WithParamInterface; -using ::testing::internal::ElementsAreArrayMatcher; - -using wvcdm::CdmAppParameterMap; -using wvcdm::CdmCertificateType; -using wvcdm::CdmClientPropertySet; -using wvcdm::CdmIdentifier; -using wvcdm::CdmInitData; -using wvcdm::CdmKeyMessage; -using wvcdm::CdmKeyRequest; -using wvcdm::CdmKeyResponse; -using wvcdm::CdmKeySetId; -using wvcdm::CdmKeySystem; -using wvcdm::CdmLicenseType; -using wvcdm::CdmOfflineLicenseState; -using wvcdm::CdmProvisioningRequest; -using wvcdm::CdmProvisioningResponse; -using wvcdm::CdmQueryMap; -using wvcdm::CdmSecurityLevel; -using wvcdm::EMPTY_ORIGIN; -using wvcdm::kCertificateWidevine; -using wvcdm::KEY_ID_SIZE; -using wvcdm::KEY_IV_SIZE; -using wvcdm::KEY_SET_ID_PREFIX; -using wvcdm::kKeyRequestTypeInitial; -using wvcdm::kKeyRequestTypeRelease; -using wvcdm::kKeyRequestTypeRenewal; -using wvcdm::kLicenseTypeOffline; -using wvcdm::kLicenseTypeRelease; -using wvcdm::kLicenseTypeStreaming; -using wvcdm::kSecurityLevelL1; -using wvcdm::kSecurityLevelL3; -using wvcdm::NEVER_EXPIRES; -using wvcdm::QUERY_KEY_CURRENT_SRM_VERSION; -using wvcdm::QUERY_KEY_DECRYPT_HASH_SUPPORT; -using wvcdm::QUERY_KEY_DEVICE_ID; -using wvcdm::QUERY_KEY_MAX_NUMBER_OF_SESSIONS; -using wvcdm::QUERY_KEY_NUMBER_OF_OPEN_SESSIONS; -using wvcdm::QUERY_KEY_OEMCRYPTO_API_VERSION; -using wvcdm::QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION; -using wvcdm::QUERY_KEY_OEMCRYPTO_SESSION_ID; -using wvcdm::QUERY_KEY_PROVISIONING_ID; -using wvcdm::QUERY_KEY_PROVISIONING_MODEL; -using wvcdm::QUERY_KEY_RESOURCE_RATING_TIER; -using wvcdm::QUERY_KEY_SECURITY_LEVEL; -using wvcdm::QUERY_KEY_SRM_UPDATE_SUPPORT; -using wvcdm::QUERY_KEY_SYSTEM_ID; -using wvcdm::QUERY_KEY_WVCDM_VERSION; -using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L1; -using wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3; -using wvcdm::SESSION_ID_PREFIX; -using wvcdm::WvCdmEventListener; -using wvutil::Base64Encode; - -namespace { -const std::string kEmptyString; -const std::string kOrigin("widevine.com"); -const std::string kAppId("com.unittest.mock.app.id"); -const uint8_t* const kUnprovisionResponse = - reinterpret_cast("unprovision"); -const size_t kUnprovisionResponseSize = 11; -const std::string kDeviceId("0123456789\0ABCDEF", 17); - -// This is a serialized WvCdmMetrics message containing a small amount of -// sample data. This ensures we're able to extract it via a property. -const char kSerializedMetricsHex[] = - "0a580a001a0210072202100d2a02100832182216636f6d2e676f6f676c652e616e64726f69" - "642e676d734208220631342e302e304a06080112020800520610d5f3fad5056a0b1d00fd4c" - "47280132020804a2010608011202080012cb010a0622047369643412b5010a021001520919" - "1d5a643bdfff50405a0b1d00d01945280132021001620d1d00f8e84528013204080020006a" - "0310b739820102100d8a01060801120248009a010310ff01da0106080112024800e2010e1d" - "005243472801320528800248009a020d1d00b016452801320428404800a202060801120248" - "19aa0206080212024800b2020b1d8098f047280132024800ba02021001ca020b1d00101945" - "280132024800e202021004fa02021002a203021000b2030210021a09196891ed7c3f35504" - "0"; - -#define N_ELEM(a) (sizeof(a) / sizeof(a[0])) -} // anonymous namespace - -class MockCDM : public WvContentDecryptionModule { - public: - MOCK_METHOD(CdmResponseType, OpenSession, (const CdmKeySystem&, - CdmClientPropertySet*, - const CdmIdentifier&, - WvCdmEventListener*, - CdmSessionId*), (override)); - - MOCK_METHOD(CdmResponseType, CloseSession, (const CdmSessionId&), (override)); - - MOCK_METHOD(CdmResponseType, GenerateKeyRequest, - (const CdmSessionId&, const CdmKeySetId&, - const std::string&, const CdmInitData&, - const CdmLicenseType, CdmAppParameterMap&, - CdmClientPropertySet*, const CdmIdentifier&, - CdmKeyRequest*), (override)); - - MOCK_METHOD(CdmResponseType, AddKey, (const CdmSessionId&, - const CdmKeyResponse&, - CdmKeySetId*), (override)); - - MOCK_METHOD(CdmResponseType, RemoveKeys, (const CdmSessionId&), (override)); - - MOCK_METHOD(CdmResponseType, RestoreKey, (const CdmSessionId&, - const CdmKeySetId&), (override)); - - MOCK_METHOD(CdmResponseType, QueryStatus, (wvcdm::RequestedSecurityLevel, - const std::string&, - std::string*), (override)); - - MOCK_METHOD(CdmResponseType, QuerySessionStatus, (const CdmSessionId&, - CdmQueryMap*), (override)); - - MOCK_METHOD(CdmResponseType, QueryKeyStatus, (const CdmSessionId&, - CdmQueryMap*), (override)); - - MOCK_METHOD(CdmResponseType, QueryOemCryptoSessionId, (const CdmSessionId&, - CdmQueryMap*), (override)); - - MOCK_METHOD(CdmResponseType, GetProvisioningRequest, (CdmCertificateType, - const std::string&, - const CdmIdentifier&, - const std::string&, - wvcdm::RequestedSecurityLevel, - CdmProvisioningRequest*, - std::string*), (override)); - - MOCK_METHOD(CdmResponseType, HandleProvisioningResponse, - (const CdmIdentifier&, const CdmProvisioningResponse&, - wvcdm::RequestedSecurityLevel, std::string*, std::string*), (override)); - - MOCK_METHOD(CdmResponseType, Unprovision, (CdmSecurityLevel, - const CdmIdentifier&), (override)); - - MOCK_METHOD(bool, IsProvisioned, (CdmSecurityLevel, const std::string&, - const std::string&, bool), (override)); - - MOCK_METHOD(bool, IsValidServiceCertificate, (const std::string&), (override)); - - MOCK_METHOD(CdmResponseType, GetMetrics, (const CdmIdentifier&, - drm_metrics::WvCdmMetrics*), (override)); - - MOCK_METHOD(CdmResponseType, GetDecryptHashError, - (const CdmSessionId&, std::string*), (override)); - - MOCK_METHOD(CdmResponseType, ListStoredLicenses, - (CdmSecurityLevel, - const CdmIdentifier&, - std::vector*), (override)); - - MOCK_METHOD(CdmResponseType, GetOfflineLicenseState, - (const std::string&, - CdmSecurityLevel, - const CdmIdentifier&, - CdmOfflineLicenseState*), (override)); - - MOCK_METHOD(CdmResponseType, RemoveOfflineLicense, - (const std::string&, - CdmSecurityLevel, - const CdmIdentifier&), (override)); -}; - -class MockCrypto : public WVGenericCryptoInterface { - public: - MOCK_METHOD(OEMCryptoResult, selectKey, (const OEMCrypto_SESSION, - const uint8_t*, size_t), (override)); - - MOCK_METHOD(OEMCryptoResult, encrypt, (OEMCrypto_SESSION, const uint8_t*, - size_t, const uint8_t*, - OEMCrypto_Algorithm, uint8_t*), (override)); - - MOCK_METHOD(OEMCryptoResult, decrypt, (OEMCrypto_SESSION, const uint8_t*, - size_t, const uint8_t*, - OEMCrypto_Algorithm, uint8_t*), (override)); - - MOCK_METHOD(OEMCryptoResult, sign, (OEMCrypto_SESSION, const uint8_t*, size_t, - OEMCrypto_Algorithm, uint8_t*, size_t*), (override)); - - MOCK_METHOD(OEMCryptoResult, verify, (OEMCrypto_SESSION, const uint8_t*, - size_t, OEMCrypto_Algorithm, - const uint8_t*, size_t), (override)); - - MOCK_METHOD(OEMCryptoResult, loadDeviceRSAKey, (OEMCrypto_SESSION, - const uint8_t*, size_t), (override)); - - MOCK_METHOD(OEMCryptoResult, generateRSASignature, (OEMCrypto_SESSION, - const uint8_t*, size_t, - uint8_t*, size_t*, - RSA_Padding_Scheme), (override)); -}; - -class MockDrmPluginListener : public IDrmPluginListener_V1_2 { - public: - MOCK_METHOD(Return, sendEvent, (EventType, const hidl_vec&, - const hidl_vec&), (override)); - - MOCK_METHOD(Return, sendExpirationUpdate, - (const hidl_vec&, int64_t), (override)); - - MOCK_METHOD(Return, sendKeysChange, (const hidl_vec&, - const hidl_vec&, bool), (override)); - - MOCK_METHOD(Return, sendSessionLostState, - (const hidl_vec&), (override)); - - MOCK_METHOD(Return, sendKeysChange_1_2, (const hidl_vec&, - const hidl_vec&, bool), (override)); -}; - -template -CdmResponseType setSessionIdOnMap(testing::Unused, CdmQueryMap* map) { - static const char oecId[] = {DIGIT + '0', '\0'}; - (*map)[QUERY_KEY_OEMCRYPTO_SESSION_ID] = oecId; - return wvcdm::NO_ERROR; -} - -MATCHER_P(HasOrigin, origin, "") { return arg.origin == origin; } - -class WVDrmPluginTest : public Test { - protected: - static const uint32_t kKeySetIdSize = 32; - static const uint32_t kSessionIdSize = 16; - uint8_t keySetIdRaw[kKeySetIdSize]; - uint8_t sessionIdRaw[kSessionIdSize]; - std::vector keySetId; - std::vector sessionId; - CdmSessionId cdmSessionId; - - virtual void SetUp() { - // Fill the session ID - FILE* fp = fopen("/dev/urandom", "r"); - fread(sessionIdRaw, sizeof(uint8_t), kSessionIdSize, fp); - - memcpy(sessionIdRaw, SESSION_ID_PREFIX, sizeof(SESSION_ID_PREFIX) - 1); - sessionId.assign(sessionIdRaw, sessionIdRaw + kSessionIdSize); - cdmSessionId.assign(sessionId.begin(), sessionId.end()); - - fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp); - fclose(fp); - - memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX)); - CdmKeySetId cdmKeySetId(reinterpret_cast(keySetIdRaw), - kKeySetIdSize); - keySetId.assign(keySetIdRaw, keySetIdRaw + kKeySetIdSize); - - // Set default return values for gMock - DefaultValue::Set(wvcdm::NO_ERROR); - DefaultValue::Set(OEMCrypto_SUCCESS); - DefaultValue::Set(true); - } -}; - -struct OriginTestVariant { - // For a test that does not expect any follow-up queries - OriginTestVariant(const std::string& nameValue, - const std::string& originValue, - const std::string& expectedOriginValue) - : name(nameValue), - origin(originValue), - expectedOrigin(expectedOriginValue) {} - - const std::string name; - const std::string origin; - const std::string expectedOrigin; -}; - -void PrintTo(const OriginTestVariant& param, ::std::ostream* os) { - *os << param.name << " Variant"; -} - -class WVDrmPluginOriginTest : public WVDrmPluginTest, - public WithParamInterface {}; - -TEST_F(WVDrmPluginTest, OpensSessions) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, - HasOrigin(EMPTY_ORIGIN), _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected mock behavior - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - EXPECT_THAT(sessionId, ElementsAreArray(sessionIdRaw, kSessionIdSize)); - Status status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, OpensSessions_1_1) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - // Provide expected mock behavior - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - testing::Return(wvcdm::NO_ERROR))); - - CdmQueryMap securityLevelQueryMap; - securityLevelQueryMap[wvcdm::QUERY_KEY_SECURITY_LEVEL] = - wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3; - - EXPECT_CALL(*cdm, QuerySessionStatus(_, NotNull())) - .WillOnce(DoAll(SetArgPointee<1>(securityLevelQueryMap), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - Status status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L1")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession_1_1( - android::hardware::drm::V1_1::SecurityLevel::SW_SECURE_CRYPTO, - [&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), - hSessionId.data() + hSessionId.size()); - }); - - ASSERT_THAT(propertySet, NotNull()); - EXPECT_THAT(sessionId, ElementsAreArray(sessionIdRaw, kSessionIdSize)); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, ClosesSessions) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, CloseSession(cdmSessionId)).Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, ClosesSessionWithError) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, CloseSession(cdmSessionId)) - .WillOnce(testing::Return(wvcdm::SESSION_NOT_FOUND_1)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::ERROR_DRM_SESSION_NOT_OPENED, status); -} - -// TODO b/35325611 Fix this disabled test -TEST_F(WVDrmPluginTest, DISABLED_GeneratesKeyRequests) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const size_t kInitDataSize = 128; - uint8_t initDataRaw[kInitDataSize]; - static const size_t kRequestSize = 256; - uint8_t requestRaw[kRequestSize]; - static const uint32_t kKeySetIdSize = 32; - uint8_t keySetIdRaw[kKeySetIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(initDataRaw, sizeof(uint8_t), kInitDataSize, fp); - fread(requestRaw, sizeof(uint8_t), kRequestSize, fp); - fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp); - fclose(fp); - - memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX) - 1); - CdmKeySetId cdmKeySetId(reinterpret_cast(keySetIdRaw), kKeySetIdSize); - std::vector keySetId; - keySetId.assign(keySetIdRaw, keySetIdRaw + kKeySetIdSize); - - CdmInitData cdmInitData(reinterpret_cast(initDataRaw), kInitDataSize); - std::vector initData; - initData.assign(initDataRaw, initDataRaw + kInitDataSize); - - // clang-format off - static const uint8_t psshPrefix[] = { - 0, 0, 0, 32 + kInitDataSize, // Total size - 'p', 's', 's', 'h', // "PSSH" - 0, 0, 0, 0, // Flags - must be zero - 0xED, 0xEF, 0x8B, 0xA9, 0x79, 0xD6, 0x4A, 0xCE, // Widevine UUID - 0xA3, 0xC8, 0x27, 0xDC, 0xD5, 0x1D, 0x21, 0xED, - 0, 0, 0, kInitDataSize // Size of initData - }; - // clang-format on - static const size_t kPsshPrefixSize = sizeof(psshPrefix); - static const size_t kPsshBoxSize = kPsshPrefixSize + kInitDataSize; - uint8_t psshBoxRaw[kPsshBoxSize]; - memcpy(psshBoxRaw, psshPrefix, kPsshPrefixSize); - memcpy(psshBoxRaw + kPsshPrefixSize, initDataRaw, kInitDataSize); - CdmInitData cdmPsshBox(reinterpret_cast(psshBoxRaw), kPsshBoxSize); - std::vector psshBox; - psshBox.assign(psshBoxRaw, psshBoxRaw + kPsshBoxSize); - - CdmKeyMessage cdmRequest(requestRaw, requestRaw + kRequestSize); - - std::map parameters; - CdmAppParameterMap cdmParameters; - parameters.insert( - std::pair("paddingScheme", "BUBBLE WRAP")); - cdmParameters["paddingScheme"] = "BUBBLE WRAP"; - parameters.insert( - std::pair("favorite-particle", "tetraquark")); - cdmParameters["favorite-particle"] = "tetraquark"; - parameters.insert(std::pair("answer", "6 * 9")); - cdmParameters["answer"] = "6 * 9"; - - std::vector optionalParameters; - KeyValue keyValue; - for (std::map::iterator itr = parameters.begin(); - itr != parameters.end(); ++itr) { - keyValue.key = itr->first; - keyValue.value = itr->second; - optionalParameters.push_back(keyValue); - } - - static const char* kDefaultUrl = "http://google.com/"; - static const char* kIsoBmffMimeType = "cenc"; - static const char* kWebmMimeType = "webm"; - - struct TestSet { - const char* mimeType; - const std::vector& initDataIn; - const CdmInitData& initDataOut; - }; - - // We run the same set of operations on several sets of data, simulating - // different valid calling patterns. - TestSet testSets[] = { - {kIsoBmffMimeType, psshBox, cdmPsshBox}, // ISO-BMFF, EME passing style - {kIsoBmffMimeType, initData, cdmPsshBox}, // ISO-BMFF, old passing style - {kWebmMimeType, initData, cdmInitData} // WebM - }; - size_t testSetCount = N_ELEM(testSets); - - // Set up the expected calls. Per gMock rules, this must be done for all test - // sets prior to testing any of them. - { - InSequence calls; - - for (size_t i = 0; i < testSetCount; ++i) { - const char* mimeType = testSets[i].mimeType; - const CdmInitData& initData = testSets[i].initDataOut; - - CdmKeyRequest initialRequest = {cdmRequest, kKeyRequestTypeInitial, - kDefaultUrl}; - - CdmKeyRequest renewalRequest = {cdmRequest, kKeyRequestTypeRenewal, - kDefaultUrl}; - - CdmKeyRequest releaseRequest = {cdmRequest, kKeyRequestTypeRelease, - kDefaultUrl}; - - EXPECT_CALL(*cdm, - GenerateKeyRequest(cdmSessionId, "", mimeType, initData, - kLicenseTypeOffline, cdmParameters, - NotNull(), HasOrigin(EMPTY_ORIGIN), _)) - .WillOnce(DoAll(SetArgPointee<8>(initialRequest), - testing::Return(wvcdm::KEY_MESSAGE))); - - EXPECT_CALL(*cdm, - GenerateKeyRequest(cdmSessionId, "", mimeType, initData, - kLicenseTypeStreaming, cdmParameters, - NotNull(), HasOrigin(EMPTY_ORIGIN), _)) - .WillOnce(DoAll(SetArgPointee<8>(renewalRequest), - testing::Return(wvcdm::KEY_MESSAGE))); - - EXPECT_CALL(*cdm, - GenerateKeyRequest("", cdmKeySetId, mimeType, initData, - kLicenseTypeRelease, cdmParameters, - NotNull(), HasOrigin(EMPTY_ORIGIN), _)) - - .WillOnce(DoAll(SetArgPointee<8>(releaseRequest), - testing::Return(wvcdm::KEY_MESSAGE))); - } - } - - // Performs the actual tests - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - for (size_t i = 0; i < testSetCount; ++i) { - const std::string mimeType(testSets[i].mimeType); - const std::vector& initData = testSets[i].initDataIn; - - plugin.getKeyRequest( - toHidlVec(sessionId), toHidlVec(initData), hidl_string(mimeType), - KeyType::OFFLINE, toHidlVec(optionalParameters), - [&](Status status, hidl_vec hRequest, - KeyRequestType keyRequestType, hidl_string defaultUrl) { - ASSERT_EQ(Status::OK, status); - - std::vector request(hRequest); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_EQ(KeyRequestType::INITIAL, keyRequestType); - EXPECT_STREQ(kDefaultUrl, defaultUrl.c_str()); - }); - - plugin.getKeyRequest( - toHidlVec(sessionId), toHidlVec(initData), hidl_string(mimeType), - KeyType::STREAMING, toHidlVec(optionalParameters), - [&](Status status, hidl_vec hRequest, - KeyRequestType keyRequestType, hidl_string defaultUrl) { - ASSERT_EQ(Status::OK, status); - - std::vector request(hRequest); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_EQ(KeyRequestType::RENEWAL, keyRequestType); - EXPECT_STREQ(kDefaultUrl, defaultUrl.c_str()); - }); - - plugin.getKeyRequest( - toHidlVec(sessionId), toHidlVec(initData), hidl_string(mimeType), - KeyType::RELEASE, toHidlVec(optionalParameters), - [&](Status status, hidl_vec hRequest, - KeyRequestType keyRequestType, hidl_string defaultUrl) { - ASSERT_EQ(Status::OK, status); - - std::vector request(hRequest); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_EQ(KeyRequestType::RELEASE, keyRequestType); - EXPECT_STREQ(kDefaultUrl, defaultUrl.c_str()); - }); - } -} - -TEST_F(WVDrmPluginTest, AddsKeys) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const uint32_t kResponseSize = 256; - uint8_t responseRaw[kResponseSize]; - static const uint32_t kKeySetIdSize = 32; - uint8_t keySetIdRaw[kKeySetIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(responseRaw, sizeof(uint8_t), kResponseSize, fp); - fread(keySetIdRaw, sizeof(uint8_t), kKeySetIdSize, fp); - fclose(fp); - - std::vector response; - response.assign(responseRaw, responseRaw + kResponseSize); - - memcpy(keySetIdRaw, KEY_SET_ID_PREFIX, sizeof(KEY_SET_ID_PREFIX) - 1); - CdmKeySetId cdmKeySetId(reinterpret_cast(keySetIdRaw), kKeySetIdSize); - - std::vector keySetId; - std::vector emptyKeySetId; - - EXPECT_CALL(*cdm, AddKey(cdmSessionId, - ElementsAreArray(responseRaw, kResponseSize), _)) - .WillOnce(DoAll(SetArgPointee<2>(cdmKeySetId), - testing::Return(wvcdm::KEY_ADDED))); - - EXPECT_CALL(*cdm, AddKey("", ElementsAreArray(responseRaw, kResponseSize), - Pointee(cdmKeySetId))) - .Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.provideKeyResponse( - toHidlVec(sessionId), toHidlVec(response), - [&](Status status, hidl_vec hKeySetId) { - ASSERT_EQ(Status::OK, status); - - std::vector id(hKeySetId); - keySetId.assign(id.data(), id.data() + id.size()); - ASSERT_THAT(keySetId, ElementsAreArray(keySetIdRaw, kKeySetIdSize)); - }); - - plugin.provideKeyResponse(toHidlVec(keySetId), toHidlVec(response), - [&](Status status, hidl_vec hKeySetId) { - ASSERT_EQ(Status::OK, status); - - EXPECT_EQ(0u, hKeySetId.size()); - }); -} - -TEST_F(WVDrmPluginTest, HandlesPrivacyCertCaseOfAddKey) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - sp> listener = - new StrictMock(); - - const CdmClientPropertySet* propertySet = nullptr; - - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - static const uint32_t kResponseSize = 256; - uint8_t responseRaw[kResponseSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(responseRaw, sizeof(uint8_t), kResponseSize, fp); - fclose(fp); - - hidl_vec hSessionId; - hSessionId.setToExternal(sessionIdRaw, kSessionIdSize); - hidl_vec hEmptyData; - - EXPECT_CALL(*listener, - sendEvent(EventType::KEY_NEEDED, hSessionId, hEmptyData)) - .Times(1); - - EXPECT_CALL(*cdm, AddKey(_, _, _)) - .WillRepeatedly(testing::Return(wvcdm::NEED_KEY)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - - plugin.setListener(listener); - - Status status = plugin.setPropertyString(hidl_string("privacyMode"), - hidl_string("enable")); - ASSERT_EQ(Status::OK, status); - EXPECT_TRUE(propertySet->use_privacy_mode()); - - std::vector response; - response.assign(responseRaw, responseRaw + kResponseSize); - std::vector keySetId; - - plugin.provideKeyResponse( - toHidlVec(sessionId), toHidlVec(response), - [&](Status status, hidl_vec /* keySetId */) { - ASSERT_EQ(Status::OK, status); - }); -} - -TEST_F(WVDrmPluginTest, RemovesKeys) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, RemoveKeys(cdmSessionId)).Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status status = plugin.removeKeys(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, RestoresKeys) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, RestoreKey(cdmSessionId, - ElementsAreArray(keySetIdRaw, kKeySetIdSize))) - .Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status status = plugin.restoreKeys(toHidlVec(sessionId), toHidlVec(keySetId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, QueriesKeyStatus) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - std::map expectedLicenseStatus; - CdmQueryMap cdmLicenseStatus; - - expectedLicenseStatus.insert( - std::pair("areTheKeysAllRight", "yes")); - cdmLicenseStatus["areTheKeysAllRight"] = "yes"; - expectedLicenseStatus.insert( - std::pair("isGMockAwesome", "ohhhhhhYeah")); - cdmLicenseStatus["isGMockAwesome"] = "ohhhhhhYeah"; - expectedLicenseStatus.insert( - std::pair("answer", "42")); - cdmLicenseStatus["answer"] = "42"; - - EXPECT_CALL(*cdm, QueryKeyStatus(cdmSessionId, _)) - .WillOnce(DoAll(SetArgPointee<1>(cdmLicenseStatus), - testing::Return(wvcdm::NO_ERROR))); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.queryKeyStatus( - toHidlVec(sessionId), - [&](Status status, hidl_vec(hLicenseStatus)) { - ASSERT_EQ(Status::OK, status); - ASSERT_EQ(expectedLicenseStatus.size(), hLicenseStatus.size()); - - KeyValue keyValuePair; - size_t i = 0; - for (std::map::iterator itr = - expectedLicenseStatus.begin(); - itr != expectedLicenseStatus.end(); ++itr) { - keyValuePair.value = hLicenseStatus[i++].value; - EXPECT_EQ(itr->second.c_str(), - std::string(keyValuePair.value.c_str())); - } - }); -} - -TEST_F(WVDrmPluginTest, GetsProvisioningRequests) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const uint32_t kRequestSize = 256; - uint8_t requestRaw[kRequestSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(requestRaw, sizeof(uint8_t), kRequestSize, fp); - fclose(fp); - - CdmProvisioningRequest cdmRequest(requestRaw, requestRaw + kRequestSize); - - static const char* kDefaultUrl = "http://google.com/"; - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - testing::Return(wvcdm::NO_ERROR))); - - // The first and the third invocation should be at default security level, - // while the second one should be L3 - EXPECT_CALL(*cdm, GetProvisioningRequest(kCertificateWidevine, IsEmpty(), - HasOrigin(EMPTY_ORIGIN), IsEmpty(), - wvcdm::kLevelDefault, _, _)) - .Times(2) - .WillRepeatedly(DoAll(SetArgPointee<5>(cdmRequest), - SetArgPointee<6>(kDefaultUrl), - testing::Return(wvcdm::NO_ERROR))); - EXPECT_CALL(*cdm, GetProvisioningRequest(kCertificateWidevine, IsEmpty(), - HasOrigin(EMPTY_ORIGIN), IsEmpty(), - wvcdm::kLevel3, _, _)) - .WillOnce(DoAll(SetArgPointee<5>(cdmRequest), - SetArgPointee<6>(kDefaultUrl), - testing::Return(wvcdm::NO_ERROR))); - - // Make 3 provisioning requests at security level default then L3 then L1 - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.getProvisionRequest( - hidl_string(""), hidl_string(""), - [&](Status status, hidl_vec hRequest, hidl_string defaultUrl) { - ASSERT_EQ(Status::OK, status); - - std::vector request(hRequest); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_STREQ(kDefaultUrl, defaultUrl.c_str()); - }); - - // Set L3 security level - Status status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - plugin.getProvisionRequest( - hidl_string(""), hidl_string(""), - [&](Status status, hidl_vec hRequest, hidl_string defaultUrl) { - ASSERT_EQ(Status::OK, status); - - std::vector request(hRequest); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_STREQ(kDefaultUrl, defaultUrl.c_str()); - }); - - // Reset security level to L1 - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L1")); - ASSERT_EQ(Status::OK, status); - plugin.getProvisionRequest( - hidl_string(""), hidl_string(""), - [&](Status status, hidl_vec hRequest, hidl_string defaultUrl) { - ASSERT_EQ(Status::OK, status); - - std::vector request(hRequest); - EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize)); - EXPECT_STREQ(kDefaultUrl, defaultUrl.c_str()); - }); -} - -TEST_F(WVDrmPluginTest, RejectsAtscProvisioningRequests) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - Status status = - plugin.setPropertyString(hidl_string("atscMode"), hidl_string("enable")); - ASSERT_EQ(Status::OK, status); - - plugin.getProvisionRequest( - hidl_string(""), hidl_string(""), - [&](Status status, hidl_vec, hidl_string) { - ASSERT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); - }); -} - -TEST_F(WVDrmPluginTest, HandlesProvisioningResponses) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const uint32_t kResponseSize = 512; - uint8_t responseRaw[kResponseSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(responseRaw, sizeof(uint8_t), kResponseSize, fp); - fclose(fp); - - std::vector response; - response.assign(responseRaw, responseRaw + kResponseSize); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - testing::Return(wvcdm::NO_ERROR))); - - // The first and the third invocation should be at default security level, - // while the second one should be L3 - EXPECT_CALL(*cdm, HandleProvisioningResponse( - HasOrigin(EMPTY_ORIGIN), - ElementsAreArray(responseRaw, kResponseSize), - wvcdm::kLevelDefault, _, _)) - .Times(2); - EXPECT_CALL(*cdm, HandleProvisioningResponse( - HasOrigin(EMPTY_ORIGIN), - ElementsAreArray(responseRaw, kResponseSize), - wvcdm::kLevel3, _, _)) - .Times(1); - - std::vector cert; - std::vector key; - - // Process 3 provisioning responses at security level default then L3 then L1 - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.provideProvisionResponse( - toHidlVec(response), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { ASSERT_EQ(Status::OK, status); }); - - // Set L3 security level - Status status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin.provideProvisionResponse( - toHidlVec(response), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { ASSERT_EQ(Status::OK, status); }); - - // Reset security level to L1 - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L1")); - plugin.provideProvisionResponse( - toHidlVec(response), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { ASSERT_EQ(Status::OK, status); }); -} - -TEST_F(WVDrmPluginTest, UnprovisionsDevice) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status res = plugin.unprovisionDevice(); - ASSERT_EQ(Status::OK, res); -} - -TEST_F(WVDrmPluginTest, MuxesUnprovisioningErrors) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - // Tests that both Unprovisions are called even if one fails. Also tests that - // no matter which fails, the function always propagates the error. - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN))) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(testing::Return(wvcdm::NO_ERROR)) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN))) - .WillOnce(testing::Return(wvcdm::NO_ERROR)) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status res = plugin.unprovisionDevice(); - ASSERT_NE(Status::OK, res); - res = plugin.unprovisionDevice(); - ASSERT_NE(Status::OK, res); - res = plugin.unprovisionDevice(); - ASSERT_NE(Status::OK, res); -} - -TEST_F(WVDrmPluginTest, UnprovisionsOrigin) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - std::vector specialResponse; - specialResponse.assign(kUnprovisionResponse, - kUnprovisionResponse + kUnprovisionResponseSize); - - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(kOrigin.c_str()))) - .Times(1); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(kOrigin.c_str()))) - .Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - Status status = - plugin.setPropertyString(hidl_string("origin"), hidl_string(kOrigin)); - ASSERT_EQ(Status::OK, status); - - plugin.provideProvisionResponse( - toHidlVec(specialResponse), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { EXPECT_EQ(Status::OK, status); }); -} - -TEST_F(WVDrmPluginTest, UnprovisionsGloballyWithSpoid) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - std::vector specialResponse; - specialResponse.assign(kUnprovisionResponse, - kUnprovisionResponse + kUnprovisionResponseSize); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _)) - .WillRepeatedly( - DoAll(SetArgPointee<2>(kDeviceId), testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, true); - plugin.provideProvisionResponse( - toHidlVec(specialResponse), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { EXPECT_EQ(Status::OK, status); }); -} - -TEST_F(WVDrmPluginTest, WillNotUnprovisionWithoutOriginOrSpoid) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - std::vector specialResponse; - specialResponse.assign(kUnprovisionResponse, - kUnprovisionResponse + kUnprovisionResponseSize); - - EXPECT_CALL(*cdm, Unprovision(_, _)).Times(0); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.provideProvisionResponse( - toHidlVec(specialResponse), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { EXPECT_NE(Status::OK, status); }); -} - -TEST_F(WVDrmPluginTest, MuxesOriginUnprovisioningErrors) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - std::vector specialResponse; - specialResponse.assign(kUnprovisionResponse, - kUnprovisionResponse + kUnprovisionResponseSize); - - // Tests that both Unprovisions are called even if one fails. Also tests that - // no matter which fails, the function always propagates the error. - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL1, HasOrigin(kOrigin.c_str()))) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(testing::Return(wvcdm::NO_ERROR)) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)); - EXPECT_CALL(*cdm, Unprovision(kSecurityLevelL3, HasOrigin(kOrigin.c_str()))) - .WillOnce(testing::Return(wvcdm::NO_ERROR)) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)) - .WillOnce(testing::Return(wvcdm::UNKNOWN_ERROR)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - Status status = - plugin.setPropertyString(hidl_string("origin"), hidl_string(kOrigin)); - ASSERT_EQ(Status::OK, status); - - plugin.provideProvisionResponse( - toHidlVec(specialResponse), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { EXPECT_NE(Status::OK, status); }); - - plugin.provideProvisionResponse( - toHidlVec(specialResponse), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { EXPECT_NE(Status::OK, status); }); - - plugin.provideProvisionResponse( - toHidlVec(specialResponse), - [&](Status status, hidl_vec /* cert */, - hidl_vec /* key */) { EXPECT_NE(Status::OK, status); }); -} - -TEST_F(WVDrmPluginTest, RejectsAtscUnprovisionDeviceRequests) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - Status status = - plugin.setPropertyString(hidl_string("atscMode"), hidl_string("enable")); - - status = plugin.unprovisionDevice(); - ASSERT_EQ(Status::ERROR_DRM_CANNOT_HANDLE, status); -} - -TEST_F(WVDrmPluginTest, ReturnsExpectedPropertyValues) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - CdmQueryMap l1Map; - l1Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L1; - - CdmQueryMap l3Map; - l3Map[QUERY_KEY_SECURITY_LEVEL] = QUERY_VALUE_SECURITY_LEVEL_L3; - - static const std::string systemId = "The Universe"; - static const std::string provisioningId("Life\0&Everything", 16); - static const std::string openSessions = "42"; - static const std::string maxSessions = "54"; - static const std::string oemCryptoApiVersion = "13"; - static const std::string currentSRMVersion = "1"; - static const std::string cdmVersion = "Infinity Minus 1"; - static const std::string resourceRatingTier = "1"; - static const std::string oemCryptoBuildInformation = "Mostly Harmless"; - static const std::string oemCryptoHashNotSupported = "0"; - static const std::string oemCryptoCrcClearBuffer = "1"; - static const std::string oemCryptoPartnerDefinedHash = "2"; - static const std::string decryptHashErrorBadHashAndFrameNumber = "53, 1"; - static const std::string provisioningModel = "Zaphod Beeblebrox"; - drm_metrics::WvCdmMetrics expected_metrics; - std::string serialized_metrics = wvutil::a2bs_hex(kSerializedMetricsHex); - ASSERT_TRUE(expected_metrics.ParseFromString(serialized_metrics)); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _)) - .WillOnce( - DoAll(SetArgPointee<2>(kDeviceId), testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SYSTEM_ID, _)) - .WillOnce( - DoAll(SetArgPointee<2>(systemId), testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_PROVISIONING_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(provisioningId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_NUMBER_OF_OPEN_SESSIONS, _)) - .WillOnce(DoAll(SetArgPointee<2>(openSessions), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_MAX_NUMBER_OF_SESSIONS, _)) - .WillOnce(DoAll(SetArgPointee<2>(maxSessions), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_OEMCRYPTO_API_VERSION, _)) - .WillOnce(DoAll(SetArgPointee<2>(oemCryptoApiVersion), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SRM_UPDATE_SUPPORT, _)) - .WillOnce( - DoAll(SetArgPointee<2>("True"), testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_CURRENT_SRM_VERSION, _)) - .WillOnce(DoAll(SetArgPointee<2>(currentSRMVersion), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_WVCDM_VERSION, _)) - .WillOnce(DoAll(SetArgPointee<2>(cdmVersion), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_RESOURCE_RATING_TIER, _)) - .WillOnce(DoAll(SetArgPointee<2>(resourceRatingTier), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DECRYPT_HASH_SUPPORT, _)) - .WillOnce(DoAll(SetArgPointee<2>("1"), testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_OEMCRYPTO_BUILD_INFORMATION, _)) - .WillOnce(DoAll(SetArgPointee<2>(oemCryptoBuildInformation), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, GetDecryptHashError(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(decryptHashErrorBadHashAndFrameNumber), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_PROVISIONING_MODEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(provisioningModel), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, GetMetrics(_, _)) - .WillOnce(DoAll(SetArgPointee<1>(expected_metrics), - testing::Return(wvcdm::NO_ERROR))); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - std::string stringResult; - std::vector vectorResult; - - plugin.getPropertyString(hidl_string("vendor"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ("Google", stringResult.c_str()); - }); - - plugin.getPropertyString( - hidl_string("version"), [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(cdmVersion.c_str(), stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("description"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ("Widevine CDM", stringResult.c_str()); - }); - - plugin.getPropertyString( - hidl_string("algorithms"), [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ("AES/CBC/NoPadding,HmacSHA256", stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("securityLevel"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L1.c_str(), - stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("securityLevel"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(QUERY_VALUE_SECURITY_LEVEL_L3.c_str(), - stringResult.c_str()); - }); - - plugin.getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - std::vector id(vectorResult); - EXPECT_THAT(id, ElementsAreArray(kDeviceId.data(), kDeviceId.size())); - }); - - plugin.getPropertyString( - hidl_string("systemId"), [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(systemId.c_str(), stringResult.c_str()); - }); - - plugin.getPropertyByteArray( - hidl_string("provisioningUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - std::vector id(vectorResult); - EXPECT_THAT( - id, ElementsAreArray(provisioningId.data(), provisioningId.size())); - }); - - plugin.getPropertyString(hidl_string("numberOfOpenSessions"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_EQ(openSessions, stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("maxNumberOfSessions"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_EQ(maxSessions, stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("oemCryptoApiVersion"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(oemCryptoApiVersion.c_str(), - stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("SRMUpdateSupport"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ("True", stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("CurrentSRMVersion"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(currentSRMVersion.c_str(), - stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("resourceRatingTier"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(resourceRatingTier.c_str(), - stringResult.c_str()); - }); - - plugin.getPropertyString(hidl_string("oemCryptoBuildInformation"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(oemCryptoBuildInformation.c_str(), - stringResult.c_str()); - }); - - std::stringstream ss; - ss << oemCryptoHashNotSupported << " " << oemCryptoCrcClearBuffer << " " - << oemCryptoPartnerDefinedHash; - std::string validResults = ss.str(); - plugin.getPropertyString(hidl_string("decryptHashSupport"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_EQ(oemCryptoCrcClearBuffer, stringResult); - }); - - plugin.getPropertyString(hidl_string("decryptHashError"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_EQ(decryptHashErrorBadHashAndFrameNumber, - stringResult); - }); - - plugin.getPropertyString(hidl_string("provisioningModel"), - [&](Status status, hidl_string stringResult) { - ASSERT_EQ(Status::OK, status); - EXPECT_STREQ(provisioningModel.c_str(), - stringResult.c_str()); - }); - - // This call occurs before any open session or other call. This means - // that the cdm identifer is not yet sealed, and metrics return empty - // metrics data. - plugin.getPropertyByteArray( - hidl_string("metrics"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - std::vector id(vectorResult); - const char empty[] = {}; - EXPECT_THAT(id, ElementsAreArray(empty, sizeof(empty))); - }); - - // Set expectations for the OpenSession call and a CloseSession call. - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, - HasOrigin(EMPTY_ORIGIN), _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - // This call causes the cdm identifier to become sealed. - std::vector sessionId; - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - // This call occurs after open session. The CDM identifer should be sealed. - // And the call should populate the mock metrics data. - plugin.getPropertyByteArray( - hidl_string("metrics"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - std::vector id(vectorResult); - EXPECT_THAT(id, ElementsAreArray(serialized_metrics.data(), - serialized_metrics.size())); - }); - - ASSERT_EQ(Status::OK, plugin.closeSession(toHidlVec(sessionId))); -} - -TEST_F(WVDrmPluginTest, DoesNotGetUnknownProperties) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - std::string stringResult; - std::vector vectorResult; - - plugin.getPropertyString(hidl_string("unknownProperty"), - [&](Status status, hidl_string stringResult) { - ASSERT_NE(Status::OK, status); - EXPECT_TRUE(stringResult.empty()); - }); - - plugin.getPropertyByteArray( - hidl_string("unknownProperty"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_NE(Status::OK, status); - EXPECT_EQ(0u, vectorResult.size()); - }); -} - -TEST_F(WVDrmPluginTest, DoesNotSetUnknownProperties) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const uint32_t kValueSize = 32; - uint8_t valueRaw[kValueSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(valueRaw, sizeof(uint8_t), kValueSize, fp); - fclose(fp); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - std::vector value; - value.assign(valueRaw, valueRaw + kValueSize); - - Status status = plugin.setPropertyString(hidl_string("unknownProperty"), - hidl_string("ignored")); - ASSERT_NE(Status::OK, status); - - status = plugin.setPropertyByteArray(hidl_string("unknownProperty"), - toHidlVec(value)); - ASSERT_NE(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, CompliesWithSpoidVariability) { - StrictMock crypto; - - const std::string kDeviceIds[] = { - kDeviceId, - kDeviceId + " the Second", - }; - const size_t kDeviceCount = N_ELEM(kDeviceIds); - - const std::string kAppNames[] = { - std::string("com.google.widevine"), - std::string("com.youtube"), - }; - const size_t kAppCount = N_ELEM(kAppNames); - - const std::string kOrigins[] = { - kOrigin, - kOrigin + " but not that one, the other one.", - std::string(/* Intentionally Empty */), - }; - const size_t kOriginCount = N_ELEM(kOrigins); - - const size_t kPluginCount = 2; - - const size_t kPluginsPerCdm = kAppCount * kOriginCount * kPluginCount; - - // We will get kPluginCount SPOIDs for every app package name + device id + - // origin combination. - std::vector spoids[kDeviceCount][kAppCount][kOriginCount] - [kPluginCount]; - - for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) { - const std::string& deviceId = kDeviceIds[deviceIndex]; - - android::sp> cdm = new StrictMock(); - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_DEVICE_ID, _)) - .Times(AtLeast(kPluginsPerCdm)) - .WillRepeatedly(DoAll(SetArgPointee<2>(deviceId), - testing::Return(wvcdm::NO_ERROR))); - - for (size_t appIndex = 0; appIndex < kAppCount; ++appIndex) { - const std::string& appPackageName = kAppNames[appIndex]; - - for (size_t originIndex = 0; originIndex < kOriginCount; ++originIndex) { - const std::string& origin = kOrigins[originIndex]; - - for (size_t pluginIndex = 0; pluginIndex < kPluginCount; - ++pluginIndex) { - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, true); - - if (!origin.empty()) { - ASSERT_EQ(Status::OK, - plugin.setPropertyString(hidl_string("origin"), - hidl_string(origin))); - } - - plugin.getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoids[deviceIndex][appIndex][originIndex][pluginIndex] = - vectorResult; - }); - } - } - } - } - - // This nest of loops makes sure all the SPOIDs we retrieved above are - // identical if their parameters were identical and dissimilar otherwise. - for (size_t deviceIndex = 0; deviceIndex < kDeviceCount; ++deviceIndex) { - for (size_t appIndex = 0; appIndex < kAppCount; ++appIndex) { - for (size_t originIndex = 0; originIndex < kOriginCount; ++originIndex) { - for (size_t pluginIndex = 0; pluginIndex < kPluginCount; - ++pluginIndex) { - const std::vector& firstSpoid = - spoids[deviceIndex][appIndex][originIndex][pluginIndex]; - - for (size_t deviceIndex2 = 0; deviceIndex2 < kDeviceCount; - ++deviceIndex2) { - for (size_t appIndex2 = 0; appIndex2 < kAppCount; ++appIndex2) { - for (size_t originIndex2 = 0; originIndex2 < kOriginCount; - ++originIndex2) { - for (size_t pluginIndex2 = 0; pluginIndex2 < kPluginCount; - ++pluginIndex2) { - const std::vector& secondSpoid = - spoids[deviceIndex2][appIndex2][originIndex2] - [pluginIndex2]; - - if (deviceIndex == deviceIndex2 && appIndex == appIndex2 && - originIndex == originIndex2) { - EXPECT_EQ(firstSpoid, secondSpoid); - } else { - EXPECT_NE(firstSpoid, secondSpoid); - } - } - } - } - } - } - } - } - } -} - -TEST_F(WVDrmPluginTest, ReturnsSameL1Spoid) { - StrictMock crypto; - - std::string kL1DeviceId = kDeviceId + "L1"; - - const std::string kAppPackageName("com.google.widevine"); - constexpr size_t kSpoidQuery = 2; - std::vector spoid[kSpoidQuery]; - - android::sp> cdm = new StrictMock(); - - EXPECT_CALL(*cdm, QueryStatus(wvcdm::kLevelDefault, QUERY_KEY_DEVICE_ID, _)) - .Times(kSpoidQuery) - .WillRepeatedly(DoAll(SetArgPointee<2>(kL1DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(kSpoidQuery) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(kSpoidQuery) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(kSpoidQuery); - - // Open a session twice with the same security level, app package name and - // origin and make sure the spoids returned are the same - for (int i = 0; i < kSpoidQuery; ++i) { - WVDrmPlugin plugin(cdm.get(), kAppPackageName, &crypto, true); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), - hSessionId.data() + hSessionId.size()); - }); - - EXPECT_EQ(Status::OK, plugin.closeSession(toHidlVec(sessionId))); - - plugin.getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoid[i] = vectorResult; - }); - } - - EXPECT_EQ(spoid[0], spoid[1]); -} - -TEST_F(WVDrmPluginTest, ReturnsL3SpoidsWhenL3ProvisionedUsingL3Spoid) { - StrictMock crypto; - - std::string kL3DeviceId = kDeviceId + "L3"; - - const std::string kAppPackageName("com.google.widevine"); - constexpr size_t kSpoidQuery = 2; - std::vector spoid[kSpoidQuery]; - - android::sp> cdm = new StrictMock(); - - EXPECT_CALL(*cdm, QueryStatus(wvcdm::kLevel3, QUERY_KEY_DEVICE_ID, _)) - .Times(kSpoidQuery) - .WillRepeatedly(DoAll(SetArgPointee<2>(kL3DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(kSpoidQuery) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(kSpoidQuery) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, IsProvisioned(wvcdm::kSecurityLevelL3, _, _, _)) - .Times(kSpoidQuery) - .WillRepeatedly(testing::Return(true)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(kSpoidQuery); - - // The device is provisioned at L3 security level. Open a session twice - // and make sure that the spoids returned are the same when the - // session are opened at the same security level(L3), app package name - // and origin - for (size_t i = 0; i < kSpoidQuery; ++i) { - WVDrmPlugin plugin(cdm.get(), kAppPackageName, &crypto, true); - - // Forcing L3 - Status status = plugin.setPropertyString(hidl_string("securityLevel"), - hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), - hSessionId.data() + hSessionId.size()); - }); - - EXPECT_EQ(Status::OK, plugin.closeSession(toHidlVec(sessionId))); - - plugin.getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoid[i] = vectorResult; - }); - } - - EXPECT_EQ(spoid[0], spoid[1]); -} - -TEST_F(WVDrmPluginTest, ReturnsL3SpoidsWhenL3Unprovisioned) { - StrictMock crypto; - - std::string kL1DeviceId = kDeviceId + "L1"; - std::string kL3DeviceId = kDeviceId + "L3"; - - const std::string kAppPackageName("com.google.widevine"); - constexpr size_t kSpoidQuery = 2; - std::vector spoid[kSpoidQuery]; - - android::sp> cdm = new StrictMock(); - - EXPECT_CALL(*cdm, QueryStatus(wvcdm::kLevelDefault, QUERY_KEY_DEVICE_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(kL1DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryStatus(wvcdm::kLevel3, QUERY_KEY_DEVICE_ID, _)) - .Times(kSpoidQuery) - .WillRepeatedly(DoAll(SetArgPointee<2>(kL3DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(kSpoidQuery) - .WillOnce(testing::Return(wvcdm::NEED_PROVISIONING)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillOnce(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, IsProvisioned(wvcdm::kSecurityLevelL3, _, _, _)) - .WillOnce(testing::Return(false)) - .WillOnce(testing::Return(true)); - - EXPECT_CALL(*cdm, IsProvisioned(wvcdm::kSecurityLevelL1, _, _, _)) - .WillOnce(testing::Return(false)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(1); - - // This device is unprovisioned at the L3 security level. An attempt to - // open a session results in an ERROR_DRM_NOT_PROVISIONED error. - // Spoids are computed using device Unique IDs at each security level. - // Since provisioning has not occurred for either spoid, the spoid - // using the L3 device ID is used. - android::sp plugin = - new WVDrmPlugin(cdm.get(), kAppPackageName, &crypto, true); - - // Force L3 - Status status = plugin->setPropertyString(hidl_string("securityLevel"), - hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin->openSession([&](Status status, hidl_vec) { - ASSERT_EQ(Status::ERROR_DRM_NOT_PROVISIONED, status); - }); - - plugin->getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoid[0] = vectorResult; - }); - - // Try to open a session again. If provisioning took place, this time the - // attempt will be successful. Retrieve the spoid. This time only - // the device unique ID at the L3 security level will be queried. - // Confirm that it matches the spoid queried earlier. - plugin = new WVDrmPlugin(cdm.get(), kAppPackageName, &crypto, true); - - // Force L3 - status = plugin->setPropertyString(hidl_string("securityLevel"), - hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin->openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - EXPECT_EQ(Status::OK, plugin->closeSession(toHidlVec(sessionId))); - - plugin->getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoid[1] = vectorResult; - }); - - EXPECT_EQ(spoid[0], spoid[1]); -} - -TEST_F(WVDrmPluginTest, ReturnsL1SpoidsWhenL3ProvisionedUsingL1Spoid) { - StrictMock crypto; - - std::string kL1DeviceId = kDeviceId + "L1"; - std::string kL3DeviceId = kDeviceId + "L3"; - - const std::string kAppPackageName("com.google.widevine"); - constexpr size_t kSpoidQuery = 2; - std::vector spoidL1; - std::vector spoidL3[kSpoidQuery]; - - // Set expectations for the first plugin instance - android::sp> cdm1 = new StrictMock(); - - EXPECT_CALL(*cdm1, QueryStatus(wvcdm::kLevelDefault, QUERY_KEY_DEVICE_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(kL1DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm1, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(testing::Return(wvcdm::NEED_PROVISIONING)); - - EXPECT_CALL(*cdm1, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillOnce(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm1, CloseSession(_)); - - // Open a session at L1 security level. The spoid is now computed with - // the L1 device unique ID - android::sp plugin = - new WVDrmPlugin(cdm1.get(), kAppPackageName, &crypto, true); - - plugin->openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - EXPECT_EQ(Status::OK, plugin->closeSession(toHidlVec(sessionId))); - - plugin->getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoidL1 = vectorResult; - }); - - // Force L3. This should not be allowed since the spoid has been - // computed. We defer correcting this, as this might have an - // impact on apps. L3 is not provisioned so a call to openSession - // returns a ERROR_DRM_NOT_PROVISIONED error. No spoid computation takes - // place. - Status status = plugin->setPropertyString(hidl_string("securityLevel"), - hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin->openSession([&](Status status, hidl_vec) { - ASSERT_EQ(Status::ERROR_DRM_NOT_PROVISIONED, status); - }); - - plugin->getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoidL3[0] = vectorResult; - }); - - // Set expectations for the second plugin instance - android::sp> cdm2 = new StrictMock(); - - EXPECT_CALL(*cdm2, QueryStatus(wvcdm::kLevelDefault, QUERY_KEY_DEVICE_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(kL1DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm2, QueryStatus(wvcdm::kLevel3, QUERY_KEY_DEVICE_ID, _)) - .WillOnce(DoAll(SetArgPointee<2>(kL3DeviceId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm2, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm2, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillOnce(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm2, IsProvisioned(wvcdm::kSecurityLevelL1, _, _, _)) - .WillOnce(testing::Return(true)); - - EXPECT_CALL(*cdm2, IsProvisioned(wvcdm::kSecurityLevelL3, _, _, _)) - .WillOnce(testing::Return(false)); - - EXPECT_CALL(*cdm2, CloseSession(_)); - - // Try to open a session again. If provisioning took place, this time the - // attempt will be successful. Spoids are computed using device unique IDs - // from both L1 and L3. The device is provisioned for L3 using the spoid with - // L1 but not L3 device unique ID, so the spoid with L1 device unique ID is - // used. - plugin = new WVDrmPlugin(cdm2.get(), kAppPackageName, &crypto, true); - - // Force L3 - status = plugin->setPropertyString(hidl_string("securityLevel"), - hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin->openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - EXPECT_EQ(Status::OK, plugin->closeSession(toHidlVec(sessionId))); - - plugin->getPropertyByteArray( - hidl_string("deviceUniqueId"), - [&](Status status, hidl_vec vectorResult) { - ASSERT_EQ(Status::OK, status); - spoidL3[1] = vectorResult; - }); - - EXPECT_EQ(spoidL3[0], spoidL3[1]); - EXPECT_EQ(spoidL1, spoidL3[0]); -} - -TEST_F(WVDrmPluginTest, FailsGenericMethodsWithoutAnAlgorithmSet) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - std::vector keyId; - std::vector input; - std::vector iv; - std::vector output; - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - // Note that we do not set the algorithms. This should cause these methods - // to fail. - - plugin.encrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input), - toHidlVec(iv), - [&](Status status, hidl_vec /* output */) { - // NO_INIT is converted to Status::ERROR_DRM_UNKNOWN - EXPECT_EQ(Status::ERROR_DRM_UNKNOWN, status); - }); - - plugin.decrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input), - toHidlVec(iv), - [&](Status status, hidl_vec /* output */) { - EXPECT_EQ(Status::ERROR_DRM_UNKNOWN, status); - }); - - plugin.sign(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input), - [&](Status status, hidl_vec /* signature */) { - EXPECT_EQ(Status::ERROR_DRM_UNKNOWN, status); - }); - - plugin.verify(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input), - toHidlVec(output), [&](Status status, bool /* match */) { - EXPECT_EQ(Status::ERROR_DRM_UNKNOWN, status); - }); -} - -MATCHER_P(IsIV, iv, "") { - for (size_t i = 0; i < KEY_IV_SIZE; ++i) { - if (iv[i] != arg[i]) { - return false; - } - } - - return true; -} - -TEST_F(WVDrmPluginTest, CallsGenericEncrypt) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const size_t kDataSize = 256; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t inputRaw[kDataSize]; - uint8_t ivRaw[KEY_IV_SIZE]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(inputRaw, sizeof(uint8_t), kDataSize, fp); - fread(ivRaw, sizeof(uint8_t), KEY_IV_SIZE, fp); - fclose(fp); - - std::vector keyId; - keyId.assign(keyIdRaw, keyIdRaw + KEY_ID_SIZE); - std::vector input; - input.assign(inputRaw, inputRaw + kDataSize); - std::vector iv; - iv.assign(ivRaw, ivRaw + KEY_IV_SIZE); - std::vector output; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, encrypt(4, _, kDataSize, IsIV(ivRaw), - OEMCrypto_AES_CBC_128_NO_PADDING, _)) - .With(Args<1, 2>(ElementsAreArray(inputRaw, kDataSize))) - .Times(1); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - Status status = plugin.setCipherAlgorithm(toHidlVec(sessionId), - hidl_string("AES/CBC/NoPadding")); - ASSERT_EQ(Status::OK, status); - - plugin.encrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input), - toHidlVec(iv), - [&](Status status, hidl_vec /* output */) { - ASSERT_EQ(Status::OK, status); - }); -} - -TEST_F(WVDrmPluginTest, CallsGenericDecrypt) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const size_t kDataSize = 256; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t inputRaw[kDataSize]; - uint8_t ivRaw[KEY_IV_SIZE]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(inputRaw, sizeof(uint8_t), kDataSize, fp); - fread(ivRaw, sizeof(uint8_t), KEY_IV_SIZE, fp); - fclose(fp); - - std::vector keyId; - keyId.assign(keyIdRaw, keyIdRaw + KEY_ID_SIZE); - std::vector input; - input.assign(inputRaw, inputRaw + kDataSize); - std::vector iv; - iv.assign(ivRaw, ivRaw + KEY_IV_SIZE); - std::vector output; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, decrypt(4, _, kDataSize, IsIV(ivRaw), - OEMCrypto_AES_CBC_128_NO_PADDING, _)) - .With(Args<1, 2>(ElementsAreArray(inputRaw, kDataSize))) - .Times(1); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - Status status = plugin.setCipherAlgorithm(toHidlVec(sessionId), - hidl_string("AES/CBC/NoPadding")); - ASSERT_EQ(Status::OK, status); - - plugin.decrypt(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(input), - toHidlVec(iv), - [&](Status status, hidl_vec /* output */) { - ASSERT_EQ(Status::OK, status); - }); -} - -TEST_F(WVDrmPluginTest, CallsGenericSign) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const size_t kDataSize = 256; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t messageRaw[kDataSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(messageRaw, sizeof(uint8_t), kDataSize, fp); - fclose(fp); - - std::vector keyId; - keyId.assign(keyIdRaw, keyIdRaw + KEY_ID_SIZE); - std::vector message; - message.assign(messageRaw, messageRaw + kDataSize); - std::vector signature; - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, - sign(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, Pointee(0))) - .With(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize))) - .WillOnce(DoAll(SetArgPointee<5>(64), - testing::Return(OEMCrypto_ERROR_SHORT_BUFFER))); - - EXPECT_CALL(crypto, - sign(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, Pointee(64))) - .With(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize))) - .Times(1); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - Status status = - plugin.setMacAlgorithm(toHidlVec(sessionId), hidl_string("HmacSHA256")); - ASSERT_EQ(Status::OK, status); - - plugin.sign(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message), - [&](Status status, hidl_vec signature) { - ASSERT_EQ(Status::OK, status); - ASSERT_NE(0u, signature.size()); - }); -} - -TEST_F(WVDrmPluginTest, CallsGenericVerify) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - static const size_t kDataSize = 256; - static const size_t kSignatureSize = 16; - uint8_t keyIdRaw[KEY_ID_SIZE]; - uint8_t messageRaw[kDataSize]; - uint8_t signatureRaw[kSignatureSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(keyIdRaw, sizeof(uint8_t), KEY_ID_SIZE, fp); - fread(messageRaw, sizeof(uint8_t), kDataSize, fp); - fread(signatureRaw, sizeof(uint8_t), kSignatureSize, fp); - fclose(fp); - - std::vector keyId; - keyId.assign(keyIdRaw, keyIdRaw + KEY_ID_SIZE); - std::vector message; - message.assign(messageRaw, messageRaw + kDataSize); - std::vector signature; - signature.assign(signatureRaw, signatureRaw + kSignatureSize); - - { - InSequence calls; - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, verify(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, - kSignatureSize)) - .With(AllOf(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize)), - Args<4, 5>(ElementsAreArray(signatureRaw, kSignatureSize)))) - .WillOnce(testing::Return(OEMCrypto_SUCCESS)); - - EXPECT_CALL(crypto, selectKey(4, _, KEY_ID_SIZE)) - .With(Args<1, 2>(ElementsAreArray(keyIdRaw, KEY_ID_SIZE))) - .Times(1); - - EXPECT_CALL(crypto, verify(4, _, kDataSize, OEMCrypto_HMAC_SHA256, _, - kSignatureSize)) - .With(AllOf(Args<1, 2>(ElementsAreArray(messageRaw, kDataSize)), - Args<4, 5>(ElementsAreArray(signatureRaw, kSignatureSize)))) - .WillOnce(testing::Return(OEMCrypto_ERROR_SIGNATURE_FAILURE)); - } - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - Status status = - plugin.setMacAlgorithm(toHidlVec(sessionId), hidl_string("HmacSHA256")); - ASSERT_EQ(Status::OK, status); - - plugin.verify(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message), - toHidlVec(signature), [&](Status status, bool match) { - ASSERT_EQ(Status::OK, status); - EXPECT_TRUE(match); - }); - - plugin.verify(toHidlVec(sessionId), toHidlVec(keyId), toHidlVec(message), - toHidlVec(signature), [&](Status status, bool match) { - ASSERT_EQ(Status::OK, status); - EXPECT_FALSE(match); - }); -} - -TEST_F(WVDrmPluginTest, RegistersForEvents) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - // Provide expected behavior to support session creation - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .Times(AtLeast(1)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::OK, status); - }); -} - -TEST_F(WVDrmPluginTest, UnregistersForAllEventsOnDestruction) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - uint8_t sessionIdRaw1[kSessionIdSize]; - uint8_t sessionIdRaw2[kSessionIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - fread(sessionIdRaw1, sizeof(uint8_t), kSessionIdSize, fp); - fread(sessionIdRaw2, sizeof(uint8_t), kSessionIdSize, fp); - fclose(fp); - - CdmSessionId cdmSessionId1(sessionIdRaw1, sessionIdRaw1 + kSessionIdSize); - CdmSessionId cdmSessionId2(sessionIdRaw2, sessionIdRaw2 + kSessionIdSize); - - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId1), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId2), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId1, _)) - .WillOnce(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId2, _)) - .WillOnce(Invoke(setSessionIdOnMap<5>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - { - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::OK, status); - }); - - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::OK, status); - }); - } -} - -// TODO b/35325611 Fix this disabled test -TEST_F(WVDrmPluginTest, DISABLED_MarshalsEvents) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - sp> listener = - new StrictMock(); - - const int64_t kExpiryTimeInSeconds = 123456789012LL; - std::string kKeyId1 = "Testing Key1 Id "; - std::string kKeyId2 = "Testing Key2 Id "; - std::string kKeyId3 = "Testing Key3 Id "; - std::string kKeyId4 = "Testing Key4 Id "; - std::string kKeyId5 = "Testing Key5 Id "; - - { - InSequence calls; - - hidl_vec hEmptyData; - hidl_vec hSessionId; - hSessionId.setToExternal(sessionIdRaw, kSessionIdSize); - - std::vector keyId; - std::vector keyStatusList; - - KeyStatus_V1_2 keyStatus; - keyId.assign(kKeyId1.begin(), kKeyId1.end()); - keyStatus.keyId = toHidlVec(keyId); - keyStatus.type = KeyStatusType_V1_2::EXPIRED; - keyStatusList.push_back(keyStatus); - - hidl_vec hKeyStatusList = toHidlVec(keyStatusList); - EXPECT_CALL(*listener, - sendKeysChange_1_2(hSessionId, hKeyStatusList, false)); - - EXPECT_CALL(*listener, - sendEvent(EventType::KEY_EXPIRED, hSessionId, hEmptyData)); - - EXPECT_CALL(*listener, - sendEvent(EventType::KEY_NEEDED, hSessionId, hEmptyData)); - - // Expiry Time in Java API is in milliseconds. - EXPECT_CALL(*listener, sendExpirationUpdate(hSessionId, NEVER_EXPIRES)); - EXPECT_CALL(*listener, - sendExpirationUpdate(hSessionId, kExpiryTimeInSeconds * 1000)); - - keyStatusList.clear(); - keyId.clear(); - keyId.assign(kKeyId1.begin(), kKeyId1.end()); - keyStatus.type = KeyStatusType_V1_2::USABLE; - keyStatusList.push_back(keyStatus); - keyId.assign(kKeyId2.begin(), kKeyId2.end()); - keyStatus.type = KeyStatusType_V1_2::OUTPUTNOTALLOWED; - keyStatusList.push_back(keyStatus); - keyId.assign(kKeyId3.begin(), kKeyId3.end()); - keyStatus.type = KeyStatusType_V1_2::INTERNALERROR; - keyStatusList.push_back(keyStatus); - keyId.assign(kKeyId4.begin(), kKeyId4.end()); - keyStatus.type = KeyStatusType_V1_2::STATUSPENDING; - keyStatusList.push_back(keyStatus); - keyId.assign(kKeyId5.begin(), kKeyId5.end()); - keyStatus.type = KeyStatusType_V1_2::USABLEINFUTURE; - keyStatusList.push_back(keyStatus); - - hidl_vec hKeyStatusList2 = toHidlVec(keyStatusList); - EXPECT_CALL(*listener, - sendKeysChange_1_2(hSessionId, hKeyStatusList2, false)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.setListener(listener); - - CdmKeyStatusMap cdmKeysStatus; - cdmKeysStatus[kKeyId1] = wvcdm::kKeyStatusExpired; - plugin.OnSessionKeysChange(cdmSessionId, cdmKeysStatus, false); - - plugin.OnSessionRenewalNeeded(cdmSessionId); - plugin.OnExpirationUpdate(cdmSessionId, NEVER_EXPIRES); - plugin.OnExpirationUpdate(cdmSessionId, kExpiryTimeInSeconds); - - cdmKeysStatus[kKeyId1] = wvcdm::kKeyStatusUsable; - cdmKeysStatus[kKeyId2] = wvcdm::kKeyStatusOutputNotAllowed; - cdmKeysStatus[kKeyId3] = wvcdm::kKeyStatusInternalError; - cdmKeysStatus[kKeyId4] = wvcdm::kKeyStatusPending; - cdmKeysStatus[kKeyId5] = wvcdm::kKeyStatusUsableInFuture; - plugin.OnSessionKeysChange(cdmSessionId, cdmKeysStatus, true); -} - -// TODO b/35325611 Fix this disabled test -TEST_F(WVDrmPluginTest, DISABLED_GeneratesProvisioningNeededEvent) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - sp> listener = - new StrictMock(); - - hidl_vec hEmptyData; - hidl_vec hSessionId; - hSessionId.setToExternal(sessionIdRaw, kSessionIdSize); - - EXPECT_CALL(*listener, - sendEvent(EventType::PROVISION_REQUIRED, hSessionId, hEmptyData)) - .Times(1); - - EXPECT_CALL(*cdm, OpenSession(StrEq("com.widevine"), _, _, _, _)) - .Times(AtLeast(1)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NEED_PROVISIONING))); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.setListener(listener); - - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::ERROR_DRM_NOT_PROVISIONED, status); - }); -} - -TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::OK, status); - }); - - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - EXPECT_FALSE(propertySet->use_privacy_mode()); - EXPECT_EQ(0u, propertySet->service_certificate().size()); - EXPECT_FALSE(propertySet->is_session_sharing_enabled()); - EXPECT_EQ(0u, propertySet->session_sharing_id()); - EXPECT_STREQ("", propertySet->app_id().c_str()); -} - -TEST_F(WVDrmPluginTest, CanSetAppId) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin queries for the security level - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillRepeatedly(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - // Test setting an empty string - Status status = - plugin.setPropertyString(hidl_string("appId"), hidl_string("")); - ASSERT_EQ(Status::OK, status); - - // Test setting an application id before a session is opened. - status = plugin.setPropertyString(hidl_string("appId"), hidl_string(kAppId)); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::OK, status); - }); - ASSERT_THAT(propertySet, NotNull()); - - // Verify application id is set correctly. - EXPECT_STREQ(kAppId.c_str(), propertySet->app_id().c_str()); - - // Test setting application id while session is opened, this should fail. - status = plugin.setPropertyString(hidl_string("appId"), hidl_string(kAppId)); - ASSERT_EQ(Status::ERROR_DRM_UNKNOWN, status); -} - -TEST_P(WVDrmPluginOriginTest, CanSetOrigin) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - OriginTestVariant params = GetParam(); - - // Provide expected mock behavior - { - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - // Provide expected behavior when plugin closes a session - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - // Note which mock calls we expect - EXPECT_CALL(*cdm, OpenSession(_, _, HasOrigin(params.expectedOrigin), _, _)) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - // Set the properties & run the test - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - if (!params.origin.empty()) { - ASSERT_EQ(Status::OK, plugin.setPropertyString(hidl_string("origin"), - hidl_string(params.origin))); - } - - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - EXPECT_EQ(Status::OK, status); - }); - // Test setting an origin while sessions are opened. This should fail. - EXPECT_NE(Status::OK, plugin.setPropertyString(hidl_string("origin"), - hidl_string(kOrigin))); - EXPECT_EQ(Status::OK, plugin.closeSession(toHidlVec(sessionId))); -} - -INSTANTIATE_TEST_CASE_P( - OriginTests, WVDrmPluginOriginTest, - Values(OriginTestVariant("No Origin", kEmptyString, EMPTY_ORIGIN), - OriginTestVariant("With an Origin", kOrigin, kOrigin.c_str()))); - -TEST_F(WVDrmPluginTest, CanSetSecurityLevel) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L3), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - // Test forcing L3 - Status status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("L3", propertySet->security_level().c_str()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test returning to L1 on an L3 device (Should Fail) - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L1")); - ASSERT_NE(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("L3", propertySet->security_level().c_str()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test returning to L1 on an L1 device - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L1")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test un-forcing a level (first forcing to L3 so we have something to reset) - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L3")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("L3", propertySet->security_level().c_str()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test nonsense (Should Fail) - status = plugin.setPropertyString(hidl_string("securityLevel"), - hidl_string("nonsense")); - ASSERT_NE(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_STREQ("", propertySet->security_level().c_str()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test attempting to force a level with a session open (Should Fail) - plugin.openSession([&](Status status, hidl_vec /* hSessionId */) { - ASSERT_EQ(Status::OK, status); - }); - status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L3")); - ASSERT_NE(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, CanSetPrivacyMode) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - - // Test turning on privacy mode - Status status = plugin.setPropertyString(hidl_string("privacyMode"), - hidl_string("enable")); - ASSERT_EQ(Status::OK, status); - EXPECT_TRUE(propertySet->use_privacy_mode()); - - // Test turning off privacy mode - status = plugin.setPropertyString(hidl_string("privacyMode"), - hidl_string("disable")); - ASSERT_EQ(Status::OK, status); - EXPECT_FALSE(propertySet->use_privacy_mode()); - - // Test nonsense (Should Fail) - status = plugin.setPropertyString(hidl_string("privacyMode"), - hidl_string("nonsense")); - ASSERT_NE(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, CanSetServiceCertificate) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - static const size_t kPrivacyCertSize = 256; - uint8_t privacyCertRaw[kPrivacyCertSize]; - - FILE* fp = fopen("/dev/urandom", "r"); - fread(privacyCertRaw, sizeof(uint8_t), kPrivacyCertSize, fp); - fclose(fp); - - std::vector privacyCert; - privacyCert.assign(privacyCertRaw, privacyCertRaw + kPrivacyCertSize); - std::string strPrivacyCert(reinterpret_cast(privacyCertRaw), - kPrivacyCertSize); - std::vector emptyVector; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - // Validate that the certificate is validated. Accept it once and reject it - // once. Note that there is no expected call for when the certificate is - // cleared. - EXPECT_CALL(*cdm, IsValidServiceCertificate(strPrivacyCert)) - .WillOnce(testing::Return(true)) - .WillOnce(testing::Return(false)); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - - // Test setting a certificate - Status status = plugin.setPropertyByteArray(hidl_string("serviceCertificate"), - toHidlVec(privacyCert)); - ASSERT_EQ(Status::OK, status); - EXPECT_THAT(propertySet->service_certificate(), - ElementsAreArray(privacyCertRaw, kPrivacyCertSize)); - - // Test clearing a certificate - status = plugin.setPropertyByteArray(hidl_string("serviceCertificate"), - toHidlVec(emptyVector)); - ASSERT_EQ(Status::OK, status); - EXPECT_EQ(0u, propertySet->service_certificate().size()); - - // Test setting a certificate and having it fail - status = plugin.setPropertyByteArray(hidl_string("serviceCertificate"), - toHidlVec(privacyCert)); - ASSERT_NE(Status::OK, status); - EXPECT_EQ(0u, propertySet->service_certificate().size()); -} - -TEST_F(WVDrmPluginTest, CanSetSessionSharing) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const CdmClientPropertySet* propertySet = nullptr; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - // Test turning on session sharing - Status status = plugin.setPropertyString(hidl_string("sessionSharing"), - hidl_string("enable")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_TRUE(propertySet->is_session_sharing_enabled()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test turning off session sharing - status = plugin.setPropertyString(hidl_string("sessionSharing"), - hidl_string("disable")); - ASSERT_EQ(Status::OK, status); - - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_FALSE(propertySet->is_session_sharing_enabled()); - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test nonsense (Should Fail) - status = plugin.setPropertyString(hidl_string("sessionSharing"), - hidl_string("nonsense")); - ASSERT_NE(Status::OK, status); - - // Test changing sharing with a session open (Should Fail) - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - status = plugin.setPropertyString(hidl_string("sessionSharing"), - hidl_string("enable")); - ASSERT_NE(Status::OK, status); - - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - CdmClientPropertySet* propertySet = nullptr; - - uint32_t sharingId; - FILE* fp = fopen("/dev/urandom", "r"); - fread(&sharingId, sizeof(uint32_t), 1, fp); - fclose(fp); - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - ASSERT_THAT(propertySet, NotNull()); - propertySet->set_session_sharing_id(sharingId); - EXPECT_EQ(sharingId, propertySet->session_sharing_id()); -} - -TEST_F(WVDrmPluginTest, CanSetAtscMode) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName = "com.test.package"; - - const CdmClientPropertySet* propertySet = nullptr; - CdmIdentifier cdmIdAtscModeNotSet; - CdmIdentifier cdmIdAtscModeSet; - CdmIdentifier cdmIdAtscModeReset; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillOnce(DoAll( - SetArgPointee<4>(cdmSessionId), SaveArg<1>(&propertySet), - SaveArg<2>(&cdmIdAtscModeNotSet), testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<4>(cdmSessionId), - SaveArg<1>(&propertySet), SaveArg<2>(&cdmIdAtscModeSet), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll( - SetArgPointee<4>(cdmSessionId), SaveArg<1>(&propertySet), - SaveArg<2>(&cdmIdAtscModeReset), testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin1(cdm.get(), appPackageName, &crypto, false); - - // Verify that ATSC mode is disabled by default - plugin1.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_FALSE(propertySet->use_atsc_mode()); - EXPECT_EQ(cdmIdAtscModeNotSet.app_package_name, appPackageName); - Status status = plugin1.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Verify that ATSC mode can be enabled - WVDrmPlugin plugin2(cdm.get(), appPackageName, &crypto, false); - - // Test turning on ATSC mode - status = - plugin2.setPropertyString(hidl_string("atscMode"), hidl_string("enable")); - ASSERT_EQ(Status::OK, status); - - plugin2.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_TRUE(propertySet->use_atsc_mode()); - EXPECT_EQ(cdmIdAtscModeSet.app_package_name, wvcdm::ATSC_APP_PACKAGE_NAME); - status = plugin2.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Verify that ATSC mode can be enabled and disabled - WVDrmPlugin plugin3(cdm.get(), appPackageName, &crypto, false); - - // Test turning on ATSC mode - status = - plugin3.setPropertyString(hidl_string("atscMode"), hidl_string("enable")); - ASSERT_EQ(Status::OK, status); - - // Test turning off ATSC mode - status = plugin3.setPropertyString(hidl_string("atscMode"), - hidl_string("disable")); - ASSERT_EQ(Status::OK, status); - - plugin3.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - ASSERT_THAT(propertySet, NotNull()); - EXPECT_FALSE(propertySet->use_atsc_mode()); - EXPECT_EQ(cdmIdAtscModeReset.app_package_name, appPackageName); - status = plugin3.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); - - // Test turning on and off ATSC mode. They should be rejected since the SPOID - // has been calculated - status = - plugin3.setPropertyString(hidl_string("atscMode"), hidl_string("enable")); - ASSERT_NE(Status::OK, status); - - status = plugin3.setPropertyString(hidl_string("atscMode"), - hidl_string("disable")); - ASSERT_NE(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, CanSetDecryptHashProperties) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - hidl_vec hSessionId; - hSessionId.setToExternal(sessionIdRaw, kSessionIdSize); - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - // CDM expects the string property value to be in the following format: - // ",," - static const std::string frameNumber = ",1"; - uint32_t hash = 0xbeef; // crc32 hash - const std::vector hashVector( - reinterpret_cast(&hash), - reinterpret_cast(&hash) + sizeof(uint32_t)); - const std::string base64EncodedHash = wvutil::Base64Encode(hashVector); - std::string computedHash(sessionId.begin(), sessionId.end()); - computedHash.append(frameNumber.c_str()); - computedHash.append(base64EncodedHash.c_str()); - Status status = plugin.setPropertyString(hidl_string("decryptHash"), - hidl_string(computedHash)); - ASSERT_NE(Status::OK, status); - - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, DoesNotSetDecryptHashProperties) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - // Provide expected mock behavior - { - // Provide expected behavior in response to OpenSession and store the - // property set - EXPECT_CALL(*cdm, OpenSession(_, _, _, _, _)) - .WillRepeatedly(DoAll(SetArgPointee<4>(cdmSessionId), - testing::Return(wvcdm::NO_ERROR))); - - // Provide expected behavior when plugin requests session control info - EXPECT_CALL(*cdm, QueryOemCryptoSessionId(cdmSessionId, _)) - .WillRepeatedly(Invoke(setSessionIdOnMap<4>)); - - EXPECT_CALL(*cdm, CloseSession(_)).Times(AtLeast(0)); - } - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - hidl_vec hSessionId; - hSessionId.setToExternal(sessionIdRaw, kSessionIdSize); - plugin.openSession([&](Status status, hidl_vec hSessionId) { - ASSERT_EQ(Status::OK, status); - sessionId.clear(); - sessionId.assign(hSessionId.data(), hSessionId.data() + hSessionId.size()); - }); - - // CDM expects the string property value to be in the following format: - // ",," - static const std::string frameNumber = ",1"; - static const std::string hash = ",AZaz0+,/"; - std::string value(sessionId.begin(), sessionId.end()); - value.append(frameNumber.c_str()); - - // Tests for missing token handling - Status status = - plugin.setPropertyString(hidl_string("decryptHash"), hidl_string(value)); - EXPECT_NE(Status::OK, status); - - // Tests for empty token - value.append(","); - status = - plugin.setPropertyString(hidl_string("decryptHash"), hidl_string(value)); - EXPECT_NE(Status::OK, status); - - // Tests for invalid sessionId - value.clear(); - value.append("bad session id"); - value.append(",1"); - value.append(hash.c_str()); - status = - plugin.setPropertyString(hidl_string("decryptHash"), hidl_string(value)); - EXPECT_NE(Status::OK, status); - - // Tests for malformed Base64encode hash, with a "," - std::string computedHash(sessionId.begin(), sessionId.end()); - computedHash.append(frameNumber.c_str()); - computedHash.append(hash.c_str()); - status = plugin.setPropertyString(hidl_string("decryptHash"), - hidl_string(computedHash)); - EXPECT_NE(Status::OK, status); - - status = plugin.closeSession(toHidlVec(sessionId)); - ASSERT_EQ(Status::OK, status); -} - -TEST_F(WVDrmPluginTest, GetOfflineLicenseIds) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - const uint32_t kLicenseCount = 5; - - uint8_t mockIdsRaw[kLicenseCount * 2][kKeySetIdSize]; - FILE* fp = fopen("/dev/urandom", "r"); - for (uint32_t i = 0; i < kLicenseCount * 2; ++i) { - fread(mockIdsRaw[i], sizeof(uint8_t), kKeySetIdSize, fp); - } - fclose(fp); - - std::vector mockIdsL1; - for (uint32_t i = 0; i < kLicenseCount; ++i) { - mockIdsL1.push_back( - std::string(mockIdsRaw[i], mockIdsRaw[i] + kKeySetIdSize)); - } - - std::vector mockIdsL3; - for (uint32_t i = 0; i < kLicenseCount; ++i) { - mockIdsL3.push_back( - std::string(mockIdsRaw[i + 5], mockIdsRaw[i + 5] + kKeySetIdSize)); - } - - EXPECT_CALL(*cdm, - ListStoredLicenses(kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN), _)) - .WillOnce( - DoAll(SetArgPointee<2>(mockIdsL1), testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, - ListStoredLicenses(kSecurityLevelL3, HasOrigin(EMPTY_ORIGIN), _)) - .WillOnce( - DoAll(SetArgPointee<2>(mockIdsL3), testing::Return(wvcdm::NO_ERROR))); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - std::vector> offlineIds; - offlineIds.clear(); - plugin.getOfflineLicenseKeySetIds( - [&](Status status, hidl_vec hKeySetIds) { - ASSERT_EQ(Status::OK, status); - - std::vector ids(hKeySetIds); - - for (auto id : ids) { - offlineIds.push_back(id); - } - }); - - size_t index = 0; - for (auto id : offlineIds) { - EXPECT_THAT(id, ElementsAreArray(mockIdsRaw[index++], kKeySetIdSize)); - } - EXPECT_EQ(kLicenseCount * 2, index); -} - -TEST_F(WVDrmPluginTest, GetOfflineLicenseState) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL(*cdm, QueryStatus(_, QUERY_KEY_SECURITY_LEVEL, _)) - .WillRepeatedly(DoAll(SetArgPointee<2>(QUERY_VALUE_SECURITY_LEVEL_L1), - testing::Return(wvcdm::NO_ERROR))); - - EXPECT_CALL(*cdm, GetOfflineLicenseState(_, kSecurityLevelL1, - HasOrigin(EMPTY_ORIGIN), _)) - .WillOnce(DoAll(SetArgPointee<3>(wvcdm::kLicenseStateActive), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<3>(wvcdm::kLicenseStateReleasing), - testing::Return(wvcdm::NO_ERROR))) - .WillOnce(DoAll(SetArgPointee<3>(wvcdm::kLicenseStateUnknown), - testing::Return(wvcdm::NO_ERROR))); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - Status status = - plugin.setPropertyString(hidl_string("securityLevel"), hidl_string("L1")); - ASSERT_EQ(Status::OK, status); - - plugin.getOfflineLicenseState( - toHidlVec(keySetId), - [&](Status status, OfflineLicenseState hLicenseState) { - ASSERT_EQ(Status::OK, status); - ASSERT_EQ(OfflineLicenseState::USABLE, hLicenseState); - }); - - plugin.getOfflineLicenseState( - toHidlVec(keySetId), - [&](Status status, OfflineLicenseState hLicenseState) { - ASSERT_EQ(Status::OK, status); - ASSERT_EQ(OfflineLicenseState::INACTIVE, hLicenseState); - }); - - plugin.getOfflineLicenseState( - toHidlVec(keySetId), - [&](Status status, OfflineLicenseState hLicenseState) { - ASSERT_EQ(Status::OK, status); - ASSERT_EQ(OfflineLicenseState::UNKNOWN, hLicenseState); - }); -} - -TEST_F(WVDrmPluginTest, RemoveOfflineLicense) { - android::sp> cdm = new StrictMock(); - StrictMock crypto; - std::string appPackageName; - - EXPECT_CALL( - *cdm, RemoveOfflineLicense(_, kSecurityLevelL1, HasOrigin(EMPTY_ORIGIN))) - .Times(1); - - WVDrmPlugin plugin(cdm.get(), appPackageName, &crypto, false); - - Status status = plugin.removeOfflineLicense(toHidlVec(keySetId)); - ASSERT_EQ(Status::OK, status); -} - -} // namespace widevine -} // namespace V1_4 -} // namespace drm -} // namespace hardware -} // namespace wvdrm diff --git a/libwvdrmengine/mediadrm/test/hidl/hidl_metrics_adapter_unittest.cpp b/libwvdrmengine/mediadrm/test/hidl/hidl_metrics_adapter_unittest.cpp deleted file mode 100644 index ef43174c..00000000 --- a/libwvdrmengine/mediadrm/test/hidl/hidl_metrics_adapter_unittest.cpp +++ /dev/null @@ -1,459 +0,0 @@ -// -// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary -// source code may only be used and distributed under the Widevine License -// Agreement. -// - -// This file contains unit tests for the HidlMetricsAdapter. - -#include "hidl_metrics_adapter.h" - -#include -#include -#include - -#include "gtest/gtest.h" -#include "wv_metrics.pb.h" - -using android::hardware::hidl_vec; -using android::hardware::drm::V1_1::DrmMetricGroup; -using drm_metrics::CounterMetric; -using drm_metrics::DistributionMetric; - -namespace { - -template -std::string ToString(const T& attribute_or_value) { - std::ostringstream os; - switch (attribute_or_value.type) { - case DrmMetricGroup::ValueType::DOUBLE_TYPE: - os << "DOUBLE_TYPE. value: " << attribute_or_value.doubleValue; - break; - case DrmMetricGroup::ValueType::INT64_TYPE: - os << "INT64_TYPE. value: " << attribute_or_value.int64Value; - break; - case DrmMetricGroup::ValueType::STRING_TYPE: - os << "STRING_TYPE. value: " << attribute_or_value.stringValue; - break; - default: - os << "UNKNOWN TYPE!!: " << (int64_t) attribute_or_value.type; - break; - } - os << " (" << attribute_or_value.int64Value << "," - << attribute_or_value.doubleValue << ",\"" - << attribute_or_value.stringValue << "\")"; - return os.str(); -} - -std::string ToString(const DrmMetricGroup::Metric& metric) { - std::ostringstream os; - os << "metric: " << metric.name << std::endl; - os << " attributes:" << std::endl; - for (unsigned a = 0; a < metric.attributes.size(); a++) { - os << " " << metric.attributes[a].name << ". " - << ToString(metric.attributes[a]) << std::endl; - } - os << " values:" << std::endl; - for (unsigned v = 0; v < metric.values.size(); v++) { - os << " " << metric.values[v].componentName << ". " - << ToString(metric.values[v]) << std::endl; - } - return os.str(); -} - -std::string ToString(const hidl_vec& metrics_vector) { - std::ostringstream os; - os << "hidl metrics..." << std::endl; - os << "group count: " << metrics_vector.size() << std::endl; - for (unsigned g = 0; g < metrics_vector.size(); g++) { - os << "group " << g << ". metric count: " - << metrics_vector[g].metrics.size() << std::endl; - for (unsigned m = 0; m < metrics_vector[g].metrics.size(); m++) { - const DrmMetricGroup::Metric metric = metrics_vector[g].metrics[m]; - os << ToString(metric); - } - } - return os.str(); -} - -bool HasMetric(const DrmMetricGroup::Metric& expected, - const DrmMetricGroup& actual_metrics) { - DrmMetricGroup::Metric metric; - auto it = std::find(actual_metrics.metrics.begin(), - actual_metrics.metrics.end(), expected); - if (it == actual_metrics.metrics.end()) { - ALOGE("COULDN'T FIND THE METRIC! %s", ToString(expected).c_str()); - for (auto it = actual_metrics.metrics.begin(); - it < actual_metrics.metrics.end(); it++) { - if (expected.name == it->name) { - ALOGE("Names match."); - } - if (expected.attributes == it->attributes) { - ALOGE("attributes match."); - } - if (expected.values == it->values) { - ALOGE("values match."); - } else { - ALOGE("values length match? %zu, %zu", - expected.values.size(), it->values.size()); - if (expected.values.size() == it->values.size()) { - for (unsigned int i = 0; i < expected.values.size(); i++) { - ALOGE("value %u match? %d", i, expected.values[i] == it->values[i]); - if (expected.values[i] != it->values[i]) { - ALOGE("value component mismatch. %u. %s, %s", - i, expected.values[i].componentName.c_str(), - it->values[i].componentName.c_str()); - } - } - } - } - } - } else { - ALOGE("Found metric: %s", ToString(*it).c_str()); - } - return it != actual_metrics.metrics.end(); -} - -} // anonymous namespace - -namespace wvcdm { - -TEST(HidlMetricsAdapterTest, EmptyMetrics) { - drm_metrics::WvCdmMetrics metrics_proto; - hidl_vec hidl_metrics; - - HidlMetricsAdapter::ToHidlMetrics(metrics_proto, &hidl_metrics); - ASSERT_EQ(0U, hidl_metrics.size()) << ToString(hidl_metrics); -} - -// Adds a metric from each type - Value, counter and distribution. -TEST(HidlMetricsAdapterTest, AllMetricTypes) { - drm_metrics::WvCdmMetrics metrics_proto; - - // Value metric - error. - metrics_proto - .mutable_engine_metrics() - ->mutable_crypto_metrics() - ->mutable_crypto_session_security_level() - ->set_error_code(7); - DrmMetricGroup::Metric expected_value_metric_1 = { - "crypto_session_security_level", - {}, - { { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, 7, 0, "" } } - }; - - // Value metric - integer. - metrics_proto - .mutable_engine_metrics() - ->mutable_oemcrypto_initialization_mode() - ->set_int_value(11); - DrmMetricGroup::Metric expected_value_metric_2 = { - "oemcrypto_initialization_mode", - {}, - { { "value", DrmMetricGroup::ValueType::INT64_TYPE, 11, 0, "" } } - }; - - // Value metric - double. - metrics_proto - .mutable_engine_metrics() - ->mutable_cdm_engine_life_span_ms() - ->set_double_value(3.14159); - DrmMetricGroup::Metric expected_value_metric_3 = { - "cdm_engine_life_span_ms", - {}, - { { "value", DrmMetricGroup::ValueType::DOUBLE_TYPE, 0, 3.14159, "" } } - }; - - // Value metric - string. - metrics_proto - .mutable_engine_metrics() - ->mutable_cdm_engine_cdm_version() - ->set_string_value("test"); - DrmMetricGroup::Metric expected_value_metric_4 = { - "cdm_engine_cdm_version", - {}, - { { "value", DrmMetricGroup::ValueType::STRING_TYPE, 0, 0, "test" } } - }; - - // Counter metric - CounterMetric* counter = metrics_proto.mutable_engine_metrics() - ->mutable_crypto_metrics()->add_crypto_session_get_token(); - counter->set_count(13); - counter->mutable_attributes()->set_error_code(17); - DrmMetricGroup::Metric expected_counter_metric_1 = { - "crypto_session_get_token", - { { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, 17, 0, "" } }, - { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 13, 0, "" } } - }; - // Add a second counter. - counter = metrics_proto.mutable_engine_metrics() - ->mutable_crypto_metrics()->add_crypto_session_get_token(); - counter->set_count(19); - counter->mutable_attributes()->set_error_code(23); - DrmMetricGroup::Metric expected_counter_metric_2 = { - "crypto_session_get_token", - { { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, 23, 0, "" } }, - { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 19, 0, "" } } - }; - - // Distribution metric - DistributionMetric* distribution = metrics_proto.mutable_engine_metrics() - ->mutable_crypto_metrics()->add_crypto_session_open_time_us(); - distribution->set_min(1.0); - distribution->set_max(1.2); - distribution->set_mean(1.1); - distribution->set_variance(.01); - distribution->set_operation_count(2); - distribution->mutable_attributes()->set_error_code(0); - DrmMetricGroup::Metric expected_distribution_metric_1 = { - "crypto_session_open_time_us", - { { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, 0, 0, "" } }, - { { "mean", DrmMetricGroup::ValueType::DOUBLE_TYPE, 0, 1.1f, "" }, - { "count", DrmMetricGroup::ValueType::INT64_TYPE, 2, 0, "" }, - { "min", DrmMetricGroup::ValueType::DOUBLE_TYPE, 0, 1.0, "" }, - { "max", DrmMetricGroup::ValueType::DOUBLE_TYPE, 0, 1.2f, "" }, - { "variance", DrmMetricGroup::ValueType::DOUBLE_TYPE, 0, 0.01, "" } } - }; - // Add a second distribution - distribution = metrics_proto.mutable_engine_metrics() - ->mutable_crypto_metrics()->add_crypto_session_open_time_us(); - distribution->set_mean(0.7); - distribution->set_operation_count(1); - distribution->mutable_attributes()->set_error_code(27); - DrmMetricGroup::Metric expected_distribution_metric_2 = { - "crypto_session_open_time_us", - { { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, 27, 0, "" } }, - { { "mean", DrmMetricGroup::ValueType::DOUBLE_TYPE, 0, 0.7f, "" }, - { "count", DrmMetricGroup::ValueType::INT64_TYPE, 1, 0, "" } } - }; - - hidl_vec hidl_metrics; - - HidlMetricsAdapter::ToHidlMetrics(metrics_proto, &hidl_metrics); - ASSERT_EQ(1U, hidl_metrics.size()); - ASSERT_EQ(8U, hidl_metrics[0].metrics.size()) << ToString(hidl_metrics); - - EXPECT_TRUE(HasMetric(expected_value_metric_1, hidl_metrics[0])) - << "Missing value_metric_1. " << ToString(expected_value_metric_1) - << std::endl << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_value_metric_2, hidl_metrics[0])) - << "Missing value_metric_2. " << ToString(expected_value_metric_2) - << std::endl << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_value_metric_3, hidl_metrics[0])) - << "Missing value_metric_3." << ToString(expected_value_metric_3) - << std::endl << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_value_metric_4, hidl_metrics[0])) - << "Missing value_metric_4. " << ToString(expected_value_metric_4) - << std::endl << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_counter_metric_1, hidl_metrics[0])) - << "Missing counter_metric_1. " << ToString(expected_counter_metric_1) - << std::endl << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_counter_metric_2, hidl_metrics[0])) - << "Missing counter_metric_2. " << ToString(expected_counter_metric_2) - << std::endl << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_distribution_metric_1, hidl_metrics[0])) - << "Missing distribution_metric_1. " - << ToString(expected_distribution_metric_1) << std::endl - << "In metrics: " << ToString(hidl_metrics); - EXPECT_TRUE(HasMetric(expected_distribution_metric_2, hidl_metrics[0])) - << "Missing distribution_metric_2. " - << ToString(expected_distribution_metric_2) << std::endl - << "In metrics: " << ToString(hidl_metrics); -} - -// Add a single metric with all attributes to confirm that all attributes -// can be converted. -TEST(HidlMetricsAdapterTest, AddAllAttrbitues) { - // Create a test attribute proto with all attributes set. - drm_metrics::WvCdmMetrics metrics_proto; - CounterMetric* counter = metrics_proto.mutable_engine_metrics() - ->mutable_crypto_metrics()->add_crypto_session_get_token(); - counter->set_count(13); - drm_metrics::Attributes* attributes = counter->mutable_attributes(); - attributes->set_error_code(17); - attributes->set_error_code_bool(true); - attributes->set_cdm_security_level(19); - attributes->set_security_level(23); - attributes->set_length(29); - attributes->set_encryption_algorithm(31); - attributes->set_signing_algorithm(37); - attributes->set_oem_crypto_result(41); - attributes->set_key_status_type(43); - attributes->set_event_type(47); - attributes->set_key_request_type(53); - attributes->set_license_type(59); - - DrmMetricGroup::Metric expected_counter_metric = { - "crypto_session_get_token", - { { "error_code", DrmMetricGroup::ValueType::INT64_TYPE, 17, 0, "" }, - { "error_code_bool", - DrmMetricGroup::ValueType::INT64_TYPE, true, 0, "" }, - { "cdm_security_level", - DrmMetricGroup::ValueType::INT64_TYPE, 19, 0, "" }, - { "security_level", - DrmMetricGroup::ValueType::INT64_TYPE, 23, 0, "" }, - { "length", DrmMetricGroup::ValueType::INT64_TYPE, 29, 0, "" }, - { "encryption_algorithm", - DrmMetricGroup::ValueType::INT64_TYPE, 31, 0, "" }, - { "signing_algorithm", - DrmMetricGroup::ValueType::INT64_TYPE, 37, 0, "" }, - { "oem_crypto_result", - DrmMetricGroup::ValueType::INT64_TYPE, 41, 0, "" }, - { "key_status_type", - DrmMetricGroup::ValueType::INT64_TYPE, 43, 0, "" }, - { "event_type", DrmMetricGroup::ValueType::INT64_TYPE, 47, 0, "" }, - { "key_request_type", - DrmMetricGroup::ValueType::INT64_TYPE, 53, 0, "" }, - { "license_type", - DrmMetricGroup::ValueType::INT64_TYPE, 59, 0, "" } }, - { { "count", DrmMetricGroup::ValueType::INT64_TYPE, 13, 0, "" } } }; - - // Confirm that all of the attributes exist in the hidl data. - hidl_vec hidl_metrics; - HidlMetricsAdapter::ToHidlMetrics(metrics_proto, &hidl_metrics); - EXPECT_TRUE(HasMetric(expected_counter_metric, hidl_metrics[0])) - << "Missing expected_counter_metrc. " - << ToString(expected_counter_metric) << std::endl - << "In metrics: " << ToString(hidl_metrics); -} - -// Add all session and engine metrics to cofirm that all are converted. -// Only check the counts since other tests confirm that metrics are converted -// properly. -TEST(HidlMetricsAdapterTest, EngineAndSessionAllMetrics) { - // Set all CryptoSession metrics. - drm_metrics::WvCdmMetrics::CryptoMetrics crypto_metrics; - crypto_metrics.mutable_crypto_session_security_level()->set_int_value(1); - crypto_metrics.add_crypto_session_delete_all_usage_reports()->set_count(13); - crypto_metrics.add_crypto_session_delete_multiple_usage_information - ()->set_count(13); - crypto_metrics.add_crypto_session_generic_decrypt_time_us()->set_min(1.0f); - crypto_metrics.add_crypto_session_generic_encrypt_time_us()->set_min(1.0f); - crypto_metrics.add_crypto_session_generic_sign_time_us()->set_min(1.0f); - crypto_metrics.add_crypto_session_generic_verify_time_us()->set_min(1.0f); - crypto_metrics.add_crypto_session_get_device_unique_id()->set_count(13); - crypto_metrics.add_crypto_session_get_token()->set_count(13); - crypto_metrics.mutable_crypto_session_life_span()->set_int_value(1); - crypto_metrics.add_crypto_session_load_certificate_private_key_time_us - ()->set_min(1.0f); - crypto_metrics.add_crypto_session_open_time_us()->set_min(1.0f); - crypto_metrics.mutable_crypto_session_system_id()->set_int_value(1); - crypto_metrics.add_crypto_session_update_usage_information_time_us - ()->set_min(1.0f); - crypto_metrics.mutable_crypto_session_usage_information_support - ()->set_int_value(1); - - // Usage Table Metrics - crypto_metrics.mutable_usage_table_header_initial_size()->set_int_value(1); - crypto_metrics.add_usage_table_header_add_entry()->set_count(13); - crypto_metrics.add_usage_table_header_delete_entry()->set_count(13); - crypto_metrics.add_usage_table_header_update_entry_time_us()->set_min(1.0f); - crypto_metrics.add_usage_table_header_load_entry()->set_count(13); - - // OemCrypto metrics. - crypto_metrics.mutable_oemcrypto_api_version()->set_int_value(1); - crypto_metrics.add_oemcrypto_close_session()->set_count(13); - crypto_metrics.add_oemcrypto_copy_buffer_time_us()->set_min(1.0f); - crypto_metrics.mutable_oemcrypto_current_hdcp_capability()->set_int_value(1); - crypto_metrics.add_oemcrypto_deactivate_usage_entry()->set_count(13); - crypto_metrics.add_oemcrypto_decrypt_cenc_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_delete_usage_entry()->set_count(13); - crypto_metrics.add_oemcrypto_delete_usage_table()->set_count(13); - crypto_metrics.add_oemcrypto_derive_keys_from_session_key_time_us - ()->set_min(1.0f); - crypto_metrics.add_oemcrypto_force_delete_usage_entry()->set_count(13); - crypto_metrics.add_oemcrypto_generate_derived_keys_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_generate_nonce()->set_count(13); - crypto_metrics.add_oemcrypto_generate_rsa_signature_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_generate_signature_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_generic_decrypt_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_generic_encrypt_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_generic_sign_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_generic_verify_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_get_device_id()->set_count(13); - crypto_metrics.add_oemcrypto_get_key_data_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_get_oem_public_certificate()->set_count(13); - crypto_metrics.add_oemcrypto_get_random()->set_count(13); - crypto_metrics.add_oemcrypto_initialize_time_us()->set_min(1.0f); - crypto_metrics.mutable_oemcrypto_is_anti_rollback_hw_present - ()->set_int_value(1); - crypto_metrics.mutable_oemcrypto_is_keybox_valid()->set_int_value(1); - crypto_metrics.add_oemcrypto_load_device_drm_key_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_load_entitled_keys_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_load_keys_time_us()->set_min(1.0f); - crypto_metrics.mutable_oemcrypto_max_hdcp_capability()->set_int_value(1); - crypto_metrics.mutable_oemcrypto_max_number_of_sessions()->set_int_value(1); - crypto_metrics.mutable_oemcrypto_number_of_open_sessions()->set_int_value(1); - crypto_metrics.mutable_oemcrypto_provisioning_method()->set_int_value(1); - crypto_metrics.add_oemcrypto_refresh_keys_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_report_usage()->set_count(13); - crypto_metrics.add_oemcrypto_rewrap_device_rsa_key_time_us()->set_min(1.0f); - crypto_metrics.add_oemcrypto_rewrap_device_rsa_key_30_time_us() - ->set_min(1.0f); - crypto_metrics.mutable_oemcrypto_security_patch_level()->set_int_value(1); - crypto_metrics.add_oemcrypto_select_key_time_us()->set_min(1.0f); - crypto_metrics.mutable_oemcrypto_usage_table_support()->set_int_value(1); - crypto_metrics.add_oemcrypto_update_usage_table()->set_count(13); - crypto_metrics.add_oemcrypto_update_usage_entry()->set_count(13); - - drm_metrics::WvCdmMetrics::SessionMetrics session_metrics; - session_metrics.mutable_session_id()->set_string_value("test"); - *(session_metrics.mutable_crypto_metrics()) = crypto_metrics; - session_metrics.mutable_cdm_session_life_span_ms()->set_double_value(1.0f); - session_metrics.add_cdm_session_renew_key_time_us()->set_min(1.0f); - session_metrics.add_cdm_session_restore_offline_session()->set_count(13); - session_metrics.add_cdm_session_restore_usage_session()->set_count(13); - session_metrics.add_cdm_session_license_request_latency_ms()->set_min(1.0); - session_metrics.mutable_oemcrypto_build_info()->set_string_value("test"); - session_metrics.mutable_license_sdk_version()->set_string_value("test sdk"); - session_metrics.mutable_license_service_version()->set_string_value("test service"); - - drm_metrics::WvCdmMetrics::EngineMetrics engine_metrics; - *(engine_metrics.mutable_crypto_metrics()) = crypto_metrics; - // OEMCrypto Initialize Metrics. - engine_metrics.mutable_level3_oemcrypto_initialization_error() - ->set_int_value(1); - engine_metrics.mutable_oemcrypto_initialization_mode()->set_int_value(1); - engine_metrics.mutable_previous_oemcrypto_initialization_failure() - ->set_int_value(1); - engine_metrics.mutable_oemcrypto_l1_api_version()->set_int_value(1); - engine_metrics.mutable_oemcrypto_l1_min_api_version()->set_int_value(1); - // CdmEngine Metrics. - engine_metrics.mutable_app_package_name()->set_int_value(1); - engine_metrics.add_cdm_engine_add_key_time_us()->set_min(1.0f); - engine_metrics.mutable_cdm_engine_cdm_version()->set_int_value(1); - engine_metrics.add_cdm_engine_close_session()->set_count(13); - engine_metrics.mutable_cdm_engine_creation_time_millis()->set_int_value(1); - engine_metrics.add_cdm_engine_decrypt_time_us()->set_min(1.0f); - engine_metrics.add_cdm_engine_find_session_for_key()->set_count(13); - engine_metrics.add_cdm_engine_generate_key_request_time_us()->set_min(1.0f); - engine_metrics.add_cdm_engine_get_provisioning_request_time_us() - ->set_min(1.0f); - engine_metrics.add_cdm_engine_get_secure_stop_ids()->set_count(13); - engine_metrics.add_cdm_engine_get_usage_info_time_us()->set_min(1.0f); - engine_metrics.add_cdm_engine_handle_provisioning_response_time_us() - ->set_min(1.0f); - engine_metrics.mutable_cdm_engine_life_span_ms()->set_int_value(1); - engine_metrics.add_cdm_engine_open_key_set_session()->set_count(13); - engine_metrics.add_cdm_engine_open_session()->set_count(13); - engine_metrics.add_cdm_engine_query_key_status_time_us()->set_min(1.0f); - engine_metrics.add_cdm_engine_release_all_usage_info()->set_count(13); - engine_metrics.add_cdm_engine_release_usage_info()->set_count(13); - engine_metrics.add_cdm_engine_remove_all_usage_info()->set_count(13); - engine_metrics.add_cdm_engine_remove_keys()->set_count(13); - engine_metrics.add_cdm_engine_remove_usage_info()->set_count(13); - engine_metrics.add_cdm_engine_restore_key_time_us()->set_min(1.0f); - engine_metrics.add_cdm_engine_unprovision()->set_count(13); - - drm_metrics::WvCdmMetrics metrics_proto; - *(metrics_proto.add_session_metrics()) = session_metrics; - *(metrics_proto.mutable_engine_metrics()) = engine_metrics; - - hidl_vec hidl_metrics; - HidlMetricsAdapter::ToHidlMetrics(metrics_proto, &hidl_metrics); - ASSERT_EQ(2U, hidl_metrics.size()); - EXPECT_EQ(89U, hidl_metrics[0].metrics.size()) << ToString(hidl_metrics); - EXPECT_EQ(70U, hidl_metrics[1].metrics.size()) << ToString(hidl_metrics); -} - -} // namespace wvcdm diff --git a/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c b/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c new file mode 100644 index 00000000..37e577e6 --- /dev/null +++ b/libwvdrmengine/oemcrypto/test/GEN_api_lock_file.c @@ -0,0 +1,306 @@ +// Copyright 2019 Google LLC. All Rights Reserved. This file and proprietary +// source code may only be used and distributed under the Widevine License +// Agreement. +// +// This code is semi-auto-generated, do not edit unless you know what you are +// doing. The script oemcrypto/lock-api-for-release will append to this file. +// +// If this file does not build, then you have modified an OEMCrypto API +// function. Instead, you should rename the old function and give the modified +// function a new oecc number. + +#include "OEMCryptoCENC.h" + +// This initial generation of this file was for v16.4, so older functions will +// not have an accurate version number. + +OEMCryptoResult _oecc84(const uint8_t* sandbox_id, size_t sandbox_id_length); +OEMCryptoResult _oecc01(void); +OEMCryptoResult _oecc02(void); +OEMCryptoResult _oecc09(OEMCrypto_SESSION* session); +OEMCryptoResult _oecc10(OEMCrypto_SESSION session); +OEMCryptoResult _oecc95(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* mac_key_context, + size_t mac_key_context_length, + const OEMCrypto_SharedMemory* enc_key_context, + size_t enc_key_context_length); +OEMCryptoResult _oecc21(OEMCrypto_SESSION session, + const uint8_t* derivation_key, + size_t derivation_key_length, + const OEMCrypto_SharedMemory* mac_key_context, + size_t mac_key_context_length, + const OEMCrypto_SharedMemory* enc_key_context, + size_t enc_key_context_length); +OEMCryptoResult _oecc14(OEMCrypto_SESSION session, uint32_t* nonce); +OEMCryptoResult _oecc96(OEMCrypto_SESSION session, uint8_t* message, + size_t message_length, size_t* core_message_size, + uint8_t* signature, size_t* signature_length); +OEMCryptoResult _oecc97(OEMCrypto_SESSION session, uint8_t* message, + size_t message_length, size_t* core_message_size, + uint8_t* signature, size_t* signature_length); +OEMCryptoResult _oecc98(OEMCrypto_SESSION session, uint8_t* message, + size_t message_length, size_t* core_message_size, + uint8_t* signature, size_t* signature_length); +OEMCryptoResult _oecc55(const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc83( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + const uint8_t* signature, size_t signature_length, + OEMCrypto_Substring enc_mac_keys_iv, OEMCrypto_Substring enc_mac_keys, + size_t key_array_length, const OEMCrypto_KeyObject* key_array, + OEMCrypto_Substring pst, OEMCrypto_Substring srm_restriction_data, + OEMCrypto_LicenseType license_type); +OEMCryptoResult _oecc99(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length); +OEMCryptoResult _oecc92( + OEMCrypto_SESSION session, const uint8_t* message, size_t message_length, + size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject_V16* key_array); +OEMCryptoResult _oecc91(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); +OEMCryptoResult _oecc101(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length); +OEMCryptoResult _oecc41(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + uint8_t* key_control_block, + size_t* key_control_block_length); +OEMCryptoResult _oecc81(OEMCrypto_SESSION session, + const uint8_t* content_key_id, + size_t content_key_id_length, + OEMCryptoCipherMode cipher_mode); +OEMCryptoResult _oecc105( + OEMCrypto_SESSION session, + const OEMCrypto_SampleDescription* samples, // an array of samples. + size_t samples_length, // the number of samples. + const OEMCrypto_CENCEncryptPatternDesc* pattern); +OEMCryptoResult _oecc93(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* data_addr, + size_t data_addr_length, + const OEMCrypto_DestBufferDesc* out_buffer_descriptor, + uint8_t subsample_flags); +OEMCryptoResult _oecc24(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); +OEMCryptoResult _oecc25(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* in_buffer, + size_t in_buffer_length, const uint8_t* iv, + OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* out_buffer); +OEMCryptoResult _oecc26(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + OEMCrypto_SharedMemory* signature, + size_t* signature_length); +OEMCryptoResult _oecc27(OEMCrypto_SESSION session, + const OEMCrypto_SharedMemory* buffer, + size_t buffer_length, OEMCrypto_Algorithm algorithm, + const OEMCrypto_SharedMemory* signature, + size_t signature_length); +OEMCryptoResult _oecc08(const uint8_t* keybox_or_cert, + size_t keybox_or_cert_length, + uint8_t* wrapped_keybox_or_cert, + size_t* wrapped_keybox_or_cert_length, + const uint8_t* transport_key, + size_t transport_key_length); +OEMCryptoResult _oecc03(const uint8_t* keybox_or_cert, + size_t keybox_or_cert_length); +OEMCrypto_ProvisioningMethod _oecc49(void); +OEMCryptoResult _oecc05(void); +OEMCryptoResult _oecc07(uint8_t* device_id, size_t* device_id_length); +OEMCryptoResult _oecc04(uint8_t* key_data, size_t* key_data_length); +OEMCryptoResult _oecc78(const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc103(OEMCrypto_SESSION session); +OEMCryptoResult _oecc104(uint8_t* public_cert, size_t* public_cert_length); +OEMCryptoResult _oecc06(uint8_t* random_data, size_t random_data_length); +uint32_t _oecc22(void); +uint32_t _oecc108(void); +uint8_t _oecc46(void); +OEMCryptoResult _oecc44(OEMCrypto_HDCP_Capability* current, + OEMCrypto_HDCP_Capability* maximum); +bool _oecc29(void); +size_t _oecc94(void); +bool _oecc39(void); +OEMCryptoResult _oecc38(size_t* count); +OEMCryptoResult _oecc37(size_t* max); +uint32_t _oecc52(void); +bool _oecc53(void); +OEMCryptoResult _oecc54(uint16_t* version); +uint32_t _oecc71(void); +uint32_t _oecc85(void); +OEMCryptoResult _oecc102(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t core_message_length, + const uint8_t* signature, size_t signature_length, + uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length); +OEMCryptoResult _oecc107(OEMCrypto_SESSION session, + OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, + size_t wrapped_private_key_length); +OEMCryptoResult _oecc45(void); +OEMCryptoResult _oecc36(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length, + RSA_Padding_Scheme padding_scheme); +OEMCryptoResult _oecc61(uint8_t* header_buffer, size_t* header_buffer_length); +OEMCryptoResult _oecc62(const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc63(OEMCrypto_SESSION session, + uint32_t* usage_entry_number); +OEMCryptoResult _oecc64(OEMCrypto_SESSION session, uint32_t usage_entry_number, + const uint8_t* buffer, size_t buffer_length); +OEMCryptoResult _oecc65(OEMCrypto_SESSION session, + OEMCrypto_SharedMemory* header_buffer, + size_t* header_buffer_length, + OEMCrypto_SharedMemory* entry_buffer, + size_t* entry_buffer_length); +OEMCryptoResult _oecc66(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length); +OEMCryptoResult _oecc32(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length, uint8_t* buffer, + size_t* buffer_length); +OEMCryptoResult _oecc68(OEMCrypto_SESSION session, uint32_t new_index); +OEMCryptoResult _oecc67(uint32_t new_entry_count, uint8_t* header_buffer, + size_t* header_buffer_length); +OEMCryptoResult _oecc57(void); +uint32_t _oecc86(void); +OEMCryptoResult _oecc88(OEMCrypto_SESSION session, uint32_t frame_number, + const uint8_t* hash, size_t hash_length); +OEMCryptoResult _oecc89(OEMCrypto_SESSION session, + uint32_t* failed_frame_number); +OEMCryptoResult _oecc109(OEMCrypto_SESSION session, size_t buffer_size, + OEMCrypto_DestBufferDesc* output_descriptor, + int* secure_fd); +OEMCryptoResult _oecc110(OEMCrypto_SESSION session, + OEMCrypto_DestBufferDesc* output_descriptor, + int secure_fd); +OEMCryptoResult _oecc115(uint32_t* ree_major, uint32_t* ree_minor, + uint32_t* tee_major, uint32_t* tee_minor); +OEMCryptoResult _oecc113(OEMCrypto_SESSION session, uint8_t* buffer, + size_t* buffer_length, uint32_t use_test_key); +OEMCryptoResult _oecc114(OEMCrypto_SESSION session, const uint8_t* buffer, + size_t buffer_length, uint32_t use_test_key); +OEMCryptoResult _oecc13(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, uint8_t* signature, + size_t* signature_length); +OEMCryptoResult _oecc51(OEMCrypto_SESSION session, + const uint32_t* unaligned_nonce, + const uint8_t* encrypted_message_key, + size_t encrypted_message_key_length, + 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); +OEMCryptoResult _oecc18(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, const uint8_t* signature, + size_t signature_length, + const uint32_t* unaligned_nonce, + 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); +OEMCryptoResult _oecc30(void); +OEMCryptoResult _oecc33(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); +OEMCryptoResult _oecc43(const uint8_t* pst, size_t pst_length); +OEMCryptoResult _oecc69(OEMCrypto_SESSION session, const uint8_t* pst, + size_t pst_length); +OEMCryptoResult _oecc34(void); +OEMCryptoResult _oecc70(uint64_t time_since_license_received, + uint64_t time_since_first_decrypt, + uint64_t time_since_last_decrypt, + OEMCrypto_Usage_Entry_Status status, + uint8_t* server_mac_key, uint8_t* client_mac_key, + const uint8_t* pst, size_t pst_length); +OEMCryptoResult _oecc12(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); +OEMCryptoResult _oecc48(OEMCrypto_SESSION session, const uint8_t* data_addr, + size_t data_addr_length, bool is_encrypted, + const uint8_t* iv, + size_t block_offset, // used for CTR "cenc" mode only. + OEMCrypto_DestBufferDesc* out_buffer, + const OEMCrypto_CENCEncryptPatternDesc_V15* pattern, + uint8_t subsample_flags); +OEMCryptoResult _oecc50(OEMCrypto_SESSION session, uint8_t* public_cert, + size_t* public_cert_length); +OEMCryptoResult _oecc19(OEMCrypto_SESSION session, + const uint8_t* wrapped_rsa_key, + size_t wrapped_rsa_key_length); + +// OEMCrypto_Idle defined in v17.1 +OEMCryptoResult _oecc123(OEMCrypto_IdleState state, uint32_t os_specific_code); + +// OEMCrypto_Wake defined in v17.1 +OEMCryptoResult _oecc124(void); + +// OEMCrypto_CreateEntitledKeySession defined in v17.1 +OEMCryptoResult _oecc111(OEMCrypto_SESSION oec_session, + OEMCrypto_SESSION* key_session); + +// OEMCrypto_RemoveEntitledKeySession defined in v17.1 +OEMCryptoResult _oecc112(OEMCrypto_SESSION key_session); + +// OEMCrypto_LoadEntitledContentKeys defined in v17.1 +OEMCryptoResult _oecc121(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, size_t key_array_length, + const OEMCrypto_EntitledContentKeyObject* key_array); + +// OEMCrypto_BuildInformation defined in v17.1 +OEMCryptoResult _oecc125(char* buffer, size_t* buffer_length); + +// OEMCrypto_SecurityLevel defined in v17.1 +OEMCrypto_Security_Level _oecc126(void); + +// OEMCrypto_GetDTCP2Capability defined in v17.1 +OEMCryptoResult _oecc128(OEMCrypto_DTCP2_Capability* capability); + +// OEMCrypto_ProductionReady defined in v17.1 +OEMCryptoResult _oecc122(void); + +// OEMCrypto_GetWatermarkingSupport defined in v17.1 +OEMCrypto_WatermarkingSupport _oecc129(void); + +// OEMCrypto_ReuseUsageEntry defined in v17.1 +OEMCryptoResult _oecc127(OEMCrypto_SESSION session, + uint32_t usage_entry_number); + +// OEMCrypto_GetBootCertificateChain defined in v17.1 +OEMCryptoResult _oecc116(uint8_t* bcc, size_t* bcc_length, + uint8_t* additional_signature, + size_t* additional_signature_length); + +// OEMCrypto_GenerateCertificateKeyPair defined in v17.1 +OEMCryptoResult _oecc117(OEMCrypto_SESSION session, uint8_t* public_key, + size_t* public_key_length, + uint8_t* public_key_signature, + size_t* public_key_signature_length, + uint8_t* wrapped_private_key, + size_t* wrapped_private_key_length, + OEMCrypto_PrivateKeyType* key_type); + +// OEMCrypto_InstallOemPrivateKey defined in v17.1 +OEMCryptoResult _oecc118(OEMCrypto_SESSION session, + OEMCrypto_PrivateKeyType key_type, + const uint8_t* wrapped_private_key, + size_t wrapped_private_key_length); + +// OEMCrypto_ReassociateEntitledKeySession defined in v17.1 +OEMCryptoResult _oecc119(OEMCrypto_SESSION key_session, + OEMCrypto_SESSION oec_session); + +// OEMCrypto_LoadCasECMKeys defined in v17.1 +OEMCryptoResult _oecc120(OEMCrypto_SESSION session, const uint8_t* message, + size_t message_length, + const OEMCrypto_EntitledContentKeyObject* even_key, + const OEMCrypto_EntitledContentKeyObject* odd_key); + +// OEMCrypto_GetOEMKeyToken defined in v17.2 +OEMCryptoResult _oecc130(OEMCrypto_SESSION key_session, uint8_t* key_token, + size_t* key_token_length); diff --git a/libwvdrmengine/oemcrypto/test/common.mk b/libwvdrmengine/oemcrypto/test/common.mk index 6f8569a7..d20a3e21 100644 --- a/libwvdrmengine/oemcrypto/test/common.mk +++ b/libwvdrmengine/oemcrypto/test/common.mk @@ -1,14 +1,5 @@ LOCAL_PATH:= $(call my-dir) -WV_UNITTESTS_BUILD_TARGET?= -ifeq ($(WV_UNITTESTS_BUILD_TARGET), hidl) -HIDL_EXTENSION := _hidl -LIB_BINDER := libhidlbase -else -HIDL_EXTENSION := -LIB_BINDER := libbinder_ndk -endif - ifeq ($(filter mips mips64, $(TARGET_ARCH)),) # Tests need to be compatible with devices that do not support gnu hash-style LOCAL_LDFLAGS+=-Wl,--hash-style=both @@ -18,6 +9,7 @@ endif LOCAL_CFLAGS += -DTEST_OEMCRYPTO_V15 LOCAL_SRC_FILES:= \ + GEN_api_lock_file.c \ oec_device_features.cpp \ oec_decrypt_fallback_chain.cpp \ oec_key_deriver.cpp \ @@ -50,7 +42,7 @@ LOCAL_STATIC_LIBRARIES := \ libgtest_main \ libwvlevel3 \ libcdm_protos \ - libcdm_utils$(HIDL_EXTENSION) \ + libcdm_utils \ libwv_kdo \ libwv_odk \ @@ -58,7 +50,7 @@ LOCAL_SHARED_LIBRARIES := \ libbase \ libcrypto \ libdl \ - $(LIB_BINDER) \ + libbinder_ndk \ liblog \ libmedia_omx \ libprotobuf-cpp-lite \ diff --git a/libwvdrmengine/prebuilts_hidl/arm/libwvhidl@1.3.so b/libwvdrmengine/prebuilts_hidl/arm/libwvhidl@1.3.so deleted file mode 100644 index d0aa3ef88b0d6bfd922e3fb3a756eaca60a7de87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2838440 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 zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* zAOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8} z0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq z5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH*AOR8}0TLhq5+DH* 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%0DJqXKoJMgsy{GN0x5;r?% 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≻8o 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 irKt8U+>c7C(?aQIo%(84>> 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

  • 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%0DD*in@qX>7xVd3R}IGDbmk%a_|Ohk_4?13>Rr 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