Initial import of Widevine Common Encryption DRM engine
Builds libwvmdrmengine.so, which is loaded by the new MediaDrm APIs to support playback of Widevine/CENC protected content. Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
This commit is contained in:
20
libwvdrmengine/mediadrm/Android.mk
Normal file
20
libwvdrmengine/mediadrm/Android.mk
Normal file
@@ -0,0 +1,20 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
src/WVDrmPlugin.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
bionic \
|
||||
external/stlport/stlport \
|
||||
frameworks/av/include \
|
||||
frameworks/native/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
|
||||
LOCAL_MODULE := libwvdrmdrmplugin
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
||||
80
libwvdrmengine/mediadrm/include/WVDrmPlugin.h
Normal file
80
libwvdrmengine/mediadrm/include/WVDrmPlugin.h
Normal file
@@ -0,0 +1,80 @@
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_DRM_PLUGIN_H_
|
||||
#define WV_DRM_PLUGIN_H_
|
||||
|
||||
#include "media/drm/DrmAPI.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
#include "media/stagefright/foundation/AString.h"
|
||||
#include "utils/Errors.h"
|
||||
#include "utils/KeyedVector.h"
|
||||
#include "utils/List.h"
|
||||
#include "utils/String8.h"
|
||||
#include "utils/Vector.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
|
||||
namespace wvdrm {
|
||||
|
||||
using android::KeyedVector;
|
||||
using android::List;
|
||||
using android::status_t;
|
||||
using android::String8;
|
||||
using android::Vector;
|
||||
|
||||
class WVDrmPlugin : public android::DrmPlugin {
|
||||
public:
|
||||
WVDrmPlugin(wvcdm::WvContentDecryptionModule* cdm);
|
||||
virtual ~WVDrmPlugin() {}
|
||||
|
||||
virtual status_t openSession(Vector<uint8_t>& sessionId);
|
||||
|
||||
virtual status_t closeSession(const Vector<uint8_t>& sessionId);
|
||||
|
||||
virtual status_t getLicenseRequest(
|
||||
const Vector<uint8_t>& sessionId,
|
||||
const Vector<uint8_t>& initData,
|
||||
const String8& mimeType,
|
||||
LicenseType licenseType,
|
||||
const KeyedVector<String8, String8>& optionalParameters,
|
||||
Vector<uint8_t>& request,
|
||||
String8& defaultUrl);
|
||||
|
||||
virtual status_t provideLicenseResponse(const Vector<uint8_t>& sessionId,
|
||||
const Vector<uint8_t>& response);
|
||||
|
||||
virtual status_t removeLicense(const Vector<uint8_t>& sessionId);
|
||||
|
||||
virtual status_t queryLicenseStatus(
|
||||
const Vector<uint8_t>& sessionId,
|
||||
KeyedVector<String8, String8>& infoMap) const;
|
||||
|
||||
virtual status_t getProvisionRequest(Vector<uint8_t>& request,
|
||||
String8& defaultUrl);
|
||||
|
||||
virtual status_t provideProvisionResponse(const Vector<uint8_t>& response);
|
||||
|
||||
virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops);
|
||||
|
||||
virtual status_t releaseSecureStops(const Vector<uint8_t>& ssRelease);
|
||||
|
||||
virtual status_t getPropertyString(const String8& name, String8& value) const;
|
||||
|
||||
virtual status_t getPropertyByteArray(const String8& name,
|
||||
Vector<uint8_t>& value) const;
|
||||
|
||||
virtual status_t setPropertyString(const String8& name, const String8& value);
|
||||
|
||||
virtual status_t setPropertyByteArray(const String8& name,
|
||||
const Vector<uint8_t>& value);
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(WVDrmPlugin);
|
||||
|
||||
wvcdm::WvContentDecryptionModule* mCDM;
|
||||
};
|
||||
|
||||
} // namespace wvdrm
|
||||
|
||||
#endif // WV_DRM_PLUGIN_H_
|
||||
257
libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp
Normal file
257
libwvdrmengine/mediadrm/src/WVDrmPlugin.cpp
Normal file
@@ -0,0 +1,257 @@
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
//#define LOG_NDEBUG 0
|
||||
#define LOG_TAG "WVCdm"
|
||||
#include <utils/Log.h>
|
||||
|
||||
#include "WVDrmPlugin.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "utils/Errors.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace wvdrm {
|
||||
|
||||
using namespace android;
|
||||
using namespace std;
|
||||
using namespace wvcdm;
|
||||
|
||||
WVDrmPlugin::WVDrmPlugin(WvContentDecryptionModule* cdm) : mCDM(cdm) {}
|
||||
|
||||
status_t WVDrmPlugin::openSession(Vector<uint8_t>& sessionId) {
|
||||
CdmSessionId cdmSessionId;
|
||||
CdmResponseType res = mCDM->OpenSession("com.widevine", &cdmSessionId);
|
||||
|
||||
if (res != wvcdm::NO_ERROR) {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
sessionId.clear();
|
||||
sessionId.appendArray(reinterpret_cast<const uint8_t*>(cdmSessionId.data()),
|
||||
cdmSessionId.size());
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::closeSession(const Vector<uint8_t>& sessionId) {
|
||||
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
|
||||
CdmResponseType res = mCDM->CloseSession(cdmSessionId);
|
||||
|
||||
if (res == wvcdm::NO_ERROR) {
|
||||
return android::OK;
|
||||
} else {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::getLicenseRequest(
|
||||
const Vector<uint8_t>& sessionId,
|
||||
const Vector<uint8_t>& initData,
|
||||
const String8& mimeType,
|
||||
LicenseType licenseType,
|
||||
const KeyedVector<String8, String8>& optionalParameters,
|
||||
Vector<uint8_t>& request,
|
||||
String8& defaultUrl) {
|
||||
CdmLicenseType cdmLicenseType;
|
||||
if (licenseType == kLicenseType_Offline) {
|
||||
cdmLicenseType = kLicenseTypeOffline;
|
||||
} else if (licenseType == kLicenseType_Streaming) {
|
||||
cdmLicenseType = kLicenseTypeStreaming;
|
||||
} else {
|
||||
return BAD_TYPE;
|
||||
}
|
||||
|
||||
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
|
||||
CdmInitData cdmInitData(initData.begin(), initData.end());
|
||||
// TODO: Do something with mimeType?
|
||||
|
||||
CdmNameValueMap cdmParameters;
|
||||
for (size_t i = 0; i < optionalParameters.size(); ++i) {
|
||||
const String8& key = optionalParameters.keyAt(i);
|
||||
const String8& value = optionalParameters.valueAt(i);
|
||||
|
||||
string cdmKey(key.string(), key.size());
|
||||
string cdmValue(value.string(), value.size());
|
||||
|
||||
cdmParameters[cdmKey] = cdmValue;
|
||||
}
|
||||
|
||||
CdmKeyMessage keyRequest;
|
||||
|
||||
CdmResponseType res = mCDM->GenerateKeyRequest(cdmSessionId, cdmInitData,
|
||||
cdmLicenseType,
|
||||
cdmParameters, &keyRequest);
|
||||
|
||||
if (res != wvcdm::KEY_MESSAGE) {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
// TODO: Do something more with defaultUrl?
|
||||
defaultUrl.clear();
|
||||
|
||||
request.clear();
|
||||
request.appendArray(reinterpret_cast<const uint8_t*>(keyRequest.data()),
|
||||
keyRequest.size());
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::provideLicenseResponse(
|
||||
const Vector<uint8_t>& sessionId,
|
||||
const Vector<uint8_t>& response) {
|
||||
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
|
||||
CdmKeyResponse cdmResponse(response.begin(), response.end());
|
||||
|
||||
CdmResponseType res = mCDM->AddKey(cdmSessionId, cdmResponse);
|
||||
|
||||
if (res == wvcdm::KEY_ADDED || res == wvcdm::NO_ERROR) {
|
||||
return android::OK;
|
||||
} else {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::removeLicense(const Vector<uint8_t>& sessionId) {
|
||||
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
|
||||
|
||||
CdmResponseType res = mCDM->CancelKeyRequest(cdmSessionId);
|
||||
|
||||
if (res == wvcdm::NO_ERROR) {
|
||||
return android::OK;
|
||||
} else {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::queryLicenseStatus(
|
||||
const Vector<uint8_t>& sessionId,
|
||||
KeyedVector<String8, String8>& infoMap) const {
|
||||
CdmSessionId cdmSessionId(sessionId.begin(), sessionId.end());
|
||||
CdmNameValueMap cdmLicenseInfo;
|
||||
|
||||
CdmResponseType res = mCDM->QueryKeyStatus(cdmSessionId, &cdmLicenseInfo);
|
||||
|
||||
if (res != wvcdm::NO_ERROR) {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
infoMap.clear();
|
||||
for (CdmNameValueMap::const_iterator iter = cdmLicenseInfo.begin();
|
||||
iter != cdmLicenseInfo.end();
|
||||
++iter) {
|
||||
const string& cdmKey = iter->first;
|
||||
const string& cdmValue = iter->second;
|
||||
|
||||
String8 key(cdmKey.data(), cdmKey.size());
|
||||
String8 value(cdmValue.data(), cdmValue.size());
|
||||
|
||||
infoMap.add(key, value);
|
||||
}
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::getProvisionRequest(Vector<uint8_t>& request,
|
||||
String8& defaultUrl) {
|
||||
CdmProvisioningRequest cdmProvisionRequest;
|
||||
string cdmDefaultUrl;
|
||||
|
||||
CdmResponseType res = mCDM->GetProvisioningRequest(&cdmProvisionRequest,
|
||||
&cdmDefaultUrl);
|
||||
|
||||
if (res != wvcdm::NO_ERROR) {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
request.clear();
|
||||
request.appendArray(reinterpret_cast<const uint8_t*>(
|
||||
cdmProvisionRequest.data()),
|
||||
cdmProvisionRequest.size());
|
||||
|
||||
defaultUrl.clear();
|
||||
defaultUrl.setTo(cdmDefaultUrl.data(), cdmDefaultUrl.size());
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::provideProvisionResponse(
|
||||
const Vector<uint8_t>& response) {
|
||||
CdmProvisioningResponse cdmResponse(response.begin(), response.end());
|
||||
|
||||
CdmResponseType res = mCDM->HandleProvisioningResponse(cdmResponse);
|
||||
|
||||
if (res == wvcdm::NO_ERROR) {
|
||||
return android::OK;
|
||||
} else {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
|
||||
CdmSecureStops cdmSecureStops;
|
||||
|
||||
CdmResponseType res = mCDM->GetSecureStops(&cdmSecureStops);
|
||||
|
||||
if (res != wvcdm::NO_ERROR) {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
secureStops.clear();
|
||||
for (CdmSecureStops::const_iterator iter = cdmSecureStops.begin();
|
||||
iter != cdmSecureStops.end();
|
||||
++iter) {
|
||||
const string& cdmStop = *iter;
|
||||
|
||||
Vector<uint8_t> stop;
|
||||
stop.appendArray(reinterpret_cast<const uint8_t*>(cdmStop.data()),
|
||||
cdmStop.size());
|
||||
|
||||
secureStops.push_back(stop);
|
||||
}
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::releaseSecureStops(const Vector<uint8_t>& ssRelease) {
|
||||
CdmSecureStopReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end());
|
||||
|
||||
CdmResponseType res = mCDM->ReleaseSecureStops(cdmMessage);
|
||||
|
||||
if (res == wvcdm::NO_ERROR) {
|
||||
return android::OK;
|
||||
} else {
|
||||
return android::UNKNOWN_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::getPropertyString(const String8& name,
|
||||
String8& value) const {
|
||||
// TODO: Implement this function once the CDM query API is finalized.
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::getPropertyByteArray(const String8& name,
|
||||
Vector<uint8_t>& value) const {
|
||||
// TODO: Implement this function once the CDM query API is finalized.
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::setPropertyString(const String8& name,
|
||||
const String8& value) {
|
||||
// TODO: Implement this function once the CDM query API is finalized.
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::setPropertyByteArray(const String8& name,
|
||||
const Vector<uint8_t>& value) {
|
||||
// TODO: Implement this function once the CDM query API is finalized.
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
// TODO: Hook up to event listener methods on CDM once Android API for
|
||||
// eventing is finalized.
|
||||
} // namespace wvdrm
|
||||
54
libwvdrmengine/mediadrm/test/Android.mk
Normal file
54
libwvdrmengine/mediadrm/test/Android.mk
Normal file
@@ -0,0 +1,54 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
WVDrmPlugin_test.cpp \
|
||||
|
||||
LOCAL_C_INCLUDES := \
|
||||
bionic \
|
||||
external/gtest/include \
|
||||
external/stlport/stlport \
|
||||
frameworks/av/include \
|
||||
frameworks/native/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/core/include \
|
||||
vendor/widevine/libwvdrmengine/cdm/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/include \
|
||||
vendor/widevine/libwvdrmengine/mediadrm/test \
|
||||
vendor/widevine/libwvdrmengine/test/gmock/include \
|
||||
|
||||
LOCAL_STATIC_LIBRARIES := \
|
||||
libcdm \
|
||||
libgmock \
|
||||
libgmock_main \
|
||||
libgtest \
|
||||
libprotobuf-cpp-2.3.0-lite \
|
||||
libwvdrmdrmplugin \
|
||||
|
||||
LOCAL_SHARED_LIBRARIES := \
|
||||
liblog \
|
||||
liboemcrypto \
|
||||
libstlport \
|
||||
libutils \
|
||||
|
||||
# CDM's protobuffers are not part of the library
|
||||
PROTO_SRC_DIR := $(proto_generated_cc_sources_dir)/$(LOCAL_PATH)/core/src
|
||||
|
||||
LOCAL_SRC_FILES += \
|
||||
$(PROTO_SRC_DIR)/license_protocol.pb.cc \
|
||||
|
||||
LOCAL_C_INCLUDES += \
|
||||
$(proto_generated_cc_sources_dir)/$(LOCAL_PATH)/core/src \
|
||||
external/protobuf/src \
|
||||
|
||||
LOCAL_ADDITIONAL_DEPENDENCIES += $(proto_generated_headers)
|
||||
|
||||
LOCAL_WHOLE_STATIC_LIBRARIES := \
|
||||
license_protocol_protos \
|
||||
|
||||
# End protobuf section
|
||||
|
||||
LOCAL_MODULE := libwvdrmdrmplugin_test
|
||||
|
||||
LOCAL_MODULE_TAGS := tests
|
||||
|
||||
include $(BUILD_EXECUTABLE)
|
||||
53
libwvdrmengine/mediadrm/test/MockCDM.h
Normal file
53
libwvdrmengine/mediadrm/test/MockCDM.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#ifndef WV_DRM_PLUGIN_MOCK_CDM_H_
|
||||
#define WV_DRM_PLUGIN_MOCK_CDM_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gmock/gmock.h"
|
||||
#include "wv_cdm_types.h"
|
||||
#include "wv_content_decryption_module.h"
|
||||
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
public:
|
||||
MOCK_METHOD2(OpenSession, CdmResponseType(const CdmKeySystem&,
|
||||
CdmSessionId*));
|
||||
|
||||
MOCK_METHOD1(CloseSession, CdmResponseType(CdmSessionId&));
|
||||
|
||||
MOCK_METHOD5(GenerateKeyRequest, CdmResponseType(const CdmSessionId&,
|
||||
const CdmInitData&,
|
||||
const CdmLicenseType,
|
||||
CdmNameValueMap&,
|
||||
CdmKeyMessage*));
|
||||
|
||||
MOCK_METHOD2(AddKey, CdmResponseType(const CdmSessionId&,
|
||||
const CdmKeyResponse&));
|
||||
|
||||
MOCK_METHOD1(CancelKeyRequest, CdmResponseType(const CdmSessionId&));
|
||||
|
||||
MOCK_METHOD2(QueryKeyStatus, CdmResponseType(const CdmSessionId&,
|
||||
CdmNameValueMap*));
|
||||
|
||||
MOCK_METHOD2(GetProvisioningRequest, CdmResponseType(CdmProvisioningRequest*,
|
||||
std::string*));
|
||||
|
||||
MOCK_METHOD1(HandleProvisioningResponse,
|
||||
CdmResponseType(CdmProvisioningResponse&));
|
||||
|
||||
MOCK_METHOD1(GetSecureStops, CdmResponseType(CdmSecureStops*));
|
||||
|
||||
MOCK_METHOD1(ReleaseSecureStops,
|
||||
CdmResponseType(const CdmSecureStopReleaseMessage&));
|
||||
};
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
#endif // WV_DRM_PLUGIN_MOCK_CDM_H_
|
||||
372
libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp
Normal file
372
libwvdrmengine/mediadrm/test/WVDrmPlugin_test.cpp
Normal file
@@ -0,0 +1,372 @@
|
||||
//
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
#include "media/stagefright/foundation/AString.h"
|
||||
#include "MockCDM.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "WVDrmPlugin.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace std;
|
||||
using namespace testing;
|
||||
using namespace wvcdm;
|
||||
using namespace wvdrm;
|
||||
|
||||
class WVDrmPluginTest : public Test {
|
||||
protected:
|
||||
static const uint32_t kSessionIdSize = 16;
|
||||
Vector<uint8_t> sessionId;
|
||||
CdmSessionId cdmSessionId;
|
||||
|
||||
virtual void SetUp() {
|
||||
uint8_t sessionIdRaw[kSessionIdSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(sessionIdRaw, sizeof(uint8_t), kSessionIdSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
sessionId.appendArray(sessionIdRaw, kSessionIdSize);
|
||||
cdmSessionId.assign(sessionId.begin(), sessionId.end());
|
||||
|
||||
// Set default CdmResponseType value for gMock
|
||||
DefaultValue<CdmResponseType>::Set(wvcdm::NO_ERROR);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(WVDrmPluginTest, OpensSessions) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
uint8_t sessionIdRaw[kSessionIdSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(sessionIdRaw, sizeof(uint8_t), kSessionIdSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
CdmSessionId cdmSessionId(sessionIdRaw, sessionIdRaw + kSessionIdSize);
|
||||
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
status_t res = plugin.openSession(sessionId);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_THAT(sessionId, ElementsAreArray(sessionIdRaw, kSessionIdSize));
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, ClosesSessions) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
EXPECT_CALL(cdm, CloseSession(cdmSessionId))
|
||||
.Times(1);
|
||||
|
||||
status_t res = plugin.closeSession(sessionId);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, GeneratesKeyRequests) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kInitDataSize = 128;
|
||||
uint8_t initDataRaw[kInitDataSize];
|
||||
static const uint32_t kRequestSize = 256;
|
||||
uint8_t requestRaw[kRequestSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(initDataRaw, sizeof(uint8_t), kInitDataSize, fp);
|
||||
fread(requestRaw, sizeof(uint8_t), kRequestSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
Vector<uint8_t> initData;
|
||||
initData.appendArray(initDataRaw, kInitDataSize);
|
||||
|
||||
CdmKeyMessage cdmRequest(requestRaw, requestRaw + kRequestSize);
|
||||
Vector<uint8_t> request;
|
||||
|
||||
KeyedVector<String8, String8> parameters;
|
||||
CdmNameValueMap cdmParameters;
|
||||
|
||||
parameters.add(String8("paddingScheme"), String8("PKCS7"));
|
||||
cdmParameters["paddingScheme"] = "PKCS7";
|
||||
parameters.add(String8("favoriteParticle"), String8("tetraquark"));
|
||||
cdmParameters["favoriteParticle"] = "tetraquark";
|
||||
parameters.add(String8("answer"), String8("42"));
|
||||
cdmParameters["answer"] = "42";
|
||||
|
||||
String8 defaultUrl;
|
||||
|
||||
{
|
||||
InSequence calls;
|
||||
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId,
|
||||
ElementsAreArray(initDataRaw,
|
||||
kInitDataSize),
|
||||
kLicenseTypeOffline, cdmParameters, _))
|
||||
.WillOnce(DoAll(SetArgPointee<4>(cdmRequest),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, GenerateKeyRequest(cdmSessionId,
|
||||
ElementsAreArray(initDataRaw,
|
||||
kInitDataSize),
|
||||
kLicenseTypeStreaming, cdmParameters,
|
||||
_))
|
||||
.WillOnce(DoAll(SetArgPointee<4>(cdmRequest),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
}
|
||||
|
||||
status_t res = plugin.getLicenseRequest(sessionId, initData,
|
||||
String8("video/h264"),
|
||||
DrmPlugin::kLicenseType_Offline,
|
||||
parameters, request, defaultUrl);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
|
||||
EXPECT_TRUE(defaultUrl.isEmpty());
|
||||
|
||||
res = plugin.getLicenseRequest(sessionId, initData, String8("video/h264"),
|
||||
DrmPlugin::kLicenseType_Streaming, parameters,
|
||||
request, defaultUrl);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
|
||||
EXPECT_TRUE(defaultUrl.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, AddsKeys) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kResponseSize = 256;
|
||||
uint8_t responseRaw[kResponseSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(responseRaw, sizeof(uint8_t), kResponseSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
Vector<uint8_t> response;
|
||||
response.appendArray(responseRaw, kResponseSize);
|
||||
|
||||
EXPECT_CALL(cdm, AddKey(cdmSessionId, ElementsAreArray(responseRaw,
|
||||
kResponseSize)))
|
||||
.Times(1);
|
||||
|
||||
status_t res = plugin.provideLicenseResponse(sessionId, response);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, CancelsKeyRequests) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
EXPECT_CALL(cdm, CancelKeyRequest(cdmSessionId))
|
||||
.Times(1);
|
||||
|
||||
status_t res = plugin.removeLicense(sessionId);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, QueriesKeyStatus) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
KeyedVector<String8, String8> expectedLicenseStatus;
|
||||
CdmNameValueMap cdmLicenseStatus;
|
||||
|
||||
expectedLicenseStatus.add(String8("areTheKeysAllRight"), String8("yes"));
|
||||
cdmLicenseStatus["areTheKeysAllRight"] = "yes";
|
||||
expectedLicenseStatus.add(String8("isGMockAwesome"), String8("ohhhhhhYeah"));
|
||||
cdmLicenseStatus["isGMockAwesome"] = "ohhhhhhYeah";
|
||||
expectedLicenseStatus.add(String8("answer"), String8("42"));
|
||||
cdmLicenseStatus["answer"] = "42";
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyStatus(cdmSessionId, _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(cdmLicenseStatus),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
KeyedVector<String8, String8> licenseStatus;
|
||||
|
||||
status_t res = plugin.queryLicenseStatus(sessionId, licenseStatus);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
|
||||
ASSERT_EQ(expectedLicenseStatus.size(), licenseStatus.size());
|
||||
for (size_t i = 0; i < expectedLicenseStatus.size(); ++i) {
|
||||
const String8& key = expectedLicenseStatus.keyAt(i);
|
||||
EXPECT_NE(android::NAME_NOT_FOUND, licenseStatus.indexOfKey(key));
|
||||
EXPECT_EQ(expectedLicenseStatus.valueFor(key), licenseStatus.valueFor(key));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, GetsProvisioningRequests) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kRequestSize = 256;
|
||||
uint8_t requestRaw[kRequestSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(requestRaw, sizeof(uint8_t), kRequestSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
CdmProvisioningRequest cdmRequest(requestRaw, requestRaw + kRequestSize);
|
||||
|
||||
static const char* kDefaultUrl = "http://google.com/";
|
||||
|
||||
EXPECT_CALL(cdm, GetProvisioningRequest(_, _))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(cdmRequest),
|
||||
SetArgPointee<1>(kDefaultUrl),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
Vector<uint8_t> request;
|
||||
String8 defaultUrl;
|
||||
|
||||
status_t res = plugin.getProvisionRequest(request, defaultUrl);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_THAT(request, ElementsAreArray(requestRaw, kRequestSize));
|
||||
EXPECT_EQ(String8(kDefaultUrl), defaultUrl);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, HandlesProvisioningResponses) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kResponseSize = 512;
|
||||
uint8_t responseRaw[kResponseSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(responseRaw, sizeof(uint8_t), kResponseSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
Vector<uint8_t> response;
|
||||
response.appendArray(responseRaw, kResponseSize);
|
||||
|
||||
EXPECT_CALL(cdm, HandleProvisioningResponse(ElementsAreArray(responseRaw,
|
||||
kResponseSize)))
|
||||
.Times(1);
|
||||
|
||||
status_t res = plugin.provideProvisionResponse(response);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, GetsSecureStops) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kStopSize = 53;
|
||||
static const uint32_t kStopCount = 7;
|
||||
uint8_t stopsRaw[kStopCount][kStopSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
for (uint32_t i = 0; i < kStopCount; ++i) {
|
||||
fread(stopsRaw[i], sizeof(uint8_t), kStopSize, fp);
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
CdmSecureStops cdmStops;
|
||||
for (uint32_t i = 0; i < kStopCount; ++i) {
|
||||
cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize));
|
||||
}
|
||||
|
||||
EXPECT_CALL(cdm, GetSecureStops(_))
|
||||
.WillOnce(DoAll(SetArgPointee<0>(cdmStops),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
List<Vector<uint8_t> > stops;
|
||||
|
||||
status_t res = plugin.getSecureStops(stops);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
|
||||
List<Vector<uint8_t> >::iterator iter = stops.begin();
|
||||
uint32_t rawIter = 0;
|
||||
while (rawIter < kStopCount && iter != stops.end()) {
|
||||
EXPECT_THAT(*iter, ElementsAreArray(stopsRaw[rawIter], kStopSize));
|
||||
|
||||
++iter;
|
||||
++rawIter;
|
||||
}
|
||||
// Assert that both lists are the same length
|
||||
EXPECT_EQ(kStopCount, rawIter);
|
||||
EXPECT_EQ(stops.end(), iter);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, ReleasesSecureStops) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kMessageSize = 128;
|
||||
uint8_t messageRaw[kMessageSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(messageRaw, sizeof(uint8_t), kMessageSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
Vector<uint8_t> message;
|
||||
message.appendArray(messageRaw, kMessageSize);
|
||||
|
||||
EXPECT_CALL(cdm, ReleaseSecureStops(ElementsAreArray(messageRaw,
|
||||
kMessageSize)))
|
||||
.Times(1);
|
||||
|
||||
status_t res = plugin.releaseSecureStops(message);
|
||||
|
||||
ASSERT_EQ(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, DoesNotGetStringProperties) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
String8 result;
|
||||
|
||||
status_t res = plugin.getPropertyString(String8("property"), result);
|
||||
|
||||
ASSERT_NE(OK, res);
|
||||
EXPECT_TRUE(result.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, DoesNotGetByteProperties) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
Vector<uint8_t> result;
|
||||
|
||||
status_t res = plugin.getPropertyByteArray(String8("property"), result);
|
||||
|
||||
ASSERT_NE(OK, res);
|
||||
EXPECT_TRUE(result.isEmpty());
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, DoesNotSetStringProperties) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
status_t res = plugin.setPropertyString(String8("property"),
|
||||
String8("ignored"));
|
||||
|
||||
ASSERT_NE(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, DoesNotSetByteProperties) {
|
||||
MockCDM cdm;
|
||||
WVDrmPlugin plugin(&cdm);
|
||||
|
||||
static const uint32_t kValueSize = 32;
|
||||
uint8_t valueRaw[kValueSize];
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(valueRaw, sizeof(uint8_t), kValueSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
Vector<uint8_t> value;
|
||||
value.appendArray(valueRaw, kValueSize);
|
||||
|
||||
status_t res = plugin.setPropertyByteArray(String8("property"), value);
|
||||
|
||||
ASSERT_NE(OK, res);
|
||||
}
|
||||
Reference in New Issue
Block a user