Implement Widevine drm HIDL HAL service.
Modify Android mediadrm and mediacrypto glue layer to use HIDL interface. Test: Play Movies (streaming and offline playback) Test: ANDROID_BUILD_TOP= ./android-gts/tools/gts-tradefed run gts -m GtsMediaTestCases Test: adb shell /system/bin/libwvdrmengine_hidl_test Test: adb shell /system/bin/libwvdrmmediacrypto_hidl_test Test: adb shell /system/bin/libwvdrmdrmplugin_hidl_test bug: 34628973 Change-Id: Icd5f2dd556acb9874697963b4d7d62cb7c943e74
This commit is contained in:
committed by
John W. Bruce
parent
a4506542df
commit
2dc53442e7
@@ -3,6 +3,37 @@
|
||||
#
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds android.hardware.drm@1.0-service.widevine
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := src_hidl/service.cpp
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
vendor/widevine/libwvdrmengine/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.base@1.0 \
|
||||
libbase \
|
||||
libhidltransport \
|
||||
libhwbinder \
|
||||
liblog \
|
||||
libutils \
|
||||
libwvhidl \
|
||||
|
||||
LOCAL_MODULE := android.hardware.drm@1.0-service.widevine
|
||||
LOCAL_INIT_RC := src_hidl/android.hardware.drm@1.0-service.widevine.rc
|
||||
LOCAL_MODULE_PATH := $(TARGET_OUT_VENDOR)/bin/hw
|
||||
LOCAL_PROPRIETARY_MODULE := true
|
||||
|
||||
LOCAL_MODULE_TARGET_ARCH := arm x86 mips
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libcdm_utils.a
|
||||
#
|
||||
@@ -61,6 +92,26 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := \
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libhidl_utils.a
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := libhidl_utils
|
||||
|
||||
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
vendor/widevine/libwvdrmengine/include_hidl
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src_hidl/TypeConvert.cpp
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmengine.so
|
||||
#
|
||||
@@ -71,7 +122,7 @@ LOCAL_SRC_FILES := \
|
||||
src/WVCreatePluginFactories.cpp \
|
||||
src/WVCryptoFactory.cpp \
|
||||
src/WVDrmFactory.cpp \
|
||||
src/WVUUID.cpp
|
||||
src/WVUUID.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
frameworks/av/include \
|
||||
@@ -90,9 +141,9 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libcdm_utils \
|
||||
libcrypto_static \
|
||||
libjsmn \
|
||||
libwvlevel3 \
|
||||
libwvdrmcryptoplugin \
|
||||
libwvdrmdrmplugin \
|
||||
libwvlevel3 \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
libcutils \
|
||||
@@ -115,6 +166,72 @@ LOCAL_PROPRIETARY_MODULE := true
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvhidl.so
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src/WVCDMSingleton.cpp \
|
||||
src/WVUUID.cpp \
|
||||
src_hidl/WVCreatePluginFactories.cpp \
|
||||
src_hidl/WVCryptoFactory.cpp \
|
||||
src_hidl/WVDrmFactory.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
frameworks/av/include \
|
||||
frameworks/native/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/metrics/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/include \
|
||||
vendor/widevine/libwvdrmengine/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/include \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcdm \
|
||||
libcdm_protos \
|
||||
libcdm_utils \
|
||||
libcrypto_static \
|
||||
libjsmn \
|
||||
libwvdrmcryptoplugin_hidl \
|
||||
libwvdrmdrmplugin_hidl \
|
||||
libwvlevel3 \
|
||||
|
||||
# When the GNU linker sees a library, it discards all symbols that it doesn't
|
||||
# need. libhidl_utils must come after both libwvdrmcryptoplugin and
|
||||
# libwvdrmdrmplugin.
|
||||
LOCAL_STATIC_LIBRARIES += libhidl_utils
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.base@1.0 \
|
||||
android.hidl.memory@1.0 \
|
||||
libcutils \
|
||||
libdl \
|
||||
libhidlbase \
|
||||
libhidlmemory \
|
||||
libhwbinder \
|
||||
liblog \
|
||||
libmedia \
|
||||
libprotobuf-cpp-lite \
|
||||
libstagefright_foundation \
|
||||
libutils \
|
||||
|
||||
LOCAL_MODULE := libwvhidl
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_MODULE_OWNER := widevine
|
||||
|
||||
LOCAL_PROPRIETARY_MODULE := true
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include vendor/widevine/libwvdrmengine/cdm/Android.mk
|
||||
include vendor/widevine/libwvdrmengine/level3/Android.mk
|
||||
include vendor/widevine/libwvdrmengine/mediacrypto/Android.mk
|
||||
|
||||
@@ -33,10 +33,6 @@ cd $ANDROID_BUILD_TOP/vendor/widevine/libwvdrmengine/oemcrypto/test
|
||||
pwd
|
||||
mm || mma
|
||||
|
||||
cd $ANDROID_BUILD_TOP/vendor/widevine/libwvdrmengine/test/java/src/com/widevine/test
|
||||
pwd
|
||||
mm WITH_DEXPREOPT=false || mma WITH_DEXPREOPT=false
|
||||
|
||||
echo "waiting for device"
|
||||
adb root && adb wait-for-device remount
|
||||
|
||||
@@ -55,7 +51,9 @@ try_adb_push $OUT/system/bin/cdm_extended_duration_test
|
||||
try_adb_push $OUT/system/bin/policy_engine_unittest
|
||||
try_adb_push $OUT/system/bin/policy_engine_constraints_unittest
|
||||
try_adb_push $OUT/system/bin/libwvdrmmediacrypto_test
|
||||
try_adb_push $OUT/system/bin/libwvdrmmediacrypto_hidl_test
|
||||
try_adb_push $OUT/system/bin/libwvdrmdrmplugin_test
|
||||
try_adb_push $OUT/system/bin/libwvdrmdrmplugin_hidl_test
|
||||
try_adb_push $OUT/system/bin/cdm_engine_test
|
||||
try_adb_push $OUT/system/bin/cdm_session_unittest
|
||||
try_adb_push $OUT/system/bin/file_store_unittest
|
||||
@@ -67,10 +65,10 @@ try_adb_push $OUT/system/bin/device_files_unittest
|
||||
try_adb_push $OUT/system/bin/service_certificate_unittest
|
||||
try_adb_push $OUT/system/bin/timer_unittest
|
||||
try_adb_push $OUT/system/bin/libwvdrmengine_test
|
||||
try_adb_push $OUT/system/bin/libwvdrmengine_hidl_test
|
||||
try_adb_push $OUT/system/bin/buffer_reader_test
|
||||
try_adb_push $OUT/system/bin/distribution_test
|
||||
try_adb_push $OUT/system/bin/event_metric_test
|
||||
adb install -r $OUT/system/app/MediaDrmAPITest/MediaDrmAPITest.apk
|
||||
|
||||
cd $ANDROID_BUILD_TOP/vendor/widevine/libwvdrmengine
|
||||
./run_all_unit_tests.sh
|
||||
|
||||
80
libwvdrmengine/include_hidl/TypeConvert.h
Normal file
80
libwvdrmengine/include_hidl/TypeConvert.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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_0_TYPECONVERT
|
||||
#define WVDRM_ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT
|
||||
#include "utils/Errors.h"
|
||||
#include <utils/Vector.h>
|
||||
|
||||
#include <android/hardware/drm/1.0/types.h>
|
||||
#include <media/stagefright/MediaErrors.h>
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::hidl_array;
|
||||
using ::android::hardware::hidl_vec;
|
||||
|
||||
template<typename T> const hidl_vec<T> toHidlVec(const Vector<T> &Vector) {
|
||||
hidl_vec<T> vec;
|
||||
vec.setToExternal(const_cast<T *>(Vector.array()), Vector.size());
|
||||
return vec;
|
||||
}
|
||||
|
||||
template<typename T> hidl_vec<T> toHidlVec(Vector<T> &Vector) {
|
||||
hidl_vec<T> vec;
|
||||
vec.setToExternal(Vector.editArray(), Vector.size());
|
||||
return vec;
|
||||
}
|
||||
|
||||
template<typename T> const Vector<T> toVector(const hidl_vec<T> &vec) {
|
||||
Vector<T> vector;
|
||||
vector.appendArray(vec.data(), vec.size());
|
||||
return *const_cast<const Vector<T> *>(&vector);
|
||||
}
|
||||
|
||||
template<typename T> Vector<T> toVector(hidl_vec<T> &vec) {
|
||||
Vector<T> vector;
|
||||
vector.appendArray(vec.data(), vec.size());
|
||||
return vector;
|
||||
}
|
||||
|
||||
template<typename T, size_t SIZE> const Vector<T> toVector(
|
||||
const hidl_array<T, SIZE> &array) {
|
||||
Vector<T> vector;
|
||||
vector.appendArray(array.data(), array.size());
|
||||
return vector;
|
||||
}
|
||||
|
||||
template<typename T, size_t SIZE> Vector<T> toVector(
|
||||
hidl_array<T, SIZE> &array) {
|
||||
Vector<T> vector;
|
||||
vector.appendArray(array.data(), array.size());
|
||||
return vector;
|
||||
}
|
||||
|
||||
Status toStatus(status_t mediaError);
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
|
||||
#endif // WVDRM_ANDROID_HARDWARE_DRM_V1_0_TYPECONVERT
|
||||
30
libwvdrmengine/include_hidl/WVCreatePluginFactories.h
Normal file
30
libwvdrmengine/include_hidl/WVCreatePluginFactories.h
Normal file
@@ -0,0 +1,30 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_CREATE_PLUGIN_FACTORIES_H_
|
||||
#define WV_CREATE_PLUGIN_FACTORIES_H_
|
||||
|
||||
#include <android/hardware/drm/1.0/ICryptoFactory.h>
|
||||
#include <android/hardware/drm/1.0/IDrmFactory.h>
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::ICryptoFactory;
|
||||
using ::android::hardware::drm::V1_0::IDrmFactory;
|
||||
|
||||
extern "C" {
|
||||
IDrmFactory* createDrmFactory();
|
||||
ICryptoFactory* createCryptoFactory();
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
#endif // WV_CREATE_PLUGIN_FACTORIES_H_
|
||||
47
libwvdrmengine/include_hidl/WVCryptoFactory.h
Normal file
47
libwvdrmengine/include_hidl/WVCryptoFactory.h
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_CRYPTO_FACTORY_H_
|
||||
#define WV_CRYPTO_FACTORY_H_
|
||||
|
||||
#include <android/hardware/drm/1.0/ICryptoFactory.h>
|
||||
|
||||
#include "WVTypes.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::ICryptoFactory;
|
||||
using ::android::hardware::drm::V1_0::ICryptoPlugin;
|
||||
using ::android::hardware::hidl_array;
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::Return;
|
||||
|
||||
struct WVCryptoFactory : public ICryptoFactory {
|
||||
public:
|
||||
WVCryptoFactory() {}
|
||||
virtual ~WVCryptoFactory() {}
|
||||
|
||||
Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
|
||||
override;
|
||||
|
||||
Return<void> createPlugin(
|
||||
const hidl_array<uint8_t, 16>& uuid,
|
||||
const hidl_vec<uint8_t>& initData,
|
||||
createPlugin_cb _hidl_cb) override;
|
||||
|
||||
private:
|
||||
WVDRM_DISALLOW_COPY_AND_ASSIGN(WVCryptoFactory);
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
#endif // WV_CRYPTO_FACTORY_H_
|
||||
54
libwvdrmengine/include_hidl/WVDrmFactory.h
Normal file
54
libwvdrmengine/include_hidl/WVDrmFactory.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_DRM_FACTORY_H_
|
||||
#define WV_DRM_FACTORY_H_
|
||||
|
||||
#include <android/hardware/drm/1.0/IDrmFactory.h>
|
||||
|
||||
#include "WVGenericCryptoInterface.h"
|
||||
#include "WVTypes.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::IDrmFactory;
|
||||
using ::android::hardware::drm::V1_0::IDrmPlugin;
|
||||
using ::android::hardware::hidl_array;
|
||||
using ::android::hardware::hidl_string;
|
||||
using ::android::hardware::Return;
|
||||
|
||||
struct WVDrmFactory : public IDrmFactory {
|
||||
WVDrmFactory() {}
|
||||
virtual ~WVDrmFactory() {}
|
||||
|
||||
Return<bool> isCryptoSchemeSupported(const hidl_array<uint8_t, 16>& uuid)
|
||||
override;
|
||||
|
||||
Return<bool> isContentTypeSupported(const hidl_string &mimeType)
|
||||
override;
|
||||
|
||||
Return<void> createPlugin(
|
||||
const hidl_array<uint8_t, 16>& uuid,
|
||||
const hidl_string& appPackageName,
|
||||
createPlugin_cb _hidl_cb) override;
|
||||
|
||||
private:
|
||||
WVDRM_DISALLOW_COPY_AND_ASSIGN(WVDrmFactory);
|
||||
|
||||
static WVGenericCryptoInterface sOemCryptoInterface;
|
||||
};
|
||||
|
||||
extern "C" IDrmFactory* HIDL_FETCH_IDrmFactory(const char* name);
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
#endif // WV_DRM_FACTORY_H_
|
||||
20
libwvdrmengine/include_hidl/WVTypes.h
Normal file
20
libwvdrmengine/include_hidl/WVTypes.h
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#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_
|
||||
@@ -1,4 +1,8 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmcryptoplugin
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
@@ -14,10 +18,46 @@ LOCAL_C_INCLUDES := \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcrypto_static \
|
||||
|
||||
LOCAL_MODULE := libwvdrmcryptoplugin
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := libcrypto_static
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmcryptoplugin_hidl
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src_hidl/WVCryptoPlugin.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/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/include \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcrypto_static \
|
||||
libhidl_utils \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.memory@1.0 \
|
||||
libhidlmemory \
|
||||
|
||||
LOCAL_MODULE := libwvdrmcryptoplugin_hidl
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
86
libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h
Normal file
86
libwvdrmengine/mediacrypto/include_hidl/WVCryptoPlugin.h
Normal file
@@ -0,0 +1,86 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_CRYPTO_PLUGIN_H_
|
||||
#define WV_CRYPTO_PLUGIN_H_
|
||||
|
||||
#include <android/hardware/drm/1.0/ICryptoPlugin.h>
|
||||
#include <android/hidl/memory/1.0/IMemory.h>
|
||||
#include <media/stagefright/foundation/AString.h>
|
||||
|
||||
#include "wv_content_decryption_module.h"
|
||||
#include "WVTypes.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::DestinationBuffer;
|
||||
using ::android::hardware::drm::V1_0::ICryptoPlugin;
|
||||
using ::android::hardware::drm::V1_0::Mode;
|
||||
using ::android::hardware::drm::V1_0::Pattern;
|
||||
using ::android::hardware::drm::V1_0::SharedBuffer;
|
||||
using ::android::hardware::drm::V1_0::Status;
|
||||
using ::android::hardware::drm::V1_0::SubSample;
|
||||
using ::android::hardware::hidl_array;
|
||||
using ::android::hardware::hidl_string;
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::hardware::hidl_memory;
|
||||
using ::android::hidl::memory::V1_0::IMemory;
|
||||
using ::android::sp;
|
||||
|
||||
struct WVCryptoPlugin : public ICryptoPlugin {
|
||||
WVCryptoPlugin(const void* data, size_t size,
|
||||
const sp<wvcdm::WvContentDecryptionModule>& cdm);
|
||||
virtual ~WVCryptoPlugin() {}
|
||||
|
||||
Return<bool> requiresSecureDecoderComponent(const hidl_string& mime)
|
||||
override;
|
||||
|
||||
Return<void> notifyResolution(uint32_t width, uint32_t height) override;
|
||||
|
||||
Return<Status> setMediaDrmSession(const hidl_vec<uint8_t>& sessionId)
|
||||
override;
|
||||
|
||||
Return<void> setSharedBufferBase(const hidl_memory& base,
|
||||
uint32_t bufferId) override;
|
||||
|
||||
Return<void> decrypt(
|
||||
bool secure,
|
||||
const hidl_array<uint8_t, 16>& keyId,
|
||||
const hidl_array<uint8_t, 16>& iv,
|
||||
Mode mode,
|
||||
const Pattern& pattern,
|
||||
const hidl_vec<SubSample>& subSamples,
|
||||
const SharedBuffer& source,
|
||||
uint64_t offset,
|
||||
const DestinationBuffer& destination,
|
||||
decrypt_cb _hidl_cb) override;
|
||||
|
||||
private:
|
||||
WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WVCryptoPlugin);
|
||||
|
||||
wvcdm::CdmSessionId mSessionId;
|
||||
std::map<uint32_t, sp<IMemory> > mSharedBufferMap;
|
||||
|
||||
sp<wvcdm::WvContentDecryptionModule> const mCDM;
|
||||
|
||||
android::status_t attemptDecrypt(
|
||||
const wvcdm::CdmDecryptionParameters& params,
|
||||
bool haveEncryptedSubsamples, android::AString* errorDetailMsg);
|
||||
static wvcdm::CdmResponseType countEncryptedBlocksInPatternedRange(
|
||||
size_t range, const Pattern& pattern, uint64_t* result);
|
||||
static void incrementIV(uint64_t increaseBy, std::vector<uint8_t>* ivPtr);
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
#endif // WV_CRYPTO_PLUGIN_H_
|
||||
407
libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp
Normal file
407
libwvdrmengine/mediacrypto/src_hidl/WVCryptoPlugin.cpp
Normal file
@@ -0,0 +1,407 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "WVCdm"
|
||||
#include <utils/Log.h>
|
||||
#include <utils/String8.h>
|
||||
|
||||
#include "WVCryptoPlugin.h"
|
||||
#include "TypeConvert.h"
|
||||
|
||||
#include <hidlmemory/mapping.h>
|
||||
|
||||
#include "mapErrors-inl.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "openssl/sha.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "WVErrors.h"
|
||||
|
||||
namespace {
|
||||
|
||||
static const size_t kAESBlockSize = 16;
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::BufferType;
|
||||
using ::android::hardware::drm::V1_0::widevine::toStatus;
|
||||
using ::android::hardware::drm::V1_0::widevine::toVector;
|
||||
using ::android::hardware::Void;
|
||||
|
||||
using android::AString;
|
||||
using android::status_t;
|
||||
|
||||
using wvcdm::CdmDecryptionParameters;
|
||||
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<WvContentDecryptionModule>& cdm)
|
||||
: mCDM(cdm){
|
||||
if (data != NULL) {
|
||||
mSessionId.assign(static_cast<const char *>(data), size);
|
||||
}
|
||||
if (!mCDM->IsOpenSession(mSessionId)) {
|
||||
mSessionId.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Return<bool> WVCryptoPlugin::requiresSecureDecoderComponent(
|
||||
const hidl_string& mime) {
|
||||
if (!strncasecmp(mime, "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<void> WVCryptoPlugin::notifyResolution(
|
||||
uint32_t width, uint32_t height) {
|
||||
mCDM->NotifyResolution(mSessionId, width, height);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<Status> WVCryptoPlugin::setMediaDrmSession(
|
||||
const hidl_vec<uint8_t>& sessionId) {
|
||||
const android::Vector<uint8_t> 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<void> WVCryptoPlugin::setSharedBufferBase(
|
||||
const hidl_memory& base, uint32_t bufferId) {
|
||||
mSharedBufferMap[bufferId] = mapMemory(base);
|
||||
return Void();
|
||||
}
|
||||
|
||||
Return<void> WVCryptoPlugin::decrypt(
|
||||
bool secure,
|
||||
const hidl_array<uint8_t, 16>& keyId,
|
||||
const hidl_array<uint8_t, 16>& iv,
|
||||
Mode mode,
|
||||
const Pattern& pattern,
|
||||
const hidl_vec<SubSample>& subSamples,
|
||||
const SharedBuffer& source,
|
||||
uint64_t offset,
|
||||
const DestinationBuffer& destination,
|
||||
decrypt_cb _hidl_cb) {
|
||||
|
||||
if (mSharedBufferMap.find(source.bufferId) == mSharedBufferMap.end()) {
|
||||
_hidl_cb(Status::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::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::BAD_VALUE,
|
||||
0, "Encryption mode 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<const char*>(keyId.data()), wvcdm::KEY_ID_SIZE);
|
||||
std::vector<uint8_t> ivVector(iv.data(), iv.data() + wvcdm::KEY_IV_SIZE);
|
||||
|
||||
AString errorDetailMsg;
|
||||
sp<IMemory> sourceBase = mSharedBufferMap[source.bufferId];
|
||||
|
||||
if (source.offset + offset + source.size > sourceBase->getSize()) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
|
||||
return Void();
|
||||
}
|
||||
|
||||
uint8_t *base = static_cast<uint8_t *>
|
||||
(static_cast<void *>(sourceBase->getPointer()));
|
||||
uint8_t* srcPtr = static_cast<uint8_t *>(base + source.offset + offset);
|
||||
void* destPtr = NULL;
|
||||
if (destination.type == BufferType::SHARED_MEMORY) {
|
||||
const SharedBuffer& destBuffer = destination.nonsecureMemory;
|
||||
sp<IMemory> destBase = mSharedBufferMap[destBuffer.bufferId];
|
||||
if (destBuffer.offset + destBuffer.size > destBase->getSize()) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
|
||||
return Void();
|
||||
}
|
||||
destPtr = static_cast<void *>(base + destination.nonsecureMemory.offset);
|
||||
} else if (destination.type == BufferType::NATIVE_HANDLE) {
|
||||
native_handle_t *handle = const_cast<native_handle_t *>(
|
||||
destination.secureMemory.getNativeHandle());
|
||||
destPtr = static_cast<void *>(handle);
|
||||
}
|
||||
|
||||
// Calculate the output buffer size and determine if any subsamples are
|
||||
// encrypted.
|
||||
size_t destSize = 0;
|
||||
bool haveEncryptedSubsamples = false;
|
||||
for (size_t i = 0; i < subSamples.size(); i++) {
|
||||
const SubSample &subSample = subSamples[i];
|
||||
destSize += subSample.numBytesOfClearData;
|
||||
destSize += subSample.numBytesOfEncryptedData;
|
||||
if (subSample.numBytesOfEncryptedData > 0) {
|
||||
haveEncryptedSubsamples = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the decrypt params that do not vary.
|
||||
CdmDecryptionParameters params = CdmDecryptionParameters();
|
||||
params.is_secure = secure;
|
||||
params.key_id = &cryptoKey;
|
||||
params.iv = &ivVector;
|
||||
params.decrypt_buffer = destPtr;
|
||||
params.decrypt_buffer_length = destSize;
|
||||
params.pattern_descriptor.encrypt_blocks = pattern.encryptBlocks;
|
||||
params.pattern_descriptor.skip_blocks = pattern.skipBlocks;
|
||||
|
||||
if (mode == Mode::AES_CTR) {
|
||||
params.cipher_mode = wvcdm::kCipherModeCtr;
|
||||
} else if (mode == Mode::AES_CBC) {
|
||||
params.cipher_mode = wvcdm::kCipherModeCbc;
|
||||
}
|
||||
|
||||
// Iterate through subsamples, sending them to the CDM serially.
|
||||
size_t bufferOffset = 0;
|
||||
size_t blockOffset = 0;
|
||||
const size_t patternLengthInBytes =
|
||||
(pattern.encryptBlocks + pattern.skipBlocks) * kAESBlockSize;
|
||||
|
||||
for (size_t i = 0; i < subSamples.size(); ++i) {
|
||||
const SubSample& subSample = subSamples[i];
|
||||
|
||||
if (mode == Mode::UNENCRYPTED && subSample.numBytesOfEncryptedData != 0) {
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
"Encrypted subsamples found in allegedly unencrypted data.");
|
||||
return Void();
|
||||
}
|
||||
|
||||
// Calculate any flags that apply to this subsample's parts.
|
||||
uint8_t clearFlags = 0;
|
||||
uint8_t encryptedFlags = 0;
|
||||
|
||||
// If this is the first subsample…
|
||||
if (i == 0) {
|
||||
// …add OEMCrypto_FirstSubsample to the first part that is present.
|
||||
if (subSample.numBytesOfClearData != 0) {
|
||||
clearFlags = clearFlags | OEMCrypto_FirstSubsample;
|
||||
} else {
|
||||
encryptedFlags = encryptedFlags | OEMCrypto_FirstSubsample;
|
||||
}
|
||||
}
|
||||
// If this is the last subsample…
|
||||
if (i == subSamples.size() - 1) {
|
||||
// …add OEMCrypto_LastSubsample to the last part that is present
|
||||
if (subSample.numBytesOfEncryptedData != 0) {
|
||||
encryptedFlags = encryptedFlags | OEMCrypto_LastSubsample;
|
||||
} else {
|
||||
clearFlags = clearFlags | OEMCrypto_LastSubsample;
|
||||
}
|
||||
}
|
||||
|
||||
// "Decrypt" any unencrypted data. Per the ISO-CENC standard, clear data
|
||||
// comes before encrypted data.
|
||||
if (subSample.numBytesOfClearData != 0) {
|
||||
params.is_encrypted = false;
|
||||
params.encrypt_buffer = srcPtr + bufferOffset;
|
||||
params.encrypt_length = subSample.numBytesOfClearData;
|
||||
params.block_offset = 0;
|
||||
params.decrypt_buffer_offset = bufferOffset;
|
||||
params.subsample_flags = clearFlags;
|
||||
|
||||
status_t res = attemptDecrypt(params, haveEncryptedSubsamples,
|
||||
&errorDetailMsg);
|
||||
if (res != android::OK) {
|
||||
_hidl_cb(toStatus(res), 0, errorDetailMsg.c_str());
|
||||
return Void();
|
||||
}
|
||||
bufferOffset += subSample.numBytesOfClearData;
|
||||
}
|
||||
|
||||
// Decrypt any encrypted data. Per the ISO-CENC standard, encrypted data
|
||||
// comes after clear data.
|
||||
if (subSample.numBytesOfEncryptedData != 0) {
|
||||
params.is_encrypted = true;
|
||||
params.encrypt_buffer = srcPtr + bufferOffset;
|
||||
params.encrypt_length = subSample.numBytesOfEncryptedData;
|
||||
params.block_offset = blockOffset;
|
||||
params.decrypt_buffer_offset = bufferOffset;
|
||||
params.subsample_flags = encryptedFlags;
|
||||
|
||||
status_t res = attemptDecrypt(params, haveEncryptedSubsamples,
|
||||
&errorDetailMsg);
|
||||
if (res != android::OK) {
|
||||
_hidl_cb(toStatus(res), 0, errorDetailMsg.c_str());
|
||||
return Void();
|
||||
}
|
||||
|
||||
bufferOffset += subSample.numBytesOfEncryptedData;
|
||||
|
||||
// Update the block offset, pattern offset, and IV as needed by the
|
||||
// various crypto modes. Possible combinations are cenc (AES-CTR), cens
|
||||
// (AES-CTR w/ Patterns), cbc1 (AES-CBC), and cbcs (AES-CBC w/ Patterns).
|
||||
if (mode == Mode::AES_CTR) {
|
||||
// Update the IV depending on how many encrypted blocks we passed.
|
||||
uint64_t increment = 0;
|
||||
if (patternLengthInBytes == 0) {
|
||||
// If there's no pattern, all the blocks are encrypted. We have to add
|
||||
// in blockOffset to account for any incomplete crypto blocks from the
|
||||
// preceding subsample.
|
||||
increment = (blockOffset + subSample.numBytesOfEncryptedData) /
|
||||
kAESBlockSize;
|
||||
} else {
|
||||
CdmResponseType countRes = countEncryptedBlocksInPatternedRange(
|
||||
subSample.numBytesOfEncryptedData, pattern, &increment);
|
||||
if (!isCdmResponseTypeSuccess(countRes)) {
|
||||
// Swallow the specifics of the error to obscure decrypt internals.
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0,
|
||||
"Error decrypting data: unknown error");
|
||||
return Void();
|
||||
}
|
||||
}
|
||||
incrementIV(increment, &ivVector);
|
||||
|
||||
// Update the block offset
|
||||
blockOffset = (blockOffset + subSample.numBytesOfEncryptedData) %
|
||||
kAESBlockSize;
|
||||
} else if (mode == Mode::AES_CBC && patternLengthInBytes == 0) {
|
||||
// If there is no pattern, assume cbc1 mode and update the IV.
|
||||
|
||||
// Stash the last crypto block in the IV.
|
||||
const uint8_t* bufferEnd = srcPtr + bufferOffset +
|
||||
subSample.numBytesOfEncryptedData;
|
||||
ivVector.assign(bufferEnd - kAESBlockSize, bufferEnd);
|
||||
}
|
||||
// There is no branch for cbcs mode because the IV and pattern offest
|
||||
// reset at the start of each subsample, so they do not need to be
|
||||
// updated.
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t status;
|
||||
uint32_t bytesWritten;
|
||||
|
||||
if (bufferOffset >= 0) {
|
||||
status = android::OK;
|
||||
bytesWritten = bufferOffset;
|
||||
} else {
|
||||
status = bufferOffset;
|
||||
bytesWritten = 0;
|
||||
}
|
||||
|
||||
_hidl_cb(toStatus(status), bytesWritten, errorDetailMsg.c_str());
|
||||
return Void();
|
||||
}
|
||||
|
||||
status_t WVCryptoPlugin::attemptDecrypt(const CdmDecryptionParameters& params,
|
||||
bool haveEncryptedSubsamples,
|
||||
AString* errorDetailMsg) {
|
||||
CdmResponseType res = mCDM->Decrypt(mSessionId, haveEncryptedSubsamples,
|
||||
params);
|
||||
|
||||
if (isCdmResponseTypeSuccess(res)) {
|
||||
return android::OK;
|
||||
} else {
|
||||
ALOGE("Decrypt error result in session %s during %s block: %d",
|
||||
mSessionId.c_str(),
|
||||
params.is_encrypted ? "encrypted" : "unencrypted",
|
||||
res);
|
||||
if (res == wvcdm::INSUFFICIENT_CRYPTO_RESOURCES) {
|
||||
errorDetailMsg->setTo(
|
||||
"Error decrypting data: insufficient crypto resources");
|
||||
// This error is actionable by the app and should be passed up.
|
||||
return mapCdmResponseType(res);
|
||||
} else if (res == wvcdm::NEED_KEY) {
|
||||
errorDetailMsg->setTo(
|
||||
"Error decrypting data: requested key has not been loaded");
|
||||
// This error is actionable by the app and should be passed up.
|
||||
return mapCdmResponseType(res);
|
||||
} else if (res == wvcdm::SESSION_NOT_FOUND_FOR_DECRYPT) {
|
||||
errorDetailMsg->setTo(
|
||||
"Error decrypting data: session not found, possibly reclaimed");
|
||||
// This error is actionable by the app and should be passed up.
|
||||
return mapCdmResponseType(res);
|
||||
} else if (res == wvcdm::DECRYPT_ERROR) {
|
||||
errorDetailMsg->setTo(
|
||||
"Error decrypting data: unspecified error");
|
||||
// This error is actionable by the app and should be passed up.
|
||||
return mapCdmResponseType(res);
|
||||
} else if (res == wvcdm::INSUFFICIENT_OUTPUT_PROTECTION) {
|
||||
errorDetailMsg->setTo(
|
||||
"Error decrypting data: insufficient output protection");
|
||||
// This error is actionable by the app and should be passed up.
|
||||
return mapCdmResponseType(res);
|
||||
} else {
|
||||
// Swallow the specifics of other errors to obscure decrypt internals.
|
||||
return kErrorCDMGeneric;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdmResponseType WVCryptoPlugin::countEncryptedBlocksInPatternedRange(
|
||||
size_t range, const Pattern& pattern, uint64_t* result) {
|
||||
if (result == NULL || range % kAESBlockSize != 0) {
|
||||
return wvcdm::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
const size_t patternLength = pattern.encryptBlocks + pattern.skipBlocks;
|
||||
uint64_t encryptedBlocksPassed = 0;
|
||||
size_t patternPosition = 0;
|
||||
for (size_t remaining = range / kAESBlockSize; remaining > 0; --remaining) {
|
||||
if (patternPosition < pattern.encryptBlocks) {
|
||||
++encryptedBlocksPassed;
|
||||
}
|
||||
patternPosition = (patternPosition + 1) % patternLength;
|
||||
}
|
||||
|
||||
*result = encryptedBlocksPassed;
|
||||
return wvcdm::NO_ERROR;
|
||||
}
|
||||
|
||||
void WVCryptoPlugin::incrementIV(uint64_t increaseBy,
|
||||
std::vector<uint8_t>* ivPtr) {
|
||||
std::vector<uint8_t>& iv = *ivPtr;
|
||||
uint64_t* counterBuffer = reinterpret_cast<uint64_t*>(&iv[8]);
|
||||
(*counterBuffer) = htonq(ntohq(*counterBuffer) + increaseBy);
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
@@ -1,8 +1,12 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmmediacrypto_test
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
WVCryptoPlugin_test.cpp \
|
||||
legacy_src/WVCryptoPlugin_test.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
frameworks/av/include \
|
||||
@@ -37,10 +41,67 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/protobuf/src \
|
||||
|
||||
# End protobuf section
|
||||
|
||||
LOCAL_MODULE := libwvdrmmediacrypto_test
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmmediacrypto_hidl_test
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
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/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediacrypto/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcdm \
|
||||
libcdm_protos \
|
||||
libcdm_utils \
|
||||
libcrypto_static \
|
||||
libjsmn \
|
||||
libgmock \
|
||||
libgmock_main \
|
||||
libgtest \
|
||||
libwvlevel3 \
|
||||
libwvdrmcryptoplugin_hidl \
|
||||
|
||||
# When the GNU linker sees a library, it discards all symbols that it doesn't
|
||||
# need. libhidl_utils must come after libwvdrmcryptoplugin.
|
||||
LOCAL_STATIC_LIBRARIES += libhidl_utils
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.base@1.0 \
|
||||
android.hidl.memory@1.0 \
|
||||
libbinder \
|
||||
libcutils \
|
||||
libdl \
|
||||
libhidlbase \
|
||||
libhidlmemory \
|
||||
liblog \
|
||||
libmedia \
|
||||
libprotobuf-cpp-lite \
|
||||
libstagefright_foundation \
|
||||
libutils \
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/protobuf/src \
|
||||
|
||||
LOCAL_MODULE := libwvdrmmediacrypto_hidl_test
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -2,29 +2,77 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "WVCryptoPluginTest"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include <map>
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <binder/MemoryDealer.h>
|
||||
#include <hidl/Status.h>
|
||||
#include <hidlmemory/mapping.h>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
#include "media/stagefright/foundation/AString.h"
|
||||
#include "media/stagefright/MediaErrors.h"
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_types.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "TypeConvert.h"
|
||||
#include "WVCryptoPlugin.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
using namespace wvcdm;
|
||||
using namespace wvdrm;
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
using ::android::hardware::drm::V1_0::BufferType;
|
||||
using ::android::hardware::drm::V1_0::DestinationBuffer;
|
||||
using ::android::hardware::drm::V1_0::Mode;
|
||||
using ::android::hardware::drm::V1_0::Pattern;
|
||||
using ::android::hardware::drm::V1_0::SharedBuffer;
|
||||
using ::android::hardware::drm::V1_0::Status;
|
||||
using ::android::hardware::drm::V1_0::SubSample;
|
||||
using ::android::hardware::drm::V1_0::widevine::toHidlVec;
|
||||
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::Void;
|
||||
using ::android::MemoryDealer;
|
||||
using ::android::sp;
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::DefaultValue;
|
||||
using ::testing::ElementsAreArray;
|
||||
using ::testing::Field;
|
||||
using ::testing::InSequence;
|
||||
using ::testing::Matcher;
|
||||
using ::testing::SetArgPointee;
|
||||
using ::testing::StrictMock;
|
||||
using ::testing::Test;
|
||||
using ::testing::Value;
|
||||
using ::testing::internal::ElementsAreArrayMatcher;
|
||||
|
||||
using wvcdm::kCipherModeCtr;
|
||||
using wvcdm::CdmCencPatternEncryptionDescriptor;
|
||||
using wvcdm::CdmCipherMode;
|
||||
using wvcdm::CdmDecryptionParameters;
|
||||
using wvcdm::CdmQueryMap;
|
||||
using wvcdm::CdmResponseType;
|
||||
using wvcdm::CdmSessionId;
|
||||
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_METHOD1(IsOpenSession, bool(const CdmSessionId&));
|
||||
|
||||
@@ -38,7 +86,11 @@ class MockCDM : public WvContentDecryptionModule {
|
||||
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<void *, uint32_t> heapBases;
|
||||
|
||||
virtual void SetUp() {
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
@@ -47,6 +99,47 @@ class WVCryptoPluginTest : public Test {
|
||||
|
||||
// Set default CdmResponseType value for gMock
|
||||
DefaultValue<CdmResponseType>::Set(wvcdm::NO_ERROR);
|
||||
heapBases.clear();
|
||||
}
|
||||
|
||||
void setHeapBase(WVCryptoPlugin& plugin,
|
||||
const sp<android::IMemoryHeap>& 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<void*, uint32_t>(heapBase, nextBufferId));
|
||||
Return<void> hResult =
|
||||
plugin.setSharedBufferBase(hidlMemory, nextBufferId++);
|
||||
|
||||
ALOGE_IF(!hResult.isOk(), "setHeapBase failed setSharedBufferBase");
|
||||
}
|
||||
|
||||
void toSharedBuffer(WVCryptoPlugin& plugin,
|
||||
const sp<android::IMemory>& memory,
|
||||
SharedBuffer* buffer) {
|
||||
ssize_t offset;
|
||||
size_t size;
|
||||
|
||||
ASSERT_NE(memory, nullptr);
|
||||
ASSERT_NE(buffer, nullptr);
|
||||
|
||||
sp<android::IMemoryHeap> 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;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -60,14 +153,14 @@ TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) {
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Specify the expected calls to QuerySessionStatus
|
||||
EXPECT_CALL(*cdm, QuerySessionStatus(_, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(l1Map),
|
||||
Return(wvcdm::NO_ERROR)))
|
||||
testing::Return(wvcdm::NO_ERROR)))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(l3Map),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
testing::Return(wvcdm::NO_ERROR)));
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
|
||||
@@ -87,20 +180,26 @@ class CDPMatcherFactory {
|
||||
// to re-specify them at every call site, we pass them into the factory
|
||||
// constructor.
|
||||
CDPMatcherFactory(bool isSecure, CdmCipherMode cipherMode, uint8_t* keyId,
|
||||
void* out, size_t outLen)
|
||||
void* out, size_t outLen, bool isVideo)
|
||||
: mIsSecure(isSecure), mCipherMode(cipherMode), mKeyId(keyId),
|
||||
mOut(out), mOutLen(outLen) {}
|
||||
mOut(out), mOutLen(outLen), mIsVideo(isVideo) {}
|
||||
|
||||
Matcher<const CdmDecryptionParameters&> operator()(bool isEncrypted,
|
||||
uint8_t* in,
|
||||
size_t inLen,
|
||||
uint8_t* iv,
|
||||
size_t blockOffset,
|
||||
size_t outOffset,
|
||||
uint8_t flags) const {
|
||||
return Truly(CDPMatcher(mIsSecure, mCipherMode, mKeyId, mOut, mOutLen,
|
||||
isEncrypted, in, inLen, iv, blockOffset,
|
||||
outOffset, flags));
|
||||
testing::Matcher<const CdmDecryptionParameters&> operator()(
|
||||
bool isEncrypted,
|
||||
uint8_t* in,
|
||||
size_t inLen,
|
||||
uint8_t* iv,
|
||||
size_t blockOffset,
|
||||
size_t outOffset,
|
||||
uint8_t flags,
|
||||
CdmCencPatternEncryptionDescriptor& cdmPatternDesc) const {
|
||||
// TODO b/28295739
|
||||
// Add New MediaCrypto Unit Tests for CBC & Pattern Mode
|
||||
// in cdmPatternDesc.
|
||||
return testing::Truly(CDPMatcher(mIsSecure, mCipherMode, mKeyId, mOut,
|
||||
mOutLen, isEncrypted, in, inLen, iv,
|
||||
blockOffset, outOffset, flags, mIsVideo,
|
||||
cdmPatternDesc));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -112,25 +211,32 @@ class CDPMatcherFactory {
|
||||
CDPMatcher(bool isSecure, CdmCipherMode cipherMode, uint8_t* keyId,
|
||||
void* out, size_t outLen, bool isEncrypted, uint8_t* in,
|
||||
size_t inLen, uint8_t* iv, size_t blockOffset,
|
||||
size_t outOffset, uint8_t flags)
|
||||
size_t outOffset, uint8_t flags, bool isVideo,
|
||||
CdmCencPatternEncryptionDescriptor& cdmPatternDesc)
|
||||
: mIsSecure(isSecure), mCipherMode(cipherMode), mKeyId(keyId),
|
||||
mOut(out), mOutLen(outLen), mIsEncrypted(isEncrypted), mIn(in),
|
||||
mInLen(inLen), mIv(iv), mBlockOffset(blockOffset),
|
||||
mOutOffset(outOffset), mFlags(flags) {}
|
||||
mOutOffset(outOffset), mFlags(flags), mIsVideo(isVideo),
|
||||
mCdmPatternDesc(cdmPatternDesc) {}
|
||||
|
||||
bool operator()(const CdmDecryptionParameters& params) const {
|
||||
return params.is_secure == mIsSecure &&
|
||||
params.cipher_mode == mCipherMode &&
|
||||
Value(*params.key_id, ElementsAreArray(mKeyId, KEY_ID_SIZE)) &&
|
||||
params.decrypt_buffer == mOut &&
|
||||
// TODO b/35259313
|
||||
// Converts mOut from hidl address to physical address
|
||||
// params.decrypt_buffer == mOut &&
|
||||
params.decrypt_buffer_length == mOutLen &&
|
||||
params.is_encrypted == mIsEncrypted &&
|
||||
params.encrypt_buffer == mIn &&
|
||||
// TODO b/35259313
|
||||
// Converts mIn from hidl address to physical address
|
||||
// params.encrypt_buffer == mIn &&
|
||||
params.encrypt_length == mInLen &&
|
||||
Value(*params.iv, ElementsAreArray(mIv, KEY_IV_SIZE)) &&
|
||||
params.block_offset == mBlockOffset &&
|
||||
params.decrypt_buffer_offset == mOutOffset &&
|
||||
params.subsample_flags == mFlags;
|
||||
params.subsample_flags == mFlags &&
|
||||
params.is_video == mIsVideo;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -146,6 +252,8 @@ class CDPMatcherFactory {
|
||||
size_t mBlockOffset;
|
||||
size_t mOutOffset;
|
||||
uint8_t mFlags;
|
||||
bool mIsVideo;
|
||||
CdmCencPatternEncryptionDescriptor mCdmPatternDesc;
|
||||
};
|
||||
|
||||
bool mIsSecure;
|
||||
@@ -153,17 +261,34 @@ class CDPMatcherFactory {
|
||||
uint8_t* mKeyId;
|
||||
void* mOut;
|
||||
size_t mOutLen;
|
||||
bool mIsVideo;
|
||||
};
|
||||
|
||||
TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
uint8_t keyId[KEY_ID_SIZE];
|
||||
static const 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<SubSample> subSamplesVector(
|
||||
subSamples, subSamples + sizeof(subSamples) / sizeof(subSamples[0]));
|
||||
auto hSubSamples = hidl_vec<SubSample>(subSamplesVector);
|
||||
|
||||
uint8_t baseIv[KEY_IV_SIZE];
|
||||
uint8_t keyId[KEY_ID_SIZE];
|
||||
|
||||
static const size_t kDataSize = 185;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[kDataSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||
@@ -171,17 +296,20 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
static const size_t kSubSampleCount = 6;
|
||||
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
||||
memset(subSamples, 0, sizeof(subSamples));
|
||||
subSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
subSamples[1].mNumBytesOfClearData = 16;
|
||||
subSamples[1].mNumBytesOfEncryptedData = 16;
|
||||
subSamples[2].mNumBytesOfEncryptedData = 8;
|
||||
subSamples[3].mNumBytesOfClearData = 29;
|
||||
subSamples[3].mNumBytesOfEncryptedData = 24;
|
||||
subSamples[4].mNumBytesOfEncryptedData = 60;
|
||||
subSamples[5].mNumBytesOfEncryptedData = 16;
|
||||
sp<MemoryDealer> memDealer = new MemoryDealer(
|
||||
kDataSize * 2, "WVCryptoPlugin_test");
|
||||
sp<android::IMemory> source = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(source, nullptr);
|
||||
pSrc = static_cast<uint8_t*>(
|
||||
static_cast<void*>(source->pointer()));
|
||||
ASSERT_NE(pSrc, nullptr);
|
||||
memcpy(pSrc, in, source->size());
|
||||
|
||||
sp<android::IMemory> destination = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(destination, nullptr);
|
||||
pDest = static_cast<uint8_t*>(
|
||||
static_cast<void*>(destination->pointer()));
|
||||
ASSERT_NE(pDest, nullptr);
|
||||
|
||||
uint8_t iv[5][KEY_IV_SIZE];
|
||||
memcpy(iv[0], baseIv, sizeof(baseIv));
|
||||
@@ -195,12 +323,13 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
memcpy(iv[4], baseIv, sizeof(baseIv));
|
||||
iv[4][15] = 7;
|
||||
|
||||
CdmCencPatternEncryptionDescriptor cdmPattern;
|
||||
CDPMatcherFactory ParamsAre =
|
||||
CDPMatcherFactory(false, kCipherModeCtr, keyId, out, kDataSize);
|
||||
CDPMatcherFactory(false, kCipherModeCtr, keyId, pDest, kDataSize, true);
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
@@ -209,67 +338,86 @@ TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
// SubSample 0
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in, 16, iv[0], 0, 0,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
ParamsAre(true, pSrc, 16, iv[0], 0, 0,
|
||||
OEMCrypto_FirstSubsample, cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 1
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(false, in + 16, 16, iv[1], 0, 16, 0)))
|
||||
ParamsAre(false, pSrc + 16, 16, iv[1], 0, 16, 0,
|
||||
cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 32, 16, iv[1], 0, 32, 0)))
|
||||
ParamsAre(true, pSrc + 32, 16, iv[1], 0, 32, 0,
|
||||
cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 2
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 48, 8, iv[2], 0, 48, 0)))
|
||||
ParamsAre(true, pSrc + 48, 8, iv[2], 0, 48, 0,
|
||||
cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 3
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(false, in + 56, 29, iv[2], 0, 56, 0)))
|
||||
ParamsAre(false, pSrc + 56, 29, iv[2], 0, 56, 0,
|
||||
cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 85, 24, iv[2], 8, 85, 0)))
|
||||
ParamsAre(true, pSrc + 85, 24, iv[2], 8, 85, 0,
|
||||
cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 4
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 109, 60, iv[3], 0, 109, 0)))
|
||||
ParamsAre(true, pSrc + 109, 60, iv[3], 0, 109, 0,
|
||||
cdmPattern)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 5
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 169, 16, iv[4], 12, 169,
|
||||
OEMCrypto_LastSubsample)))
|
||||
ParamsAre(true, pSrc + 169, 16, iv[4], 12, 169,
|
||||
OEMCrypto_LastSubsample, cdmPattern)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv[0], CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount,
|
||||
out, &errorDetailMessage);
|
||||
uint32_t bytesWritten = 0;
|
||||
std::string errorDetailMessage;
|
||||
DestinationBuffer hDestination;
|
||||
hDestination.type = BufferType::SHARED_MEMORY;
|
||||
toSharedBuffer(plugin, destination, &hDestination.nonsecureMemory);
|
||||
Pattern noPattern = { 0, 0 };
|
||||
|
||||
EXPECT_EQ(static_cast<ssize_t>(kDataSize), res) <<
|
||||
"WVCryptoPlugin decrypted the wrong number of bytes";
|
||||
SharedBuffer sourceBuffer;
|
||||
toSharedBuffer(plugin, source, &sourceBuffer);
|
||||
|
||||
plugin.decrypt(
|
||||
false, hidl_array<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(iv[0]),
|
||||
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.";
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
@@ -278,7 +426,6 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
|
||||
static const size_t kDataSize = 32;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[kDataSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||
@@ -286,15 +433,16 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
||||
memset(subSamples, 0, sizeof(subSamples));
|
||||
subSamples[0].mNumBytesOfClearData = 16;
|
||||
subSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
SubSample subSample;
|
||||
subSample.numBytesOfClearData = 16;
|
||||
subSample.numBytesOfEncryptedData = 16;
|
||||
std::vector<SubSample> subSampleVector;
|
||||
subSampleVector.push_back(subSample);
|
||||
auto hSubSamples = hidl_vec<SubSample>(subSampleVector);
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
@@ -309,25 +457,59 @@ TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
.Times(2);
|
||||
}
|
||||
|
||||
sp<MemoryDealer> memDealer = new MemoryDealer(
|
||||
kDataSize * 2, "WVCryptoPlugin_test");
|
||||
sp<android::IMemory> source = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(source, nullptr);
|
||||
pSrc = static_cast<uint8_t*>(
|
||||
static_cast<void*>(source->pointer()));
|
||||
ASSERT_NE(pSrc, nullptr);
|
||||
memcpy(pSrc, in, source->size());
|
||||
|
||||
sp<android::IMemory> destination = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(destination, nullptr);
|
||||
pDest = static_cast<uint8_t*>(
|
||||
static_cast<void*>(destination->pointer()));
|
||||
ASSERT_NE(pDest, nullptr);
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount,
|
||||
out, &errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
uint32_t bytesWritten = 0;
|
||||
Status err = Status::OK;
|
||||
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<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(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());
|
||||
});
|
||||
|
||||
res = plugin.decrypt(true, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
plugin.decrypt(
|
||||
true, hidl_array<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(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, SetsFlagsForMinimumSubsampleRuns) {
|
||||
@@ -338,7 +520,6 @@ TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||
|
||||
static const size_t kDataSize = 16;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[kDataSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||
@@ -346,23 +527,30 @@ TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample clearSubSamples[kSubSampleCount];
|
||||
memset(clearSubSamples, 0, sizeof(clearSubSamples));
|
||||
clearSubSamples[0].mNumBytesOfClearData = 16;
|
||||
SubSample clearSubSample;
|
||||
clearSubSample.numBytesOfClearData = 16;
|
||||
clearSubSample.numBytesOfEncryptedData = 0;
|
||||
std::vector<SubSample> clearSubSampleVector;
|
||||
clearSubSampleVector.push_back(clearSubSample);
|
||||
auto hClearSubSamples = hidl_vec<SubSample>(clearSubSampleVector);
|
||||
|
||||
CryptoPlugin::SubSample encryptedSubSamples[kSubSampleCount];
|
||||
memset(encryptedSubSamples, 0, sizeof(encryptedSubSamples));
|
||||
encryptedSubSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
SubSample encryptedSubSample;
|
||||
encryptedSubSample.numBytesOfClearData = 0;
|
||||
encryptedSubSample.numBytesOfEncryptedData = 16;
|
||||
std::vector<SubSample> encryptedSubSampleVector;
|
||||
encryptedSubSampleVector.push_back(encryptedSubSample);
|
||||
auto hEncryptedSubSamples = hidl_vec<SubSample>(encryptedSubSampleVector);
|
||||
|
||||
CryptoPlugin::SubSample mixedSubSamples[kSubSampleCount];
|
||||
memset(mixedSubSamples, 0, sizeof(mixedSubSamples));
|
||||
mixedSubSamples[0].mNumBytesOfClearData = 8;
|
||||
mixedSubSamples[0].mNumBytesOfEncryptedData = 8;
|
||||
SubSample mixedSubSample;
|
||||
mixedSubSample.numBytesOfClearData = 8;
|
||||
mixedSubSample.numBytesOfEncryptedData = 8;
|
||||
std::vector<SubSample> mixedSubSampleVector;
|
||||
mixedSubSampleVector.push_back(mixedSubSample);
|
||||
auto hMixedSubSamples = hidl_vec<SubSample>(mixedSubSampleVector);
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
@@ -371,46 +559,86 @@ TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample |
|
||||
OEMCrypto_LastSubsample)))
|
||||
OEMCrypto_FirstSubsample |
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_LastSubsample)))
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
sp<MemoryDealer> memDealer = new MemoryDealer(
|
||||
kDataSize * 2, "WVCryptoPlugin_test");
|
||||
sp<android::IMemory> source = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(source, nullptr);
|
||||
pSrc = static_cast<uint8_t*>(
|
||||
static_cast<void*>(source->pointer()));
|
||||
ASSERT_NE(pSrc, nullptr);
|
||||
memcpy(pSrc, in, source->size());
|
||||
|
||||
sp<android::IMemory> destination = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(destination, nullptr);
|
||||
pDest = static_cast<uint8_t*>(
|
||||
static_cast<void*>(destination->pointer()));
|
||||
ASSERT_NE(pDest, nullptr);
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, clearSubSamples,
|
||||
kSubSampleCount, out, &errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
uint32_t bytesWritten = 0;
|
||||
Status err = Status::OK;
|
||||
std::string errorDetailMessage;
|
||||
DestinationBuffer hDestination;
|
||||
hDestination.type = BufferType::SHARED_MEMORY;
|
||||
toSharedBuffer(plugin, destination, &hDestination.nonsecureMemory);
|
||||
Pattern noPattern = { 0, 0 };
|
||||
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, encryptedSubSamples, kSubSampleCount,
|
||||
out, &errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
SharedBuffer sourceBuffer;
|
||||
toSharedBuffer(plugin, source, &sourceBuffer);
|
||||
|
||||
plugin.decrypt(
|
||||
false, hidl_array<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(iv),
|
||||
Mode::AES_CTR, noPattern, hClearSubSamples, sourceBuffer, 0, hDestination,
|
||||
[&](Status status, uint32_t hBytesWritten, hidl_string hDetailedError) {
|
||||
EXPECT_EQ(status, Status::OK);
|
||||
|
||||
bytesWritten = hBytesWritten;
|
||||
errorDetailMessage.assign(hDetailedError.c_str());
|
||||
});
|
||||
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, mixedSubSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
plugin.decrypt(
|
||||
false, hidl_array<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(iv),
|
||||
Mode::AES_CTR, noPattern, hEncryptedSubSamples, 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(
|
||||
false, hidl_array<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(iv),
|
||||
Mode::AES_CTR, noPattern, hMixedSubSamples, 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) {
|
||||
@@ -422,7 +650,6 @@ TEST_F(WVCryptoPluginTest, AllowsSessionIdChanges) {
|
||||
|
||||
static const size_t kDataSize = 32;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[kDataSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||
@@ -431,20 +658,20 @@ TEST_F(WVCryptoPluginTest, AllowsSessionIdChanges) {
|
||||
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
||||
memset(subSamples, 0, sizeof(subSamples));
|
||||
subSamples[0].mNumBytesOfClearData = 16;
|
||||
subSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
SubSample subSample;
|
||||
subSample.numBytesOfClearData = 16;
|
||||
subSample.numBytesOfEncryptedData = 16;
|
||||
std::vector<SubSample> subSampleVector;
|
||||
subSampleVector.push_back(subSample);
|
||||
auto hSubSamples = hidl_vec<SubSample>(subSampleVector);
|
||||
|
||||
Vector<uint8_t> sessionIdVector;
|
||||
sessionIdVector.appendArray(sessionId, kSessionIdSize);
|
||||
Vector<uint8_t> sessionId2Vector;
|
||||
sessionId2Vector.appendArray(sessionId2, kSessionIdSize);
|
||||
std::vector<uint8_t> sessionIdVector(sessionId, sessionId + kSessionIdSize);
|
||||
std::vector<uint8_t> sessionId2Vector(sessionId2,
|
||||
sessionId2 + kSessionIdSize);
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
.WillRepeatedly(testing::Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
@@ -459,57 +686,97 @@ TEST_F(WVCryptoPluginTest, AllowsSessionIdChanges) {
|
||||
.Times(2);
|
||||
}
|
||||
|
||||
sp<MemoryDealer> memDealer = new MemoryDealer(
|
||||
kDataSize * 2, "WVCryptoPlugin_test");
|
||||
sp<android::IMemory> source = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(source, nullptr);
|
||||
pSrc = static_cast<uint8_t*>(
|
||||
static_cast<void*>(source->pointer()));
|
||||
ASSERT_NE(pSrc, nullptr);
|
||||
memcpy(pSrc, in, source->size());
|
||||
|
||||
sp<android::IMemory> destination = memDealer->allocate(kDataSize);
|
||||
ASSERT_NE(destination, nullptr);
|
||||
pDest = static_cast<uint8_t*>(
|
||||
static_cast<void*>(destination->pointer()));
|
||||
ASSERT_NE(pDest, nullptr);
|
||||
|
||||
uint8_t blank[1]; // Some compilers will not accept 0.
|
||||
WVCryptoPlugin plugin(blank, 0, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
ssize_t res;
|
||||
|
||||
res = plugin.setMediaDrmSession(sessionIdVector);
|
||||
EXPECT_EQ(android::NO_ERROR, res);
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
EXPECT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
uint32_t bytesWritten = 0;
|
||||
Status err = Status::OK;
|
||||
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<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(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());
|
||||
});
|
||||
|
||||
res = plugin.setMediaDrmSession(sessionId2Vector);
|
||||
EXPECT_EQ(android::NO_ERROR, res);
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
EXPECT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
status = plugin.setMediaDrmSession(sessionId2Vector);
|
||||
EXPECT_EQ(status, Status::OK);
|
||||
|
||||
plugin.decrypt(
|
||||
false, hidl_array<uint8_t, 16>(keyId), hidl_array<uint8_t, 16>(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<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
uint8_t blank[1]; // Some compilers will not accept 0.
|
||||
Vector<uint8_t> sessionIdVector;
|
||||
sessionIdVector.appendArray(sessionId, kSessionIdSize);
|
||||
std::vector<uint8_t> sessionIdVector(sessionId, sessionId + kSessionIdSize);
|
||||
|
||||
// Specify the expected calls to IsOpenSession
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(blank, 0)))
|
||||
.WillOnce(Return(false));
|
||||
.WillOnce(testing::Return(false));
|
||||
|
||||
EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(sessionId, kSessionIdSize)))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true));
|
||||
.WillOnce(testing::Return(false))
|
||||
.WillOnce(testing::Return(true));
|
||||
}
|
||||
|
||||
WVCryptoPlugin plugin(blank, 0, cdm.get());
|
||||
|
||||
ssize_t res;
|
||||
res = plugin.setMediaDrmSession(sessionIdVector);
|
||||
EXPECT_EQ(android::ERROR_DRM_SESSION_NOT_OPENED, res);
|
||||
res = plugin.setMediaDrmSession(sessionIdVector);
|
||||
EXPECT_EQ(android::NO_ERROR, res);
|
||||
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_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
@@ -0,0 +1,515 @@
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
#include "media/stagefright/foundation/AString.h"
|
||||
#include "media/stagefright/MediaErrors.h"
|
||||
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_types.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
#include "WVCryptoPlugin.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
using namespace wvcdm;
|
||||
using namespace wvdrm;
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
public:
|
||||
MOCK_METHOD1(IsOpenSession, bool(const CdmSessionId&));
|
||||
|
||||
MOCK_METHOD3(Decrypt, CdmResponseType(const CdmSessionId&, bool,
|
||||
const CdmDecryptionParameters&));
|
||||
|
||||
MOCK_METHOD2(QuerySessionStatus, CdmResponseType(const CdmSessionId&,
|
||||
CdmQueryMap*));
|
||||
};
|
||||
|
||||
class WVCryptoPluginTest : public Test {
|
||||
protected:
|
||||
static const uint32_t kSessionIdSize = 16;
|
||||
uint8_t sessionId[kSessionIdSize];
|
||||
|
||||
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<CdmResponseType>::Set(wvcdm::NO_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(WVCryptoPluginTest, CorrectlyReportsSecureBuffers) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
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(Return(true));
|
||||
|
||||
// Specify the expected calls to QuerySessionStatus
|
||||
EXPECT_CALL(*cdm, QuerySessionStatus(_, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(l1Map),
|
||||
Return(wvcdm::NO_ERROR)))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(l3Map),
|
||||
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";
|
||||
}
|
||||
|
||||
// Factory for matchers that perform deep matching of values against a
|
||||
// CdmDecryptionParameters struct. For use in the test AttemptsToDecrypt.
|
||||
class CDPMatcherFactory {
|
||||
public:
|
||||
// Some values do not change over the course of the test. To avoid having
|
||||
// to re-specify them at every call site, we pass them into the factory
|
||||
// constructor.
|
||||
CDPMatcherFactory(bool isSecure, CdmCipherMode cipherMode, uint8_t* keyId,
|
||||
void* out, size_t outLen)
|
||||
: mIsSecure(isSecure), mCipherMode(cipherMode), mKeyId(keyId),
|
||||
mOut(out), mOutLen(outLen) {}
|
||||
|
||||
Matcher<const CdmDecryptionParameters&> operator()(bool isEncrypted,
|
||||
uint8_t* in,
|
||||
size_t inLen,
|
||||
uint8_t* iv,
|
||||
size_t blockOffset,
|
||||
size_t outOffset,
|
||||
uint8_t flags) const {
|
||||
return Truly(CDPMatcher(mIsSecure, mCipherMode, mKeyId, mOut, mOutLen,
|
||||
isEncrypted, in, inLen, iv, blockOffset,
|
||||
outOffset, flags));
|
||||
}
|
||||
|
||||
private:
|
||||
// Predicate that validates that the fields of a passed-in
|
||||
// CdmDecryptionParameters match the values it was given at construction
|
||||
// time.
|
||||
class CDPMatcher {
|
||||
public:
|
||||
CDPMatcher(bool isSecure, CdmCipherMode cipherMode, uint8_t* keyId,
|
||||
void* out, size_t outLen, bool isEncrypted, uint8_t* in,
|
||||
size_t inLen, uint8_t* iv, size_t blockOffset,
|
||||
size_t outOffset, uint8_t flags)
|
||||
: mIsSecure(isSecure), mCipherMode(cipherMode), mKeyId(keyId),
|
||||
mOut(out), mOutLen(outLen), mIsEncrypted(isEncrypted), mIn(in),
|
||||
mInLen(inLen), mIv(iv), mBlockOffset(blockOffset),
|
||||
mOutOffset(outOffset), mFlags(flags) {}
|
||||
|
||||
bool operator()(const CdmDecryptionParameters& params) const {
|
||||
return params.is_secure == mIsSecure &&
|
||||
params.cipher_mode == mCipherMode &&
|
||||
Value(*params.key_id, ElementsAreArray(mKeyId, KEY_ID_SIZE)) &&
|
||||
params.decrypt_buffer == mOut &&
|
||||
params.decrypt_buffer_length == mOutLen &&
|
||||
params.is_encrypted == mIsEncrypted &&
|
||||
params.encrypt_buffer == mIn &&
|
||||
params.encrypt_length == mInLen &&
|
||||
Value(*params.iv, ElementsAreArray(mIv, KEY_IV_SIZE)) &&
|
||||
params.block_offset == mBlockOffset &&
|
||||
params.decrypt_buffer_offset == mOutOffset &&
|
||||
params.subsample_flags == mFlags;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mIsSecure;
|
||||
CdmCipherMode mCipherMode;
|
||||
uint8_t* mKeyId;
|
||||
void* mOut;
|
||||
size_t mOutLen;
|
||||
bool mIsEncrypted;
|
||||
uint8_t* mIn;
|
||||
size_t mInLen;
|
||||
uint8_t* mIv;
|
||||
size_t mBlockOffset;
|
||||
size_t mOutOffset;
|
||||
uint8_t mFlags;
|
||||
};
|
||||
|
||||
bool mIsSecure;
|
||||
CdmCipherMode mCipherMode;
|
||||
uint8_t* mKeyId;
|
||||
void* mOut;
|
||||
size_t mOutLen;
|
||||
};
|
||||
|
||||
TEST_F(WVCryptoPluginTest, AttemptsToDecrypt) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
uint8_t keyId[KEY_ID_SIZE];
|
||||
uint8_t baseIv[KEY_IV_SIZE];
|
||||
|
||||
static const size_t kDataSize = 185;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[kDataSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(keyId, sizeof(uint8_t), KEY_ID_SIZE, fp);
|
||||
fread(baseIv, sizeof(uint8_t), KEY_IV_SIZE, fp);
|
||||
fread(in, sizeof(uint8_t), kDataSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
static const size_t kSubSampleCount = 6;
|
||||
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
||||
memset(subSamples, 0, sizeof(subSamples));
|
||||
subSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
subSamples[1].mNumBytesOfClearData = 16;
|
||||
subSamples[1].mNumBytesOfEncryptedData = 16;
|
||||
subSamples[2].mNumBytesOfEncryptedData = 8;
|
||||
subSamples[3].mNumBytesOfClearData = 29;
|
||||
subSamples[3].mNumBytesOfEncryptedData = 24;
|
||||
subSamples[4].mNumBytesOfEncryptedData = 60;
|
||||
subSamples[5].mNumBytesOfEncryptedData = 16;
|
||||
|
||||
uint8_t iv[5][KEY_IV_SIZE];
|
||||
memcpy(iv[0], baseIv, sizeof(baseIv));
|
||||
iv[0][15] = 0;
|
||||
memcpy(iv[1], baseIv, sizeof(baseIv));
|
||||
iv[1][15] = 1;
|
||||
memcpy(iv[2], baseIv, sizeof(baseIv));
|
||||
iv[2][15] = 2;
|
||||
memcpy(iv[3], baseIv, sizeof(baseIv));
|
||||
iv[3][15] = 4;
|
||||
memcpy(iv[4], baseIv, sizeof(baseIv));
|
||||
iv[4][15] = 7;
|
||||
|
||||
CDPMatcherFactory ParamsAre =
|
||||
CDPMatcherFactory(false, kCipherModeCtr, keyId, out, kDataSize);
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
// SubSample 0
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in, 16, iv[0], 0, 0,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 1
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(false, in + 16, 16, iv[1], 0, 16, 0)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 32, 16, iv[1], 0, 32, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 2
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 48, 8, iv[2], 0, 48, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 3
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(false, in + 56, 29, iv[2], 0, 56, 0)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 85, 24, iv[2], 8, 85, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 4
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 109, 60, iv[3], 0, 109, 0)))
|
||||
.Times(1);
|
||||
|
||||
// SubSample 5
|
||||
EXPECT_CALL(*cdm, Decrypt(ElementsAreArray(sessionId, kSessionIdSize),
|
||||
true,
|
||||
ParamsAre(true, in + 169, 16, iv[4], 12, 169,
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv[0], CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount,
|
||||
out, &errorDetailMessage);
|
||||
|
||||
EXPECT_EQ(static_cast<ssize_t>(kDataSize), res) <<
|
||||
"WVCryptoPlugin decrypted the wrong number of bytes";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
|
||||
TEST_F(WVCryptoPluginTest, CommunicatesSecureBufferRequest) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
uint8_t keyId[KEY_ID_SIZE];
|
||||
uint8_t iv[KEY_IV_SIZE];
|
||||
|
||||
static const size_t kDataSize = 32;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[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);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
||||
memset(subSamples, 0, sizeof(subSamples));
|
||||
subSamples[0].mNumBytesOfClearData = 16;
|
||||
subSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::is_secure, false)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::is_secure, true)))
|
||||
.Times(2);
|
||||
}
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount,
|
||||
out, &errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
res = plugin.decrypt(true, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
TEST_F(WVCryptoPluginTest, SetsFlagsForMinimumSubsampleRuns) {
|
||||
android::sp<MockCDM> cdm = new MockCDM();
|
||||
|
||||
uint8_t keyId[KEY_ID_SIZE];
|
||||
uint8_t iv[KEY_IV_SIZE];
|
||||
|
||||
static const size_t kDataSize = 16;
|
||||
uint8_t in[kDataSize];
|
||||
uint8_t out[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);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample clearSubSamples[kSubSampleCount];
|
||||
memset(clearSubSamples, 0, sizeof(clearSubSamples));
|
||||
clearSubSamples[0].mNumBytesOfClearData = 16;
|
||||
|
||||
CryptoPlugin::SubSample encryptedSubSamples[kSubSampleCount];
|
||||
memset(encryptedSubSamples, 0, sizeof(encryptedSubSamples));
|
||||
encryptedSubSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
|
||||
CryptoPlugin::SubSample mixedSubSamples[kSubSampleCount];
|
||||
memset(mixedSubSamples, 0, sizeof(mixedSubSamples));
|
||||
mixedSubSamples[0].mNumBytesOfClearData = 8;
|
||||
mixedSubSamples[0].mNumBytesOfEncryptedData = 8;
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
typedef CdmDecryptionParameters CDP;
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample |
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_FirstSubsample)))
|
||||
.Times(1);
|
||||
|
||||
EXPECT_CALL(*cdm, Decrypt(_, _, Field(&CDP::subsample_flags,
|
||||
OEMCrypto_LastSubsample)))
|
||||
.Times(1);
|
||||
}
|
||||
|
||||
WVCryptoPlugin plugin(sessionId, kSessionIdSize, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
|
||||
ssize_t res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, clearSubSamples,
|
||||
kSubSampleCount, out, &errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, encryptedSubSamples, kSubSampleCount,
|
||||
out, &errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, mixedSubSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
ASSERT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
TEST_F(WVCryptoPluginTest, AllowsSessionIdChanges) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
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];
|
||||
uint8_t out[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);
|
||||
|
||||
static const uint32_t kSubSampleCount = 1;
|
||||
CryptoPlugin::SubSample subSamples[kSubSampleCount];
|
||||
memset(subSamples, 0, sizeof(subSamples));
|
||||
subSamples[0].mNumBytesOfClearData = 16;
|
||||
subSamples[0].mNumBytesOfEncryptedData = 16;
|
||||
|
||||
Vector<uint8_t> sessionIdVector;
|
||||
sessionIdVector.appendArray(sessionId, kSessionIdSize);
|
||||
Vector<uint8_t> sessionId2Vector;
|
||||
sessionId2Vector.appendArray(sessionId2, kSessionIdSize);
|
||||
|
||||
// Provide the expected behavior for IsOpenSession
|
||||
EXPECT_CALL(*cdm, IsOpenSession(_))
|
||||
.WillRepeatedly(Return(true));
|
||||
|
||||
// Specify the expected calls to Decrypt
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
EXPECT_CALL(*cdm,
|
||||
Decrypt(ElementsAreArray(sessionId, kSessionIdSize), _, _))
|
||||
.Times(2);
|
||||
|
||||
EXPECT_CALL(*cdm,
|
||||
Decrypt(ElementsAreArray(sessionId2, kSessionIdSize), _, _))
|
||||
.Times(2);
|
||||
}
|
||||
|
||||
uint8_t blank[1]; // Some compilers will not accept 0.
|
||||
WVCryptoPlugin plugin(blank, 0, cdm.get());
|
||||
android::CryptoPlugin::Pattern noPattern = {0};
|
||||
AString errorDetailMessage;
|
||||
ssize_t res;
|
||||
|
||||
res = plugin.setMediaDrmSession(sessionIdVector);
|
||||
EXPECT_EQ(android::NO_ERROR, res);
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
EXPECT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
|
||||
res = plugin.setMediaDrmSession(sessionId2Vector);
|
||||
EXPECT_EQ(android::NO_ERROR, res);
|
||||
res = plugin.decrypt(false, keyId, iv, CryptoPlugin::kMode_AES_CTR,
|
||||
noPattern, in, subSamples, kSubSampleCount, out,
|
||||
&errorDetailMessage);
|
||||
EXPECT_GE(res, 0) <<
|
||||
"WVCryptoPlugin returned an error";
|
||||
EXPECT_EQ(0u, errorDetailMessage.size()) <<
|
||||
"WVCryptoPlugin reported a detailed error message.";
|
||||
}
|
||||
|
||||
TEST_F(WVCryptoPluginTest, DisallowsUnopenedSessionIdChanges) {
|
||||
android::sp<StrictMock<MockCDM>> cdm = new StrictMock<MockCDM>();
|
||||
|
||||
uint8_t blank[1]; // Some compilers will not accept 0.
|
||||
Vector<uint8_t> sessionIdVector;
|
||||
sessionIdVector.appendArray(sessionId, kSessionIdSize);
|
||||
|
||||
// Specify the expected calls to IsOpenSession
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(blank, 0)))
|
||||
.WillOnce(Return(false));
|
||||
|
||||
EXPECT_CALL(*cdm, IsOpenSession(ElementsAreArray(sessionId, kSessionIdSize)))
|
||||
.WillOnce(Return(false))
|
||||
.WillOnce(Return(true));
|
||||
}
|
||||
|
||||
WVCryptoPlugin plugin(blank, 0, cdm.get());
|
||||
|
||||
ssize_t res;
|
||||
res = plugin.setMediaDrmSession(sessionIdVector);
|
||||
EXPECT_EQ(android::ERROR_DRM_SESSION_NOT_OPENED, res);
|
||||
res = plugin.setMediaDrmSession(sessionIdVector);
|
||||
EXPECT_EQ(android::NO_ERROR, res);
|
||||
}
|
||||
@@ -1,4 +1,8 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmdrmplugin
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
@@ -20,3 +24,34 @@ LOCAL_MODULE := libwvdrmdrmplugin
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmdrmplugin_hidl
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src/WVGenericCryptoInterface.cpp \
|
||||
src_hidl/WVDrmPlugin.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/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.memory@1.0 \
|
||||
|
||||
LOCAL_MODULE := libwvdrmdrmplugin_hidl
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
|
||||
355
libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h
Normal file
355
libwvdrmengine/mediadrm/include_hidl/WVDrmPlugin.h
Normal file
@@ -0,0 +1,355 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_DRM_PLUGIN_H_
|
||||
#define WV_DRM_PLUGIN_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <android/hardware/drm/1.0/IDrmPlugin.h>
|
||||
#include <android/hardware/drm/1.0/IDrmPluginListener.h>
|
||||
|
||||
#include "cdm_client_property_set.h"
|
||||
#include "cdm_identifier.h"
|
||||
#include "OEMCryptoCENC.h"
|
||||
#include "utils/String8.h"
|
||||
#include "utils/Vector.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
#include "WVGenericCryptoInterface.h"
|
||||
#include "WVTypes.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::EventType;
|
||||
using ::android::hardware::drm::V1_0::IDrmPlugin;
|
||||
using ::android::hardware::drm::V1_0::IDrmPluginListener;
|
||||
using ::android::hardware::drm::V1_0::KeyRequestType;
|
||||
using ::android::hardware::drm::V1_0::KeyStatus;
|
||||
using ::android::hardware::drm::V1_0::KeyType;
|
||||
using ::android::hardware::drm::V1_0::KeyValue;
|
||||
using ::android::hardware::drm::V1_0::SecureStop;
|
||||
using ::android::hardware::drm::V1_0::Status;
|
||||
using ::android::hardware::hidl_array;
|
||||
using ::android::hardware::hidl_string;
|
||||
using ::android::hardware::hidl_vec;
|
||||
using ::android::hardware::Return;
|
||||
using ::android::sp;
|
||||
|
||||
using android::status_t;
|
||||
using android::String8;
|
||||
using android::Vector;
|
||||
using std::map;
|
||||
using wvcdm::CdmIdentifier;
|
||||
using wvcdm::CdmKeyStatusMap;
|
||||
using wvcdm::CdmSessionId;
|
||||
using wvcdm::CdmResponseType;
|
||||
using wvcdm::WvContentDecryptionModule;
|
||||
|
||||
const OEMCrypto_Algorithm kInvalidCryptoAlgorithm =
|
||||
static_cast<OEMCrypto_Algorithm>(-1);
|
||||
|
||||
struct WVDrmPlugin : public IDrmPlugin, IDrmPluginListener,
|
||||
wvcdm::WvCdmEventListener {
|
||||
|
||||
WVDrmPlugin(const sp<WvContentDecryptionModule>& cdm,
|
||||
const std::string& appPackageName,
|
||||
WVGenericCryptoInterface* crypto);
|
||||
|
||||
virtual ~WVDrmPlugin();
|
||||
|
||||
Return<void> openSession(openSession_cb _hidl_cb) override;
|
||||
|
||||
Return<Status> closeSession(const hidl_vec<uint8_t>& sessionId) override;
|
||||
|
||||
Return<void> getKeyRequest(
|
||||
const hidl_vec<uint8_t>& scope,
|
||||
const hidl_vec<uint8_t>& initData,
|
||||
const hidl_string& mimeType,
|
||||
KeyType keyType,
|
||||
const hidl_vec<KeyValue>& optionalParameters,
|
||||
getKeyRequest_cb _hidl_cb) override;
|
||||
|
||||
Return<void> provideKeyResponse(
|
||||
const hidl_vec<uint8_t>& scope,
|
||||
const hidl_vec<uint8_t>& response,
|
||||
provideKeyResponse_cb _hidl_cb) override;
|
||||
|
||||
Return<Status> removeKeys(const hidl_vec<uint8_t>& sessionId) override;
|
||||
|
||||
Return<Status> restoreKeys(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<uint8_t>& keySetId) override;
|
||||
|
||||
Return<void> queryKeyStatus(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
queryKeyStatus_cb _hidl_cb) override;
|
||||
|
||||
Return<void> getProvisionRequest(
|
||||
const hidl_string& certificateType,
|
||||
const hidl_string& certificateAuthority,
|
||||
getProvisionRequest_cb _hidl_cb) override;
|
||||
|
||||
Return<void> provideProvisionResponse(
|
||||
const hidl_vec<uint8_t>& response,
|
||||
provideProvisionResponse_cb _hidl_cb) override;
|
||||
|
||||
Return<void> getSecureStops(getSecureStops_cb _hidl_cb) override;
|
||||
|
||||
Return<void> getSecureStop(
|
||||
const hidl_vec<uint8_t>& secureStopId,
|
||||
getSecureStop_cb _hidl_cb) override;
|
||||
|
||||
Return<Status> releaseAllSecureStops() override;
|
||||
|
||||
Return<Status> releaseSecureStop(
|
||||
const hidl_vec<uint8_t>& secureStopId) override;
|
||||
|
||||
Return<void> getPropertyString(
|
||||
const hidl_string& propertyName,
|
||||
getPropertyString_cb _hidl_cb) override;
|
||||
|
||||
Return<void> getPropertyByteArray(
|
||||
const hidl_string& propertyName,
|
||||
getPropertyByteArray_cb _hidl_cb) override;
|
||||
|
||||
Return<Status> setPropertyString(
|
||||
const hidl_string& propertyName,
|
||||
const hidl_string& value) override;
|
||||
|
||||
Return<Status> setPropertyByteArray(
|
||||
const hidl_string& propertyName,
|
||||
const hidl_vec<uint8_t>& value) override;
|
||||
|
||||
Return<Status> setCipherAlgorithm(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_string& algorithm) override;
|
||||
|
||||
Return<Status> setMacAlgorithm(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_string& algorithm) override;
|
||||
|
||||
Return<void> encrypt(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<uint8_t>& keyId,
|
||||
const hidl_vec<uint8_t>& input,
|
||||
const hidl_vec<uint8_t>& iv,
|
||||
encrypt_cb _hidl_cb) override;
|
||||
|
||||
Return<void> decrypt(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<uint8_t>& keyId,
|
||||
const hidl_vec<uint8_t>& input,
|
||||
const hidl_vec<uint8_t>& iv,
|
||||
decrypt_cb _hidl_cb) override;
|
||||
|
||||
Return<void> sign(const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<uint8_t>& keyId, const hidl_vec<uint8_t>& message,
|
||||
sign_cb _hidl_cb) override;
|
||||
|
||||
Return<void> verify(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<uint8_t>& keyId,
|
||||
const hidl_vec<uint8_t>& message,
|
||||
const hidl_vec<uint8_t>& signature,
|
||||
verify_cb _hidl_cb) override;
|
||||
|
||||
Return<void> signRSA(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_string& algorithm,
|
||||
const hidl_vec<uint8_t>& message,
|
||||
const hidl_vec<uint8_t>& wrappedkey,
|
||||
signRSA_cb _hidl_cb) override;
|
||||
|
||||
Return<void> setListener(const sp<IDrmPluginListener>& listener) override;
|
||||
|
||||
Return<void> sendEvent(
|
||||
EventType eventType,
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<uint8_t>& data) override;
|
||||
|
||||
Return<void> sendExpirationUpdate(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
int64_t expiryTimeInMS) override;
|
||||
|
||||
Return<void> sendKeysChange(
|
||||
const hidl_vec<uint8_t>& sessionId,
|
||||
const hidl_vec<KeyStatus>& keyStatusList,
|
||||
bool hasNewUsableKey) override;
|
||||
|
||||
// The following methods do not use hidl interface, it is used internally.
|
||||
virtual status_t unprovisionDevice();
|
||||
|
||||
virtual void OnSessionRenewalNeeded(const CdmSessionId& cdmSessionId);
|
||||
|
||||
virtual void OnSessionKeysChange(
|
||||
const CdmSessionId& cdmSessionId,
|
||||
const CdmKeyStatusMap& cdmKeysStatus,
|
||||
bool hasNewUsableKey);
|
||||
|
||||
virtual void OnExpirationUpdate(
|
||||
const CdmSessionId& cdmSessionId,
|
||||
int64_t newExpiryTimeSeconds);
|
||||
|
||||
private:
|
||||
WVDRM_DISALLOW_COPY_AND_ASSIGN_AND_NEW(WVDrmPlugin);
|
||||
|
||||
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) {}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
|
||||
|
||||
std::string mSecurityLevel;
|
||||
bool mUsePrivacyMode;
|
||||
std::string mServiceCertificate;
|
||||
bool mShareKeys;
|
||||
uint32_t mSessionSharingId;
|
||||
std::string mAppId;
|
||||
const std::string mEmptyString;
|
||||
} mPropertySet;
|
||||
|
||||
std::string mAppPackageName;
|
||||
sp<wvcdm::WvContentDecryptionModule> const mCDM;
|
||||
CdmIdentifier mCdmIdentifier;
|
||||
WVGenericCryptoInterface* mCrypto;
|
||||
map<CdmSessionId, CryptoSession> mCryptoSessions;
|
||||
sp<IDrmPluginListener> mListener;
|
||||
|
||||
const std::string& appPackageName() const {
|
||||
return mAppPackageName;
|
||||
}
|
||||
|
||||
status_t queryProperty(const std::string& property,
|
||||
std::string& stringValue) const;
|
||||
|
||||
status_t queryProperty(wvcdm::SecurityLevel securityLevel,
|
||||
const std::string& property,
|
||||
std::string& stringValue) const;
|
||||
|
||||
status_t queryProperty(const std::string& property,
|
||||
String8& string8_value) const;
|
||||
|
||||
status_t queryProperty(const std::string& property,
|
||||
Vector<uint8_t>& vector_value) const;
|
||||
|
||||
status_t mapAndNotifyOfCdmResponseType(const Vector<uint8_t>& sessionId,
|
||||
CdmResponseType res);
|
||||
|
||||
status_t mapAndNotifyOfOEMCryptoResult(const Vector<uint8_t>& sessionId,
|
||||
OEMCryptoResult res);
|
||||
|
||||
status_t mapOEMCryptoResult(OEMCryptoResult res);
|
||||
|
||||
bool initDataResemblesPSSH(const Vector<uint8_t>& initData);
|
||||
|
||||
status_t unprovision(const CdmIdentifier& identifier);
|
||||
};
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
#endif // WV_DRM_PLUGIN_H_
|
||||
1249
libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp
Normal file
1249
libwvdrmengine/mediadrm/src_hidl/WVDrmPlugin.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,12 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmdrmplugin_test
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
WVDrmPlugin_test.cpp \
|
||||
legacy_src/WVDrmPlugin_test.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
frameworks/av/include \
|
||||
@@ -38,10 +42,68 @@ LOCAL_SHARED_LIBRARIES := \
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/protobuf/src \
|
||||
|
||||
# End protobuf section
|
||||
|
||||
LOCAL_MODULE := libwvdrmdrmplugin_test
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmdrmplugin_hidl_test
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
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/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcdm \
|
||||
libcdm_protos \
|
||||
libcdm_utils \
|
||||
libcrypto_static \
|
||||
libjsmn \
|
||||
libgmock \
|
||||
libgmock_main \
|
||||
libgtest \
|
||||
libwvlevel3 \
|
||||
libwvdrmdrmplugin_hidl \
|
||||
|
||||
# When the GNU linker sees a library, it discards all symbols that it doesn't
|
||||
# need. libhidl_utils must come after libwvdrmdrmplugin.
|
||||
LOCAL_STATIC_LIBRARIES += libhidl_utils
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
android.hidl.base@1.0 \
|
||||
android.hidl.memory@1.0 \
|
||||
libbinder \
|
||||
libcutils \
|
||||
libdl \
|
||||
libhidlbase \
|
||||
libhidlmemory \
|
||||
liblog \
|
||||
libmedia \
|
||||
libprotobuf-cpp-lite \
|
||||
libstagefright_foundation \
|
||||
libutils \
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
external/protobuf/src \
|
||||
|
||||
LOCAL_MODULE := libwvdrmdrmplugin_hidl_test
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1861
libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp
Normal file
1861
libwvdrmengine/mediadrm/test/legacy_src/WVDrmPlugin_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -71,7 +71,9 @@ adb_shell_run request_license_test
|
||||
adb_shell_run policy_engine_unittest
|
||||
adb_shell_run policy_engine_constraints_unittest
|
||||
adb_shell_run libwvdrmmediacrypto_test
|
||||
adb_shell_run libwvdrmmediacrypto_hidl_test
|
||||
adb_shell_run libwvdrmdrmplugin_test
|
||||
adb_shell_run libwvdrmdrmplugin_hidl_test
|
||||
adb_shell_run cdm_engine_test
|
||||
adb_shell_run cdm_session_unittest
|
||||
adb_shell_run file_store_unittest
|
||||
@@ -89,14 +91,9 @@ adb_shell_run event_metric_test
|
||||
library_path="/system/vendor/lib/mediadrm/ "
|
||||
adb_shell_run libwvdrmengine_test LD_LIBRARY_PATH=$library_path
|
||||
|
||||
library_path="/system/vendor/lib/hw/ "
|
||||
adb_shell_run libwvdrmengine_hidl_test LD_LIBRARY_PATH=$library_path
|
||||
|
||||
# Re-enable DroidGuard
|
||||
set_droidguard enable
|
||||
|
||||
adb shell am start com.widevine.test/com.widevine.test.MediaDrmAPITest
|
||||
if [ $final_result -eq 0 ]; then
|
||||
echo "MediaDrm unittests completed successfully!"
|
||||
else
|
||||
printf '\n%s\n' "${failed_tests[@]}"
|
||||
exit $final_result
|
||||
fi
|
||||
|
||||
|
||||
74
libwvdrmengine/src_hidl/TypeConvert.cpp
Normal file
74
libwvdrmengine/src_hidl/TypeConvert.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "TypeConvert.h"
|
||||
|
||||
namespace android {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
Status toStatus(status_t mediaError) {
|
||||
Status status;
|
||||
switch(mediaError) {
|
||||
case android::OK:
|
||||
status = Status::OK;
|
||||
break;
|
||||
case android::ERROR_DRM_NO_LICENSE:
|
||||
status = Status::ERROR_DRM_NO_LICENSE;
|
||||
break;
|
||||
case android::ERROR_DRM_LICENSE_EXPIRED:
|
||||
status = Status::ERROR_DRM_LICENSE_EXPIRED;
|
||||
break;
|
||||
case android::ERROR_DRM_SESSION_NOT_OPENED:
|
||||
status = Status::ERROR_DRM_SESSION_NOT_OPENED;
|
||||
break;
|
||||
case android::ERROR_DRM_CANNOT_HANDLE:
|
||||
status = Status::ERROR_DRM_CANNOT_HANDLE;
|
||||
break;
|
||||
case android::ERROR_DRM_TAMPER_DETECTED:
|
||||
status = Status::ERROR_DRM_INVALID_STATE;
|
||||
break;
|
||||
case android::BAD_VALUE:
|
||||
status = Status::BAD_VALUE;
|
||||
break;
|
||||
case android::ERROR_DRM_NOT_PROVISIONED:
|
||||
status = Status::ERROR_DRM_NOT_PROVISIONED;
|
||||
break;
|
||||
case android::ERROR_DRM_RESOURCE_BUSY:
|
||||
status = Status::ERROR_DRM_RESOURCE_BUSY;
|
||||
break;
|
||||
case android::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION:
|
||||
status = Status::ERROR_DRM_INSUFFICIENT_OUTPUT_PROTECTION;
|
||||
break;
|
||||
case android::ERROR_DRM_DEVICE_REVOKED:
|
||||
status = Status::ERROR_DRM_DEVICE_REVOKED;
|
||||
break;
|
||||
default:
|
||||
ALOGW("Unable to convert legacy status: %d, defaulting to UNKNOWN",
|
||||
mediaError);
|
||||
status = Status::ERROR_DRM_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace android
|
||||
31
libwvdrmengine/src_hidl/WVCreatePluginFactories.cpp
Normal file
31
libwvdrmengine/src_hidl/WVCreatePluginFactories.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#include "WVCreatePluginFactories.h"
|
||||
|
||||
#include "WVCryptoFactory.h"
|
||||
#include "WVDrmFactory.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
extern "C" {
|
||||
|
||||
IDrmFactory* createDrmFactory() {
|
||||
return new WVDrmFactory();
|
||||
}
|
||||
|
||||
ICryptoFactory* createCryptoFactory() {
|
||||
return new WVCryptoFactory();
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
50
libwvdrmengine/src_hidl/WVCryptoFactory.cpp
Normal file
50
libwvdrmengine/src_hidl/WVCryptoFactory.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "WVCdm"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "WVCryptoFactory.h"
|
||||
#include "WVCDMSingleton.h"
|
||||
#include "WVCryptoPlugin.h"
|
||||
#include "WVUUID.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::Status;
|
||||
using ::android::hardware::Void;
|
||||
|
||||
Return<bool> WVCryptoFactory::isCryptoSchemeSupported(
|
||||
const hidl_array<uint8_t, 16>& uuid) {
|
||||
return isWidevineUUID(uuid.data());
|
||||
}
|
||||
|
||||
Return<void> WVCryptoFactory::createPlugin(
|
||||
const hidl_array<uint8_t, 16>& uuid,
|
||||
const hidl_vec<uint8_t>& initData,
|
||||
createPlugin_cb _hidl_cb) {
|
||||
|
||||
WVCryptoPlugin *plugin = NULL;
|
||||
if (!isCryptoSchemeSupported(uuid.data())) {
|
||||
ALOGE("Widevine Drm HAL: failed to create crypto plugin, " \
|
||||
"invalid crypto scheme");
|
||||
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, plugin);
|
||||
return Void();
|
||||
}
|
||||
|
||||
plugin = new WVCryptoPlugin(initData.data(), initData.size(), getCDM());
|
||||
_hidl_cb(Status::OK, plugin);
|
||||
return Void();
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
61
libwvdrmengine/src_hidl/WVDrmFactory.cpp
Normal file
61
libwvdrmengine/src_hidl/WVDrmFactory.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
//
|
||||
// Copyright 2017 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "WVCdm"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "WVDrmFactory.h"
|
||||
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "WVCDMSingleton.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
#include "WVDrmPlugin.h"
|
||||
#include "WVUUID.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::drm::V1_0::Status;
|
||||
using ::android::hardware::Void;
|
||||
|
||||
WVGenericCryptoInterface WVDrmFactory::sOemCryptoInterface;
|
||||
|
||||
Return<bool> WVDrmFactory::isCryptoSchemeSupported(
|
||||
const hidl_array<uint8_t, 16>& uuid) {
|
||||
return isWidevineUUID(uuid.data());
|
||||
}
|
||||
|
||||
Return<bool> WVDrmFactory::isContentTypeSupported(
|
||||
const hidl_string& initDataType) {
|
||||
return wvcdm::WvContentDecryptionModule::IsSupported(initDataType.c_str());
|
||||
}
|
||||
|
||||
Return<void> WVDrmFactory::createPlugin(
|
||||
const hidl_array<uint8_t, 16>& uuid,
|
||||
const hidl_string& appPackageName,
|
||||
createPlugin_cb _hidl_cb) {
|
||||
|
||||
WVDrmPlugin *plugin = NULL;
|
||||
if (!isCryptoSchemeSupported(uuid.data())) {
|
||||
ALOGE("Widevine Drm HAL: failed to create drm plugin, " \
|
||||
"invalid crypto scheme");
|
||||
_hidl_cb(Status::BAD_VALUE, plugin);
|
||||
return Void();
|
||||
}
|
||||
|
||||
plugin = new WVDrmPlugin(getCDM(), appPackageName.c_str(),
|
||||
&sOemCryptoInterface);
|
||||
_hidl_cb(Status::OK, plugin);
|
||||
return Void();
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
@@ -0,0 +1,6 @@
|
||||
service drm-widevine-hal-1-0 /vendor/bin/hw/android.hardware.drm@1.0-service.widevine
|
||||
class hal
|
||||
user media
|
||||
group mediadrm drmrpc
|
||||
ioprio rt 4
|
||||
writepid /dev/cpuset/foreground/tasks
|
||||
48
libwvdrmengine/src_hidl/service.cpp
Normal file
48
libwvdrmengine/src_hidl/service.cpp
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright 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.
|
||||
*/
|
||||
#define LOG_TAG "android.hardware.drm@1.0-service.widevine"
|
||||
|
||||
#include <WVCryptoFactory.h>
|
||||
#include <WVDrmFactory.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <hidl/HidlTransportSupport.h>
|
||||
|
||||
using ::android::hardware::configureRpcThreadpool;
|
||||
using ::android::hardware::joinRpcThreadpool;
|
||||
using ::android::sp;
|
||||
|
||||
using android::hardware::drm::V1_0::ICryptoFactory;
|
||||
using android::hardware::drm::V1_0::IDrmFactory;
|
||||
using wvdrm::hardware::drm::V1_0::widevine::WVCryptoFactory;
|
||||
using wvdrm::hardware::drm::V1_0::widevine::WVDrmFactory;
|
||||
|
||||
int main(int /* argc */, char** /* argv */) {
|
||||
ALOGD("android.hardware.drm@1.0-service.widevine starting...");
|
||||
|
||||
sp<IDrmFactory> drmFactory = new WVDrmFactory;
|
||||
sp<ICryptoFactory> cryptoFactory = new WVCryptoFactory;
|
||||
|
||||
configureRpcThreadpool(8, true /* callerWillJoin */);
|
||||
|
||||
// Setup hwbinder service
|
||||
CHECK_EQ(drmFactory->registerAsService("widevine"), android::NO_ERROR)
|
||||
<< "Failed to register Widevine Factory HAL";
|
||||
CHECK_EQ(cryptoFactory->registerAsService("widevine"), android::NO_ERROR)
|
||||
<< "Failed to register Widevine Crypto HAL";
|
||||
|
||||
joinRpcThreadpool();
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmengine_test
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
WVCreatePluginFactories_test.cpp \
|
||||
WVCryptoFactory_test.cpp \
|
||||
WVDrmFactory_test.cpp \
|
||||
legacy_src/WVCreatePluginFactories_test.cpp \
|
||||
legacy_src/WVCryptoFactory_test.cpp \
|
||||
legacy_src/WVDrmFactory_test.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
frameworks/av/include \
|
||||
@@ -31,3 +35,44 @@ LOCAL_MODULE := libwvdrmengine_test
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Builds libwvdrmengine_hidl_test
|
||||
#
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
WVCreatePluginFactories_test.cpp \
|
||||
WVCryptoFactory_test.cpp \
|
||||
WVDrmFactory_test.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
frameworks/av/include \
|
||||
frameworks/native/include \
|
||||
vendor/widevine/libwvdrmengine/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include_hidl \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
vendor/widevine/libwvdrmengine/oemcrypto/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcrypto_static \
|
||||
libgtest \
|
||||
libgtest_main \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
android.hardware.drm@1.0 \
|
||||
libdl \
|
||||
libhidlbase \
|
||||
libhidlmemory \
|
||||
liblog \
|
||||
libmedia \
|
||||
libstagefright_foundation \
|
||||
libutils \
|
||||
libwvhidl \
|
||||
|
||||
LOCAL_MODULE := libwvdrmengine_hidl_test
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
|
||||
@@ -3,21 +3,34 @@
|
||||
//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <UniquePtr.h>
|
||||
#include "WVCreatePluginFactories.h"
|
||||
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::sp;
|
||||
|
||||
using namespace android;
|
||||
|
||||
TEST(CreatePluginFactoriesTest, CreatesDrmFactory) {
|
||||
UniquePtr<DrmFactory> factory(createDrmFactory());
|
||||
sp<IDrmFactory> factory(createDrmFactory());
|
||||
|
||||
EXPECT_NE((DrmFactory*)NULL, factory.get()) <<
|
||||
EXPECT_NE((IDrmFactory*)NULL, factory.get()) <<
|
||||
"createDrmFactory() returned null";
|
||||
}
|
||||
|
||||
TEST(CreatePluginFactoriesTest, CreatesCryptoFactory) {
|
||||
UniquePtr<CryptoFactory> factory(createCryptoFactory());
|
||||
sp<ICryptoFactory> factory(createCryptoFactory());
|
||||
|
||||
EXPECT_NE((CryptoFactory*)NULL, factory.get()) <<
|
||||
EXPECT_NE((ICryptoFactory*)NULL, factory.get()) <<
|
||||
"createCryptoFactory() returned null";
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
@@ -2,12 +2,17 @@
|
||||
* Copyright 2012 Google Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <UniquePtr.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "WVCryptoFactory.h"
|
||||
|
||||
using namespace wvdrm;
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using wvdrm::hardware::drm::V1_0::widevine::WVCryptoFactory;
|
||||
using ::android::sp;
|
||||
|
||||
const uint8_t kWidevineUUID[16] = {
|
||||
0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
|
||||
@@ -25,7 +30,7 @@ const uint8_t kUnknownUUID[16] = {
|
||||
};
|
||||
|
||||
TEST(WVCryptoFactoryTest, SupportsSupportedCryptoSchemes) {
|
||||
UniquePtr<WVCryptoFactory> factory(new WVCryptoFactory());
|
||||
sp<WVCryptoFactory> factory(new WVCryptoFactory());
|
||||
|
||||
EXPECT_TRUE(factory->isCryptoSchemeSupported(kWidevineUUID)) <<
|
||||
"WVPluginFactory does not support Widevine's UUID";
|
||||
@@ -35,8 +40,14 @@ TEST(WVCryptoFactoryTest, SupportsSupportedCryptoSchemes) {
|
||||
}
|
||||
|
||||
TEST(WVCryptoFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) {
|
||||
UniquePtr<WVCryptoFactory> factory(new WVCryptoFactory());
|
||||
sp<WVCryptoFactory> factory(new WVCryptoFactory());
|
||||
|
||||
EXPECT_FALSE(factory->isCryptoSchemeSupported(kUnknownUUID)) <<
|
||||
"WVPluginFactory incorrectly claims to support an unknown UUID";
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
@@ -3,10 +3,17 @@
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <UniquePtr.h>
|
||||
#include "WVDrmFactory.h"
|
||||
|
||||
using namespace wvdrm;
|
||||
namespace wvdrm {
|
||||
namespace hardware {
|
||||
namespace drm {
|
||||
namespace V1_0 {
|
||||
namespace widevine {
|
||||
|
||||
using ::android::hardware::hidl_string;
|
||||
using wvdrm::hardware::drm::V1_0::widevine::WVDrmFactory;
|
||||
|
||||
using namespace android;
|
||||
|
||||
const uint8_t kWidevineUUID[16] = {
|
||||
@@ -44,16 +51,16 @@ TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) {
|
||||
TEST(WVDrmFactoryTest, SupportsSupportedContainerFormats) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/mp4"))) <<
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(hidl_string("video/mp4"))) <<
|
||||
"WVPluginFactory does not support ISO-BMFF video";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/mp4"))) <<
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(hidl_string("audio/mp4"))) <<
|
||||
"WVPluginFactory does not support ISO-BMFF audio";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/webm"))) <<
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(hidl_string("video/webm"))) <<
|
||||
"WVPluginFactory does not support WebM video";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/webm"))) <<
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(hidl_string("audio/webm"))) <<
|
||||
"WVPluginFactory does not support WebM audio";
|
||||
}
|
||||
|
||||
@@ -61,27 +68,33 @@ TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedContainerFormats) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
// Taken from Encoding.com's list of the most common internet video MIME-types
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-matroska"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/x-matroska"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Matroska";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-flv"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/x-flv"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Flash Video";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("application/x-mpegURL"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("application/x-mpegURL"))) <<
|
||||
"WVPluginFactory incorrectly claims to support m3u8 Indexes";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/MP2T"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/MP2T"))) <<
|
||||
"WVPluginFactory incorrectly claims to support MPEG-2 TS";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/3gpp"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/3gpp"))) <<
|
||||
"WVPluginFactory incorrectly claims to support 3GP Mobile";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/quicktime"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/quicktime"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Quicktime";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-msvideo"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/x-msvideo"))) <<
|
||||
"WVPluginFactory incorrectly claims to support AVI";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-ms-wmv"))) <<
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(hidl_string("video/x-ms-wmv"))) <<
|
||||
"WVPluginFactory incorrectly claims to support WMV";
|
||||
}
|
||||
|
||||
} // namespace widevine
|
||||
} // namespace V1_0
|
||||
} // namespace drm
|
||||
} // namespace hardware
|
||||
} // namespace wvdrm
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <UniquePtr.h>
|
||||
#include "WVCreatePluginFactories.h"
|
||||
|
||||
using namespace android;
|
||||
|
||||
TEST(CreatePluginFactoriesTest, CreatesDrmFactory) {
|
||||
UniquePtr<DrmFactory> factory(createDrmFactory());
|
||||
|
||||
EXPECT_NE((DrmFactory*)NULL, factory.get()) <<
|
||||
"createDrmFactory() returned null";
|
||||
}
|
||||
|
||||
TEST(CreatePluginFactoriesTest, CreatesCryptoFactory) {
|
||||
UniquePtr<CryptoFactory> factory(createCryptoFactory());
|
||||
|
||||
EXPECT_NE((CryptoFactory*)NULL, factory.get()) <<
|
||||
"createCryptoFactory() returned null";
|
||||
}
|
||||
42
libwvdrmengine/test/unit/legacy_src/WVCryptoFactory_test.cpp
Normal file
42
libwvdrmengine/test/unit/legacy_src/WVCryptoFactory_test.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include <UniquePtr.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "WVCryptoFactory.h"
|
||||
|
||||
using namespace wvdrm;
|
||||
|
||||
const uint8_t kWidevineUUID[16] = {
|
||||
0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
|
||||
0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
|
||||
};
|
||||
|
||||
const uint8_t kOldNetflixWidevineUUID[16] = {
|
||||
0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34,
|
||||
0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47
|
||||
};
|
||||
|
||||
const uint8_t kUnknownUUID[16] = {
|
||||
0x6A,0x7F,0xAA,0xB0,0x83,0xC7,0x9E,0x20,
|
||||
0x08,0xBC,0xEF,0x32,0x34,0x1A,0x9A,0x26
|
||||
};
|
||||
|
||||
TEST(WVCryptoFactoryTest, SupportsSupportedCryptoSchemes) {
|
||||
UniquePtr<WVCryptoFactory> factory(new WVCryptoFactory());
|
||||
|
||||
EXPECT_TRUE(factory->isCryptoSchemeSupported(kWidevineUUID)) <<
|
||||
"WVPluginFactory does not support Widevine's UUID";
|
||||
|
||||
EXPECT_TRUE(factory->isCryptoSchemeSupported(kOldNetflixWidevineUUID)) <<
|
||||
"WVPluginFactory does not support the old Netflix Widevine UUID";
|
||||
}
|
||||
|
||||
TEST(WVCryptoFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) {
|
||||
UniquePtr<WVCryptoFactory> factory(new WVCryptoFactory());
|
||||
|
||||
EXPECT_FALSE(factory->isCryptoSchemeSupported(kUnknownUUID)) <<
|
||||
"WVPluginFactory incorrectly claims to support an unknown UUID";
|
||||
}
|
||||
87
libwvdrmengine/test/unit/legacy_src/WVDrmFactory_test.cpp
Normal file
87
libwvdrmengine/test/unit/legacy_src/WVDrmFactory_test.cpp
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright 2012 Google Inc. All Rights Reserved.
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include <UniquePtr.h>
|
||||
#include "WVDrmFactory.h"
|
||||
|
||||
using namespace wvdrm;
|
||||
using namespace android;
|
||||
|
||||
const uint8_t kWidevineUUID[16] = {
|
||||
0xED,0xEF,0x8B,0xA9,0x79,0xD6,0x4A,0xCE,
|
||||
0xA3,0xC8,0x27,0xDC,0xD5,0x1D,0x21,0xED
|
||||
};
|
||||
|
||||
const uint8_t kOldNetflixWidevineUUID[16] = {
|
||||
0x29,0x70,0x1F,0xE4,0x3C,0xC7,0x4A,0x34,
|
||||
0x8C,0x5B,0xAE,0x90,0xC7,0x43,0x9A,0x47
|
||||
};
|
||||
|
||||
const uint8_t kUnknownUUID[16] = {
|
||||
0x6A,0x7F,0xAA,0xB0,0x83,0xC7,0x9E,0x20,
|
||||
0x08,0xBC,0xEF,0x32,0x34,0x1A,0x9A,0x26
|
||||
};
|
||||
|
||||
TEST(WVDrmFactoryTest, SupportsSupportedCryptoSchemes) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
EXPECT_TRUE(factory.isCryptoSchemeSupported(kWidevineUUID)) <<
|
||||
"WVPluginFactory does not support Widevine's UUID";
|
||||
|
||||
EXPECT_TRUE(factory.isCryptoSchemeSupported(kOldNetflixWidevineUUID)) <<
|
||||
"WVPluginFactory does not support the old Netflix Widevine UUID";
|
||||
}
|
||||
|
||||
TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedCryptoSchemes) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
EXPECT_FALSE(factory.isCryptoSchemeSupported(kUnknownUUID)) <<
|
||||
"WVPluginFactory incorrectly claims to support an unknown UUID";
|
||||
}
|
||||
|
||||
TEST(WVDrmFactoryTest, SupportsSupportedContainerFormats) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/mp4"))) <<
|
||||
"WVPluginFactory does not support ISO-BMFF video";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/mp4"))) <<
|
||||
"WVPluginFactory does not support ISO-BMFF audio";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("video/webm"))) <<
|
||||
"WVPluginFactory does not support WebM video";
|
||||
|
||||
EXPECT_TRUE(factory.isContentTypeSupported(String8("audio/webm"))) <<
|
||||
"WVPluginFactory does not support WebM audio";
|
||||
}
|
||||
|
||||
TEST(WVDrmFactoryTest, DoesNotSupportUnsupportedContainerFormats) {
|
||||
WVDrmFactory factory;
|
||||
|
||||
// Taken from Encoding.com's list of the most common internet video MIME-types
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-matroska"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Matroska";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-flv"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Flash Video";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("application/x-mpegURL"))) <<
|
||||
"WVPluginFactory incorrectly claims to support m3u8 Indexes";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/MP2T"))) <<
|
||||
"WVPluginFactory incorrectly claims to support MPEG-2 TS";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/3gpp"))) <<
|
||||
"WVPluginFactory incorrectly claims to support 3GP Mobile";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/quicktime"))) <<
|
||||
"WVPluginFactory incorrectly claims to support Quicktime";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-msvideo"))) <<
|
||||
"WVPluginFactory incorrectly claims to support AVI";
|
||||
|
||||
EXPECT_FALSE(factory.isContentTypeSupported(String8("video/x-ms-wmv"))) <<
|
||||
"WVPluginFactory incorrectly claims to support WMV";
|
||||
}
|
||||
Reference in New Issue
Block a user