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:
Jeff Tinker
2013-03-21 17:39:02 -07:00
parent 38334efbe7
commit 1a8aa0dd05
211 changed files with 51913 additions and 144 deletions

View 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)

View 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_

View 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

View 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)

View 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_

View 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);
}