Allow Apps to Voluntarily Downgrade to L3 Crypto
This merges the following changes from the Widevine CDM repository: 564f4cc Add CdmClientPropertySet to CDM Adds an interface to the CDM that allows it to query its client for certain properties. In this case, this includes the ability to specify what security level is desired, as well as support for service ceritifcate privacy mode. 9cfbd3e Force Level 3 fallback Adds support for voluntarily invoking L3 crypto to the OEMCrypto wrapper. 95d12c1 Add pointer to CdmClientPropertySet class to OpenSession. Adds support for storing the property set on a session-by-session basis and choosing the appropriate crypto level. 17de442 Add Settable Properties for Clank to Android Adds support for setting the aforementioned properties to the DrmEngine bbe704d Fixes to force fallback to level three security Corrections to invoke provisioning, OEMCrypto API with configured security level rather than the default. Unit tests were also revised. Note that some parts of this are also support for the ability to use a service certificate-based privacy mode. The remaining code for supporting this mode is still forthcoming. Bug: 10109249 Change-Id: I2755e4dea1de3e8a56cff237360298f7b7f1bddc
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
#include <stdint.h>
|
||||
#include <map>
|
||||
|
||||
#include "cdm_client_property_set.h"
|
||||
#include "media/drm/DrmAPI.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
#include "media/stagefright/foundation/AString.h"
|
||||
@@ -157,6 +158,45 @@ class WVDrmPlugin : public android::DrmPlugin,
|
||||
OEMCrypto_Algorithm mMacAlgorithm;
|
||||
};
|
||||
|
||||
class WVClientPropertySet : public wvcdm::CdmClientPropertySet {
|
||||
public:
|
||||
WVClientPropertySet()
|
||||
: mUsePrivacyMode(false) {}
|
||||
|
||||
virtual ~WVClientPropertySet() {}
|
||||
|
||||
void set_security_level(const std::string& securityLevel) {
|
||||
mSecurityLevel = securityLevel;
|
||||
}
|
||||
|
||||
virtual std::string security_level() const {
|
||||
return mSecurityLevel;
|
||||
}
|
||||
|
||||
void set_use_privacy_mode(bool usePrivacyMode) {
|
||||
mUsePrivacyMode = usePrivacyMode;
|
||||
}
|
||||
|
||||
virtual bool use_privacy_mode() const {
|
||||
return mUsePrivacyMode;
|
||||
}
|
||||
|
||||
void set_service_certificate(const std::vector<uint8_t>& serviceCertificate) {
|
||||
mServiceCertificate = serviceCertificate;
|
||||
}
|
||||
|
||||
virtual std::vector<uint8_t> service_certificate() const {
|
||||
return mServiceCertificate;
|
||||
}
|
||||
|
||||
private:
|
||||
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
|
||||
|
||||
std::string mSecurityLevel;
|
||||
bool mUsePrivacyMode;
|
||||
std::vector<uint8_t> mServiceCertificate;
|
||||
} mPropertySet;
|
||||
|
||||
WvContentDecryptionModule* mCDM;
|
||||
WVGenericCryptoInterface* mCrypto;
|
||||
map<CdmSessionId, CryptoSession> mCryptoSessions;
|
||||
|
||||
@@ -25,6 +25,10 @@ using namespace android;
|
||||
using namespace std;
|
||||
using namespace wvcdm;
|
||||
|
||||
static const char* const kResetSecurityLevel = "";
|
||||
static const char* const kEnable = "enable";
|
||||
static const char* const kDisable = "disable";
|
||||
|
||||
WVDrmPlugin::WVDrmPlugin(WvContentDecryptionModule* cdm,
|
||||
WVGenericCryptoInterface* crypto)
|
||||
: mCDM(cdm), mCrypto(crypto) {}
|
||||
@@ -51,10 +55,11 @@ WVDrmPlugin::~WVDrmPlugin() {
|
||||
|
||||
status_t WVDrmPlugin::openSession(Vector<uint8_t>& sessionId) {
|
||||
CdmSessionId cdmSessionId;
|
||||
CdmResponseType res = mCDM->OpenSession("com.widevine", &cdmSessionId);
|
||||
CdmResponseType res = mCDM->OpenSession("com.widevine", &mPropertySet,
|
||||
&cdmSessionId);
|
||||
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
return mapAndNotifyOfCdmResponseType(sessionId, res);
|
||||
return mapCdmResponseType(res);
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
@@ -347,16 +352,22 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
|
||||
} else if (name == "algorithms") {
|
||||
value = "AES/CBC/NoPadding,HmacSHA256";
|
||||
} else if (name == "securityLevel") {
|
||||
CdmQueryMap status;
|
||||
CdmResponseType res = mCDM->QueryStatus(&status);
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
ALOGE("Error querying CDM status: %u", res);
|
||||
return mapCdmResponseType(res);
|
||||
} else if (!status.count(QUERY_KEY_SECURITY_LEVEL)) {
|
||||
ALOGE("CDM did not report a security level");
|
||||
return kErrorCDMGeneric;
|
||||
string requestedLevel = mPropertySet.security_level();
|
||||
|
||||
if (requestedLevel.length() > 0) {
|
||||
value = requestedLevel.c_str();
|
||||
} else {
|
||||
CdmQueryMap status;
|
||||
CdmResponseType res = mCDM->QueryStatus(&status);
|
||||
if (!isCdmResponseTypeSuccess(res)) {
|
||||
ALOGE("Error querying CDM status: %u", res);
|
||||
return mapCdmResponseType(res);
|
||||
} else if (!status.count(QUERY_KEY_SECURITY_LEVEL)) {
|
||||
ALOGE("CDM did not report a security level");
|
||||
return kErrorCDMGeneric;
|
||||
}
|
||||
value = status[QUERY_KEY_SECURITY_LEVEL].c_str();
|
||||
}
|
||||
value = status[QUERY_KEY_SECURITY_LEVEL].c_str();
|
||||
} else if (name == "systemId") {
|
||||
CdmQueryMap status;
|
||||
CdmResponseType res = mCDM->QueryStatus(&status);
|
||||
@@ -368,8 +379,14 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
|
||||
return kErrorCDMGeneric;
|
||||
}
|
||||
value = status[QUERY_KEY_SYSTEM_ID].c_str();
|
||||
} else if (name == "privacyMode") {
|
||||
if (mPropertySet.use_privacy_mode()) {
|
||||
value = kEnable;
|
||||
} else {
|
||||
value = kDisable;
|
||||
}
|
||||
} else {
|
||||
ALOGE("App requested unknown property %s", name.string());
|
||||
ALOGE("App requested unknown string property %s", name.string());
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
@@ -414,8 +431,12 @@ status_t WVDrmPlugin::getPropertyByteArray(const String8& name,
|
||||
value.clear();
|
||||
value.appendArray(reinterpret_cast<const uint8_t*>(uniqueId.data()),
|
||||
uniqueId.size());
|
||||
} else if (name == "serviceCertificate") {
|
||||
vector<uint8_t> cert = mPropertySet.service_certificate();
|
||||
value.clear();
|
||||
value.appendArray(&cert[0], cert.size());
|
||||
} else {
|
||||
ALOGE("App requested unknown property %s", name.string());
|
||||
ALOGE("App requested unknown byte array property %s", name.string());
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
@@ -424,12 +445,48 @@ status_t WVDrmPlugin::getPropertyByteArray(const String8& name,
|
||||
|
||||
status_t WVDrmPlugin::setPropertyString(const String8& name,
|
||||
const String8& value) {
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
if (name == "securityLevel") {
|
||||
if (mCryptoSessions.size() == 0) {
|
||||
if (value == QUERY_VALUE_SECURITY_LEVEL_L3.c_str()) {
|
||||
mPropertySet.set_security_level(QUERY_VALUE_SECURITY_LEVEL_L3);
|
||||
} else if (value == kResetSecurityLevel) {
|
||||
mPropertySet.set_security_level("");
|
||||
} else {
|
||||
ALOGE("App requested invalid security level %s", value.string());
|
||||
return android::BAD_VALUE;
|
||||
}
|
||||
} else {
|
||||
ALOGE("App tried to change security level while sessions are open.");
|
||||
return kErrorSessionIsOpen;
|
||||
}
|
||||
} else if (name == "privacyMode") {
|
||||
if (value == kEnable) {
|
||||
mPropertySet.set_use_privacy_mode(true);
|
||||
} else if (value == kDisable) {
|
||||
mPropertySet.set_use_privacy_mode(false);
|
||||
} else {
|
||||
ALOGE("App requested unknown privacy mode %s", value.string());
|
||||
return android::BAD_VALUE;
|
||||
}
|
||||
} else {
|
||||
ALOGE("App set unknown string property %s", name.string());
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::setPropertyByteArray(const String8& name,
|
||||
const Vector<uint8_t>& value) {
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
if (name == "serviceCertificate") {
|
||||
vector<uint8_t> cert(value.begin(), value.end());
|
||||
mPropertySet.set_service_certificate(cert);
|
||||
} else {
|
||||
ALOGE("App set unknown byte array property %s", name.string());
|
||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||
}
|
||||
|
||||
return android::OK;
|
||||
}
|
||||
|
||||
status_t WVDrmPlugin::setCipherAlgorithm(const Vector<uint8_t>& sessionId,
|
||||
|
||||
@@ -23,7 +23,6 @@ LOCAL_STATIC_LIBRARIES := \
|
||||
libgmock \
|
||||
libgmock_main \
|
||||
libgtest \
|
||||
libwvwrapper \
|
||||
libwvlevel3 \
|
||||
libprotobuf-cpp-2.3.0-lite \
|
||||
libwvdrmdrmplugin \
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
|
||||
#include "cdm_client_property_set.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "media/stagefright/foundation/ABase.h"
|
||||
@@ -23,7 +24,8 @@ using namespace wvdrm;
|
||||
|
||||
class MockCDM : public WvContentDecryptionModule {
|
||||
public:
|
||||
MOCK_METHOD2(OpenSession, CdmResponseType(const CdmKeySystem&,
|
||||
MOCK_METHOD3(OpenSession, CdmResponseType(const CdmKeySystem&,
|
||||
const CdmClientPropertySet*,
|
||||
CdmSessionId*));
|
||||
|
||||
MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&));
|
||||
@@ -133,8 +135,8 @@ TEST_F(WVDrmPluginTest, OpensSessions) {
|
||||
StrictMock<MockCrypto> crypto;
|
||||
WVDrmPlugin plugin(&cdm, &crypto);
|
||||
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
// Provide expected behavior when plugin requests session control info
|
||||
@@ -633,9 +635,9 @@ TEST_F(WVDrmPluginTest, FailsGenericMethodsWithoutAnAlgorithmSet) {
|
||||
bool match;
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -719,9 +721,9 @@ TEST_F(WVDrmPluginTest, CallsGenericEncrypt) {
|
||||
}
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -786,9 +788,9 @@ TEST_F(WVDrmPluginTest, CallsGenericDecrypt) {
|
||||
}
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -855,9 +857,9 @@ TEST_F(WVDrmPluginTest, CallsGenericSign) {
|
||||
}
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -934,9 +936,9 @@ TEST_F(WVDrmPluginTest, CallsGenericVerify) {
|
||||
}
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -977,9 +979,9 @@ TEST_F(WVDrmPluginTest, RegistersForEvents) {
|
||||
.Times(1);
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -1014,10 +1016,10 @@ TEST_F(WVDrmPluginTest, UnregistersForAllEventsOnDestruction) {
|
||||
CdmSessionId cdmSessionId1(sessionIdRaw1, sessionIdRaw1 + kSessionIdSize);
|
||||
CdmSessionId cdmSessionId2(sessionIdRaw2, sessionIdRaw2 + kSessionIdSize);
|
||||
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(cdmSessionId1),
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.WillOnce(DoAll(SetArgPointee<2>(cdmSessionId1),
|
||||
Return(wvcdm::NO_ERROR)))
|
||||
.WillOnce(DoAll(SetArgPointee<1>(cdmSessionId2),
|
||||
.WillOnce(DoAll(SetArgPointee<2>(cdmSessionId2),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId1, _))
|
||||
@@ -1071,9 +1073,9 @@ TEST_F(WVDrmPluginTest, MarshalsEvents) {
|
||||
}
|
||||
|
||||
// Provide expected behavior to support session creation
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _))
|
||||
EXPECT_CALL(cdm, OpenSession(StrEq("com.widevine"), _, _))
|
||||
.Times(AtLeast(1))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<1>(cdmSessionId),
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
@@ -1099,3 +1101,217 @@ TEST_F(WVDrmPluginTest, MarshalsEvents) {
|
||||
plugin.onEvent(cdmSessionId, LICENSE_EXPIRED_EVENT);
|
||||
plugin.onEvent(cdmSessionId, LICENSE_RENEWAL_NEEDED_EVENT);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
|
||||
StrictMock<MockCDM> cdm;
|
||||
StrictMock<MockCrypto> crypto;
|
||||
WVDrmPlugin plugin(&cdm, &crypto);
|
||||
|
||||
const CdmClientPropertySet* propertySet = NULL;
|
||||
|
||||
// Provide expected mock behavior
|
||||
{
|
||||
// Provide expected behavior in response to OpenSession and store the
|
||||
// property set
|
||||
EXPECT_CALL(cdm, OpenSession(_, _, _))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
SaveArg<1>(&propertySet),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
// Provide expected behavior when plugin requests session control info
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
|
||||
|
||||
// Let gMock know these calls will happen but we aren't interested in them.
|
||||
EXPECT_CALL(cdm, AttachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, DetachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, CloseSession(_))
|
||||
.Times(AtLeast(0));
|
||||
}
|
||||
|
||||
plugin.openSession(sessionId);
|
||||
|
||||
ASSERT_THAT(propertySet, NotNull());
|
||||
EXPECT_STREQ("", propertySet->security_level().c_str());
|
||||
EXPECT_FALSE(propertySet->use_privacy_mode());
|
||||
EXPECT_EQ(0u, propertySet->service_certificate().size());
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, CanSetSecurityLevel) {
|
||||
StrictMock<MockCDM> cdm;
|
||||
StrictMock<MockCrypto> crypto;
|
||||
WVDrmPlugin plugin(&cdm, &crypto);
|
||||
|
||||
const CdmClientPropertySet* propertySet = NULL;
|
||||
|
||||
// Provide expected mock behavior
|
||||
{
|
||||
// Provide expected behavior in response to OpenSession and store the
|
||||
// property set
|
||||
EXPECT_CALL(cdm, OpenSession(_, _, _))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
SaveArg<1>(&propertySet),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
// Provide expected behavior when plugin requests session control info
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
|
||||
|
||||
// Let gMock know these calls will happen but we aren't interested in them.
|
||||
EXPECT_CALL(cdm, AttachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, DetachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, CloseSession(_))
|
||||
.Times(AtLeast(0));
|
||||
}
|
||||
|
||||
status_t res;
|
||||
|
||||
// Test forcing L3
|
||||
res = plugin.setPropertyString(String8("securityLevel"), String8("L3"));
|
||||
ASSERT_EQ(OK, res);
|
||||
|
||||
plugin.openSession(sessionId);
|
||||
ASSERT_THAT(propertySet, NotNull());
|
||||
EXPECT_STREQ("L3", propertySet->security_level().c_str());
|
||||
plugin.closeSession(sessionId);
|
||||
|
||||
// Test forcing L1 (Should Fail)
|
||||
res = plugin.setPropertyString(String8("securityLevel"), String8("L1"));
|
||||
ASSERT_NE(OK, res);
|
||||
|
||||
// Test un-forcing a level
|
||||
res = plugin.setPropertyString(String8("securityLevel"), String8(""));
|
||||
ASSERT_EQ(OK, res);
|
||||
|
||||
plugin.openSession(sessionId);
|
||||
ASSERT_THAT(propertySet, NotNull());
|
||||
EXPECT_STREQ("", propertySet->security_level().c_str());
|
||||
plugin.closeSession(sessionId);
|
||||
|
||||
// Test nonsense (Should Fail)
|
||||
res = plugin.setPropertyString(String8("securityLevel"), String8("nonsense"));
|
||||
ASSERT_NE(OK, res);
|
||||
|
||||
// Test attempting to force a level with a session open (Should Fail)
|
||||
plugin.openSession(sessionId);
|
||||
res = plugin.setPropertyString(String8("securityLevel"), String8("L3"));
|
||||
ASSERT_NE(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, CanSetPrivacyMode) {
|
||||
StrictMock<MockCDM> cdm;
|
||||
StrictMock<MockCrypto> crypto;
|
||||
WVDrmPlugin plugin(&cdm, &crypto);
|
||||
|
||||
const CdmClientPropertySet* propertySet = NULL;
|
||||
|
||||
// Provide expected mock behavior
|
||||
{
|
||||
// Provide expected behavior in response to OpenSession and store the
|
||||
// property set
|
||||
EXPECT_CALL(cdm, OpenSession(_, _, _))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
SaveArg<1>(&propertySet),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
// Provide expected behavior when plugin requests session control info
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
|
||||
|
||||
// Let gMock know these calls will happen but we aren't interested in them.
|
||||
EXPECT_CALL(cdm, AttachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, DetachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, CloseSession(_))
|
||||
.Times(AtLeast(0));
|
||||
}
|
||||
|
||||
plugin.openSession(sessionId);
|
||||
ASSERT_THAT(propertySet, NotNull());
|
||||
|
||||
status_t res;
|
||||
|
||||
// Test turning on privacy mode
|
||||
res = plugin.setPropertyString(String8("privacyMode"), String8("enable"));
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_TRUE(propertySet->use_privacy_mode());
|
||||
|
||||
// Test turning off privacy mode
|
||||
res = plugin.setPropertyString(String8("privacyMode"), String8("disable"));
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_FALSE(propertySet->use_privacy_mode());
|
||||
|
||||
// Test nonsense (Should Fail)
|
||||
res = plugin.setPropertyString(String8("privacyMode"), String8("nonsense"));
|
||||
ASSERT_NE(OK, res);
|
||||
}
|
||||
|
||||
TEST_F(WVDrmPluginTest, CanSetServiceCertificate) {
|
||||
StrictMock<MockCDM> cdm;
|
||||
StrictMock<MockCrypto> crypto;
|
||||
WVDrmPlugin plugin(&cdm, &crypto);
|
||||
|
||||
const CdmClientPropertySet* propertySet = NULL;
|
||||
|
||||
static const size_t kPrivacyCertSize = 256;
|
||||
uint8_t privacyCertRaw[kPrivacyCertSize];
|
||||
|
||||
FILE* fp = fopen("/dev/urandom", "r");
|
||||
fread(privacyCertRaw, sizeof(uint8_t), kPrivacyCertSize, fp);
|
||||
fclose(fp);
|
||||
|
||||
Vector<uint8_t> privacyCert;
|
||||
privacyCert.appendArray(privacyCertRaw, kPrivacyCertSize);
|
||||
Vector<uint8_t> emptyVector;
|
||||
|
||||
// Provide expected mock behavior
|
||||
{
|
||||
// Provide expected behavior in response to OpenSession and store the
|
||||
// property set
|
||||
EXPECT_CALL(cdm, OpenSession(_, _, _))
|
||||
.WillRepeatedly(DoAll(SetArgPointee<2>(cdmSessionId),
|
||||
SaveArg<1>(&propertySet),
|
||||
Return(wvcdm::NO_ERROR)));
|
||||
|
||||
// Provide expected behavior when plugin requests session control info
|
||||
EXPECT_CALL(cdm, QueryKeyControlInfo(cdmSessionId, _))
|
||||
.WillRepeatedly(Invoke(setSessionIdOnMap<4>));
|
||||
|
||||
// Let gMock know these calls will happen but we aren't interested in them.
|
||||
EXPECT_CALL(cdm, AttachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, DetachEventListener(_, _))
|
||||
.Times(AtLeast(0));
|
||||
|
||||
EXPECT_CALL(cdm, CloseSession(_))
|
||||
.Times(AtLeast(0));
|
||||
}
|
||||
|
||||
plugin.openSession(sessionId);
|
||||
ASSERT_THAT(propertySet, NotNull());
|
||||
|
||||
status_t res;
|
||||
|
||||
// Test setting a certificate
|
||||
res = plugin.setPropertyByteArray(String8("serviceCertificate"), privacyCert);
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_THAT(propertySet->service_certificate(),
|
||||
ElementsAreArray(privacyCertRaw, kPrivacyCertSize));
|
||||
|
||||
// Test clearing a certificate
|
||||
res = plugin.setPropertyByteArray(String8("serviceCertificate"), emptyVector);
|
||||
ASSERT_EQ(OK, res);
|
||||
EXPECT_EQ(0u, propertySet->service_certificate().size());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user