Merge "Allows sharing of keys between sessions" into klp-dev
This commit is contained in:
@@ -16,6 +16,9 @@ class CdmClientPropertySet {
|
|||||||
virtual std::string security_level() const = 0;
|
virtual std::string security_level() const = 0;
|
||||||
virtual bool use_privacy_mode() const = 0;
|
virtual bool use_privacy_mode() const = 0;
|
||||||
virtual std::vector<uint8_t> service_certificate() const = 0;
|
virtual std::vector<uint8_t> service_certificate() const = 0;
|
||||||
|
virtual bool is_session_sharing_enabled() const = 0;
|
||||||
|
virtual uint32_t session_sharing_id() const = 0;
|
||||||
|
virtual void set_session_sharing_id(uint32_t id) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -93,6 +93,7 @@ class CdmEngine : public TimerHandler {
|
|||||||
|
|
||||||
// Is the key known to any session?
|
// Is the key known to any session?
|
||||||
virtual bool IsKeyValid(const KeyId& key_id);
|
virtual bool IsKeyValid(const KeyId& key_id);
|
||||||
|
virtual bool FindSessionForKey(const KeyId& key_id, CdmSessionId* sessionId);
|
||||||
|
|
||||||
// Event listener related methods
|
// Event listener related methods
|
||||||
virtual bool AttachEventListener(const CdmSessionId& session_id,
|
virtual bool AttachEventListener(const CdmSessionId& session_id,
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#ifndef CDM_BASE_LICENSE_H_
|
#ifndef CDM_BASE_LICENSE_H_
|
||||||
#define CDM_BASE_LICENSE_H_
|
#define CDM_BASE_LICENSE_H_
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
#include "wv_cdm_types.h"
|
#include "wv_cdm_types.h"
|
||||||
|
|
||||||
namespace video_widevine_server {
|
namespace video_widevine_server {
|
||||||
@@ -41,6 +43,7 @@ class CdmLicense {
|
|||||||
CdmKeyResponse& license_response,
|
CdmKeyResponse& license_response,
|
||||||
CdmKeyResponse& license_renewal_response);
|
CdmKeyResponse& license_renewal_response);
|
||||||
bool HasInitData() { return !init_data_.empty(); }
|
bool HasInitData() { return !init_data_.empty(); }
|
||||||
|
bool IsKeyLoaded(const KeyId& key_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
|
bool PrepareServiceCertificateRequest(CdmKeyMessage* signed_request,
|
||||||
@@ -58,6 +61,7 @@ class CdmLicense {
|
|||||||
std::string service_certificate_;
|
std::string service_certificate_;
|
||||||
std::string init_data_;
|
std::string init_data_;
|
||||||
bool initialized_;
|
bool initialized_;
|
||||||
|
std::set<KeyId> loaded_keys_;
|
||||||
|
|
||||||
// Used for certificate based licensing
|
// Used for certificate based licensing
|
||||||
CdmKeyMessage key_request_;
|
CdmKeyMessage key_request_;
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ class Properties {
|
|||||||
static const std::vector<uint8_t> GetServiceCertificate(
|
static const std::vector<uint8_t> GetServiceCertificate(
|
||||||
const CdmSessionId& session_id);
|
const CdmSessionId& session_id);
|
||||||
static bool UsePrivacyMode(const CdmSessionId& session_id);
|
static bool UsePrivacyMode(const CdmSessionId& session_id);
|
||||||
|
static uint32_t GetSessionSharingId(const CdmSessionId& session_id);
|
||||||
|
|
||||||
static bool AddSessionPropertySet(
|
static bool AddSessionPropertySet(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
|
|||||||
@@ -525,6 +525,29 @@ bool CdmEngine::IsKeyValid(const KeyId& key_id) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CdmEngine::FindSessionForKey(
|
||||||
|
const KeyId& key_id,
|
||||||
|
CdmSessionId* session_id) {
|
||||||
|
if (NULL == session_id) {
|
||||||
|
LOGE("CdmEngine::FindSessionForKey: session id not provided");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t session_sharing_id = Properties::GetSessionSharingId(*session_id);
|
||||||
|
|
||||||
|
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||||
|
iter != sessions_.end(); ++iter) {
|
||||||
|
CdmSessionId id = iter->second->session_id();
|
||||||
|
if (Properties::GetSessionSharingId(id) == session_sharing_id) {
|
||||||
|
if (iter->second->IsKeyValid(key_id)) {
|
||||||
|
*session_id = id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool CdmEngine::AttachEventListener(
|
bool CdmEngine::AttachEventListener(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
WvCdmEventListener* listener) {
|
WvCdmEventListener* listener) {
|
||||||
|
|||||||
@@ -324,22 +324,7 @@ CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool CdmSession::IsKeyValid(const KeyId& key_id) {
|
bool CdmSession::IsKeyValid(const KeyId& key_id) {
|
||||||
if (crypto_session_.get() == NULL || !crypto_session_->IsOpen())
|
return license_parser_.IsKeyLoaded(key_id);
|
||||||
return false;
|
|
||||||
|
|
||||||
if (key_id_ != key_id) {
|
|
||||||
// OEMCrypto does not provide a way to query the existence/validity of a
|
|
||||||
// key. SelectKey can be used to check whether a key is valid, but there
|
|
||||||
// is also a side effect - the key is selected for decryption, which might
|
|
||||||
// be undesirable and it posts restriction on the use of IsKeyValid API.
|
|
||||||
// TODO(kqyang, gmorgan): consider adding a function in OEMCrypto to check
|
|
||||||
// if a key is valid.
|
|
||||||
if (!crypto_session_->SelectKey(key_id)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
key_id_ = key_id;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmSessionId CdmSession::GenerateSessionId() {
|
CdmSessionId CdmSession::GenerateSessionId() {
|
||||||
|
|||||||
@@ -539,9 +539,22 @@ CdmResponseType CdmLicense::HandleKeyResponse(
|
|||||||
// merge from Eureka)
|
// merge from Eureka)
|
||||||
policy_engine_->SetLicense(license);
|
policy_engine_->SetLicense(license);
|
||||||
|
|
||||||
return session_->LoadKeys(signed_response.msg(), signed_response.signature(),
|
CdmResponseType resp = session_->LoadKeys(signed_response.msg(),
|
||||||
mac_key_iv, mac_key, key_array.size(),
|
signed_response.signature(),
|
||||||
&key_array[0]);
|
mac_key_iv,
|
||||||
|
mac_key,
|
||||||
|
key_array.size(),
|
||||||
|
&key_array[0]);
|
||||||
|
|
||||||
|
if (KEY_ADDED == resp) {
|
||||||
|
loaded_keys_.clear();
|
||||||
|
for (std::vector<CryptoKey>::iterator it = key_array.begin();
|
||||||
|
it != key_array.end();
|
||||||
|
++it) {
|
||||||
|
loaded_keys_.insert(it->key_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
CdmResponseType CdmLicense::HandleKeyUpdateResponse(
|
||||||
@@ -753,4 +766,8 @@ CdmResponseType CdmLicense::HandleKeyErrorResponse(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
|
||||||
|
return loaded_keys_.find(key_id) != loaded_keys_.end();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -100,6 +100,17 @@ bool Properties::UsePrivacyMode(const CdmSessionId& session_id) {
|
|||||||
return property_set->use_privacy_mode();
|
return property_set->use_privacy_mode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t Properties::GetSessionSharingId(const CdmSessionId& session_id) {
|
||||||
|
const CdmClientPropertySet* property_set =
|
||||||
|
GetCdmClientPropertySet(session_id);
|
||||||
|
if (NULL == property_set) {
|
||||||
|
LOGE("Properties::GetSessionSharingId: cannot find property set for %s",
|
||||||
|
session_id.c_str());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return property_set->session_sharing_id();
|
||||||
|
}
|
||||||
|
|
||||||
bool Properties::GetSecurityLevelDirectories(std::vector<std::string>* dirs) {
|
bool Properties::GetSecurityLevelDirectories(std::vector<std::string>* dirs) {
|
||||||
dirs->resize(sizeof(kSecurityLevelDirs)/sizeof(const char*));
|
dirs->resize(sizeof(kSecurityLevelDirs)/sizeof(const char*));
|
||||||
for (size_t i = 0; i < dirs->size(); ++i) {
|
for (size_t i = 0; i < dirs->size(); ++i) {
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class WvContentDecryptionModule {
|
|||||||
// Session related methods
|
// Session related methods
|
||||||
virtual CdmResponseType OpenSession(
|
virtual CdmResponseType OpenSession(
|
||||||
const CdmKeySystem& key_system,
|
const CdmKeySystem& key_system,
|
||||||
const CdmClientPropertySet* property_set,
|
CdmClientPropertySet* property_set,
|
||||||
CdmSessionId* session_id);
|
CdmSessionId* session_id);
|
||||||
virtual CdmResponseType CloseSession(const CdmSessionId& session_id);
|
virtual CdmResponseType CloseSession(const CdmSessionId& session_id);
|
||||||
|
|
||||||
@@ -84,6 +84,7 @@ class WvContentDecryptionModule {
|
|||||||
WvCdmEventListener* listener);
|
WvCdmEventListener* listener);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint32_t GenerateSessionSharingId();
|
||||||
|
|
||||||
// instance variables
|
// instance variables
|
||||||
UniquePtr<CdmEngine> cdm_engine_;
|
UniquePtr<CdmEngine> cdm_engine_;
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#include "cdm_client_property_set.h"
|
||||||
#include "cdm_engine.h"
|
#include "cdm_engine.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "properties.h"
|
||||||
#include "wv_cdm_constants.h"
|
#include "wv_cdm_constants.h"
|
||||||
#include "wv_cdm_event_listener.h"
|
#include "wv_cdm_event_listener.h"
|
||||||
|
|
||||||
@@ -18,8 +20,13 @@ WvContentDecryptionModule::~WvContentDecryptionModule() {}
|
|||||||
|
|
||||||
CdmResponseType WvContentDecryptionModule::OpenSession(
|
CdmResponseType WvContentDecryptionModule::OpenSession(
|
||||||
const CdmKeySystem& key_system,
|
const CdmKeySystem& key_system,
|
||||||
const CdmClientPropertySet* property_set,
|
CdmClientPropertySet* property_set,
|
||||||
CdmSessionId* session_id) {
|
CdmSessionId* session_id) {
|
||||||
|
if (property_set && property_set->is_session_sharing_enabled()) {
|
||||||
|
if (property_set->session_sharing_id() == 0)
|
||||||
|
property_set->set_session_sharing_id(GenerateSessionSharingId());
|
||||||
|
}
|
||||||
|
|
||||||
return cdm_engine_->OpenSession(key_system, property_set, session_id);
|
return cdm_engine_->OpenSession(key_system, property_set, session_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +118,15 @@ CdmResponseType WvContentDecryptionModule::ReleaseSecureStops(
|
|||||||
CdmResponseType WvContentDecryptionModule::Decrypt(
|
CdmResponseType WvContentDecryptionModule::Decrypt(
|
||||||
const CdmSessionId& session_id,
|
const CdmSessionId& session_id,
|
||||||
const CdmDecryptionParameters& parameters) {
|
const CdmDecryptionParameters& parameters) {
|
||||||
return cdm_engine_->Decrypt(session_id, parameters);
|
CdmSessionId id = session_id;
|
||||||
|
if (Properties::GetSessionSharingId(session_id) != 0) {
|
||||||
|
bool status = cdm_engine_->FindSessionForKey(*parameters.key_id, &id);
|
||||||
|
if (!status) {
|
||||||
|
LOGE("WvContentDecryptionModule::Decrypt: unable to find session");
|
||||||
|
return KEY_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return cdm_engine_->Decrypt(id, parameters);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WvContentDecryptionModule::AttachEventListener(
|
bool WvContentDecryptionModule::AttachEventListener(
|
||||||
@@ -124,4 +139,9 @@ bool WvContentDecryptionModule::DetachEventListener(
|
|||||||
return cdm_engine_->DetachEventListener(session_id, listener);
|
return cdm_engine_->DetachEventListener(session_id, listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {
|
||||||
|
static int next_session_sharing_id = 0;
|
||||||
|
return ++next_session_sharing_id;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wvcdm
|
} // namespace wvcdm
|
||||||
|
|||||||
@@ -205,7 +205,10 @@ SubSampleInfo partial_offset_single_encrypted_sub_sample = {
|
|||||||
namespace wvcdm {
|
namespace wvcdm {
|
||||||
class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
||||||
public:
|
public:
|
||||||
TestWvCdmClientPropertySet() : use_privacy_mode_(false) {}
|
TestWvCdmClientPropertySet()
|
||||||
|
: use_privacy_mode_(false),
|
||||||
|
is_session_sharing_enabled_(false),
|
||||||
|
session_sharing_id_(0) {}
|
||||||
virtual ~TestWvCdmClientPropertySet() {}
|
virtual ~TestWvCdmClientPropertySet() {}
|
||||||
|
|
||||||
virtual std::string security_level() const { return security_level_; }
|
virtual std::string security_level() const { return security_level_; }
|
||||||
@@ -213,6 +216,10 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
|||||||
return service_certificate_;
|
return service_certificate_;
|
||||||
}
|
}
|
||||||
virtual bool use_privacy_mode() const { return use_privacy_mode_; }
|
virtual bool use_privacy_mode() const { return use_privacy_mode_; }
|
||||||
|
bool is_session_sharing_enabled() const {
|
||||||
|
return is_session_sharing_enabled_;
|
||||||
|
}
|
||||||
|
uint32_t session_sharing_id() const { return session_sharing_id_; }
|
||||||
|
|
||||||
void set_security_level(const std::string& security_level) {
|
void set_security_level(const std::string& security_level) {
|
||||||
if (!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
if (!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
|
||||||
@@ -227,11 +234,17 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
|
|||||||
void set_use_privacy_mode(bool use_privacy_mode) {
|
void set_use_privacy_mode(bool use_privacy_mode) {
|
||||||
use_privacy_mode_ = use_privacy_mode;
|
use_privacy_mode_ = use_privacy_mode;
|
||||||
}
|
}
|
||||||
|
void set_session_sharing_mode(bool enable) {
|
||||||
|
is_session_sharing_enabled_ = enable;
|
||||||
|
}
|
||||||
|
void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string security_level_;
|
std::string security_level_;
|
||||||
std::vector<uint8_t> service_certificate_;
|
std::vector<uint8_t> service_certificate_;
|
||||||
bool use_privacy_mode_;
|
bool use_privacy_mode_;
|
||||||
|
bool is_session_sharing_enabled_;
|
||||||
|
uint32_t session_sharing_id_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestWvCdmEventListener : public WvCdmEventListener {
|
class TestWvCdmEventListener : public WvCdmEventListener {
|
||||||
@@ -377,6 +390,10 @@ class WvCdmDecryptionTest
|
|||||||
: public WvCdmRequestLicenseTest,
|
: public WvCdmRequestLicenseTest,
|
||||||
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
public ::testing::WithParamInterface<SubSampleInfo*> {};
|
||||||
|
|
||||||
|
class WvCdmSessionSharingTest
|
||||||
|
: public WvCdmRequestLicenseTest,
|
||||||
|
public ::testing::WithParamInterface<bool> {};
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
TEST_F(WvCdmRequestLicenseTest, ProvisioningTest) {
|
||||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||||
std::string provisioning_server_url;
|
std::string provisioning_server_url;
|
||||||
@@ -523,6 +540,54 @@ TEST_F(WvCdmRequestLicenseTest, DISABLED_PrivacyModeWithServiceCertificateTest)
|
|||||||
decryptor_.CloseSession(session_id_);
|
decryptor_.CloseSession(session_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(WvCdmSessionSharingTest, SessionSharingTest) {
|
||||||
|
bool enable_session_sharing = GetParam();
|
||||||
|
|
||||||
|
TestWvCdmClientPropertySet property_set;
|
||||||
|
property_set.set_session_sharing_mode(enable_session_sharing);
|
||||||
|
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||||
|
CdmSessionId gp_session_id_1 = session_id_;
|
||||||
|
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||||
|
VerifyKeyRequestResponse(g_license_server, g_client_auth, g_key_id, false);
|
||||||
|
|
||||||
|
// TODO(rfrias): Move content information to ConfigTestEnv
|
||||||
|
std::string gp_client_auth2 =
|
||||||
|
"?source=YOUTUBE&video_id=z3S_NhwueaM&oauth=ya.gtsqawidevine";
|
||||||
|
std::string gp_key_id2 =
|
||||||
|
wvcdm::a2bs_hex(
|
||||||
|
"000000347073736800000000" // blob size and pssh
|
||||||
|
"edef8ba979d64acea3c827dcd51d21ed00000014" // Widevine system id
|
||||||
|
"08011210bdf1cb4fffc6506b8b7945b0bd2917fb"); // pssh data
|
||||||
|
|
||||||
|
decryptor_.OpenSession(g_key_system, &property_set, &session_id_);
|
||||||
|
CdmSessionId gp_session_id_2 = session_id_;
|
||||||
|
GenerateKeyRequest(g_key_system, gp_key_id2, kLicenseTypeStreaming);
|
||||||
|
VerifyKeyRequestResponse(g_license_server, gp_client_auth2, gp_key_id2, false);
|
||||||
|
|
||||||
|
SubSampleInfo* data = &single_encrypted_sub_sample;
|
||||||
|
std::vector<uint8_t> decrypt_buffer(data->encrypt_data.size());
|
||||||
|
CdmDecryptionParameters decryption_parameters(&data->key_id,
|
||||||
|
&data->encrypt_data.front(),
|
||||||
|
data->encrypt_data.size(),
|
||||||
|
&data->iv,
|
||||||
|
data->block_offset,
|
||||||
|
&decrypt_buffer[0]);
|
||||||
|
decryption_parameters.is_encrypted = data->is_encrypted;
|
||||||
|
decryption_parameters.is_secure = data->is_secure;
|
||||||
|
EXPECT_EQ(
|
||||||
|
NO_ERROR == decryptor_.Decrypt(gp_session_id_2, decryption_parameters),
|
||||||
|
enable_session_sharing);
|
||||||
|
EXPECT_EQ(std::equal(data->decrypt_data.begin(), data->decrypt_data.end(),
|
||||||
|
decrypt_buffer.begin()),
|
||||||
|
enable_session_sharing);
|
||||||
|
|
||||||
|
decryptor_.CloseSession(gp_session_id_1);
|
||||||
|
decryptor_.CloseSession(gp_session_id_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_CASE_P(Cdm, WvCdmSessionSharingTest, ::testing::Bool());
|
||||||
|
|
||||||
TEST_F(WvCdmRequestLicenseTest, BaseMessageTest) {
|
TEST_F(WvCdmRequestLicenseTest, BaseMessageTest) {
|
||||||
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
decryptor_.OpenSession(g_key_system, NULL, &session_id_);
|
||||||
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
GenerateKeyRequest(g_key_system, g_key_id, kLicenseTypeStreaming);
|
||||||
|
|||||||
@@ -161,40 +161,58 @@ class WVDrmPlugin : public android::DrmPlugin,
|
|||||||
class WVClientPropertySet : public wvcdm::CdmClientPropertySet {
|
class WVClientPropertySet : public wvcdm::CdmClientPropertySet {
|
||||||
public:
|
public:
|
||||||
WVClientPropertySet()
|
WVClientPropertySet()
|
||||||
: mUsePrivacyMode(false) {}
|
: mUsePrivacyMode(false), mShareKeys(false), mSessionSharingId(0) {}
|
||||||
|
|
||||||
virtual ~WVClientPropertySet() {}
|
virtual ~WVClientPropertySet() {}
|
||||||
|
|
||||||
void set_security_level(const std::string& securityLevel) {
|
|
||||||
mSecurityLevel = securityLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual std::string security_level() const {
|
virtual std::string security_level() const {
|
||||||
return mSecurityLevel;
|
return mSecurityLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_use_privacy_mode(bool usePrivacyMode) {
|
void set_security_level(const std::string& securityLevel) {
|
||||||
mUsePrivacyMode = usePrivacyMode;
|
mSecurityLevel = securityLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual bool use_privacy_mode() const {
|
virtual bool use_privacy_mode() const {
|
||||||
return mUsePrivacyMode;
|
return mUsePrivacyMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_service_certificate(const std::vector<uint8_t>& serviceCertificate) {
|
void set_use_privacy_mode(bool usePrivacyMode) {
|
||||||
mServiceCertificate = serviceCertificate;
|
mUsePrivacyMode = usePrivacyMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::vector<uint8_t> service_certificate() const {
|
virtual std::vector<uint8_t> service_certificate() const {
|
||||||
return mServiceCertificate;
|
return mServiceCertificate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_service_certificate(const std::vector<uint8_t>& serviceCertificate) {
|
||||||
|
mServiceCertificate = serviceCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
|
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
|
||||||
|
|
||||||
std::string mSecurityLevel;
|
std::string mSecurityLevel;
|
||||||
bool mUsePrivacyMode;
|
bool mUsePrivacyMode;
|
||||||
std::vector<uint8_t> mServiceCertificate;
|
std::vector<uint8_t> mServiceCertificate;
|
||||||
|
bool mShareKeys;
|
||||||
|
uint32_t mSessionSharingId;
|
||||||
} mPropertySet;
|
} mPropertySet;
|
||||||
|
|
||||||
WvContentDecryptionModule* mCDM;
|
WvContentDecryptionModule* mCDM;
|
||||||
|
|||||||
@@ -392,6 +392,12 @@ status_t WVDrmPlugin::getPropertyString(const String8& name,
|
|||||||
} else {
|
} else {
|
||||||
value = kDisable;
|
value = kDisable;
|
||||||
}
|
}
|
||||||
|
} else if (name == "sessionSharing") {
|
||||||
|
if (mPropertySet.is_session_sharing_enabled()) {
|
||||||
|
value = kEnable;
|
||||||
|
} else {
|
||||||
|
value = kDisable;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ALOGE("App requested unknown string property %s", name.string());
|
ALOGE("App requested unknown string property %s", name.string());
|
||||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||||
@@ -475,6 +481,20 @@ status_t WVDrmPlugin::setPropertyString(const String8& name,
|
|||||||
ALOGE("App requested unknown privacy mode %s", value.string());
|
ALOGE("App requested unknown privacy mode %s", value.string());
|
||||||
return android::BAD_VALUE;
|
return android::BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
} else if (name == "sessionSharing") {
|
||||||
|
if (mCryptoSessions.size() == 0) {
|
||||||
|
if (value == kEnable) {
|
||||||
|
mPropertySet.set_is_session_sharing_enabled(true);
|
||||||
|
} else if (value == kDisable) {
|
||||||
|
mPropertySet.set_is_session_sharing_enabled(false);
|
||||||
|
} else {
|
||||||
|
ALOGE("App requested unknown sharing type %s", value.string());
|
||||||
|
return android::BAD_VALUE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ALOGE("App tried to change key sharing while sessions are open.");
|
||||||
|
return kErrorSessionIsOpen;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ALOGE("App set unknown string property %s", name.string());
|
ALOGE("App set unknown string property %s", name.string());
|
||||||
return android::ERROR_DRM_CANNOT_HANDLE;
|
return android::ERROR_DRM_CANNOT_HANDLE;
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ using namespace wvdrm;
|
|||||||
class MockCDM : public WvContentDecryptionModule {
|
class MockCDM : public WvContentDecryptionModule {
|
||||||
public:
|
public:
|
||||||
MOCK_METHOD3(OpenSession, CdmResponseType(const CdmKeySystem&,
|
MOCK_METHOD3(OpenSession, CdmResponseType(const CdmKeySystem&,
|
||||||
const CdmClientPropertySet*,
|
CdmClientPropertySet*,
|
||||||
CdmSessionId*));
|
CdmSessionId*));
|
||||||
|
|
||||||
MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&));
|
MOCK_METHOD1(CloseSession, CdmResponseType(const CdmSessionId&));
|
||||||
@@ -1181,7 +1181,6 @@ TEST_F(WVDrmPluginTest, GeneratesProvisioningNeededEvent) {
|
|||||||
ASSERT_EQ(ERROR_DRM_NOT_PROVISIONED, res);
|
ASSERT_EQ(ERROR_DRM_NOT_PROVISIONED, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
|
TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
|
||||||
StrictMock<MockCDM> cdm;
|
StrictMock<MockCDM> cdm;
|
||||||
StrictMock<MockCrypto> crypto;
|
StrictMock<MockCrypto> crypto;
|
||||||
@@ -1219,6 +1218,8 @@ TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
|
|||||||
EXPECT_STREQ("", propertySet->security_level().c_str());
|
EXPECT_STREQ("", propertySet->security_level().c_str());
|
||||||
EXPECT_FALSE(propertySet->use_privacy_mode());
|
EXPECT_FALSE(propertySet->use_privacy_mode());
|
||||||
EXPECT_EQ(0u, propertySet->service_certificate().size());
|
EXPECT_EQ(0u, propertySet->service_certificate().size());
|
||||||
|
EXPECT_FALSE(propertySet->is_session_sharing_enabled());
|
||||||
|
EXPECT_EQ(0u, propertySet->session_sharing_id());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(WVDrmPluginTest, CanSetSecurityLevel) {
|
TEST_F(WVDrmPluginTest, CanSetSecurityLevel) {
|
||||||
@@ -1395,3 +1396,107 @@ TEST_F(WVDrmPluginTest, CanSetServiceCertificate) {
|
|||||||
ASSERT_EQ(OK, res);
|
ASSERT_EQ(OK, res);
|
||||||
EXPECT_EQ(0u, propertySet->service_certificate().size());
|
EXPECT_EQ(0u, propertySet->service_certificate().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, CanSetSessionSharing) {
|
||||||
|
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 turning on session sharing
|
||||||
|
res = plugin.setPropertyString(String8("sessionSharing"), String8("enable"));
|
||||||
|
ASSERT_EQ(OK, res);
|
||||||
|
|
||||||
|
plugin.openSession(sessionId);
|
||||||
|
ASSERT_THAT(propertySet, NotNull());
|
||||||
|
EXPECT_TRUE(propertySet->is_session_sharing_enabled());
|
||||||
|
plugin.closeSession(sessionId);
|
||||||
|
|
||||||
|
// Test turning off session sharing
|
||||||
|
res = plugin.setPropertyString(String8("sessionSharing"), String8("disable"));
|
||||||
|
ASSERT_EQ(OK, res);
|
||||||
|
|
||||||
|
plugin.openSession(sessionId);
|
||||||
|
ASSERT_THAT(propertySet, NotNull());
|
||||||
|
EXPECT_FALSE(propertySet->is_session_sharing_enabled());
|
||||||
|
plugin.closeSession(sessionId);
|
||||||
|
|
||||||
|
// Test nonsense (Should Fail)
|
||||||
|
res = plugin.setPropertyString(String8("sessionSharing"), String8("nonsense"));
|
||||||
|
ASSERT_NE(OK, res);
|
||||||
|
|
||||||
|
// Test changing sharing with a session open (Should Fail)
|
||||||
|
plugin.openSession(sessionId);
|
||||||
|
res = plugin.setPropertyString(String8("sessionSharing"), String8("enable"));
|
||||||
|
ASSERT_NE(OK, res);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(WVDrmPluginTest, AllowsStoringOfSessionSharingId) {
|
||||||
|
StrictMock<MockCDM> cdm;
|
||||||
|
StrictMock<MockCrypto> crypto;
|
||||||
|
WVDrmPlugin plugin(&cdm, &crypto);
|
||||||
|
|
||||||
|
CdmClientPropertySet* propertySet = NULL;
|
||||||
|
|
||||||
|
uint32_t sharingId;
|
||||||
|
FILE* fp = fopen("/dev/urandom", "r");
|
||||||
|
fread(&sharingId, sizeof(uint32_t), 1, fp);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
// Provide expected mock behavior
|
||||||
|
{
|
||||||
|
// Provide expected behavior in response to OpenSession and store the
|
||||||
|
// property set
|
||||||
|
EXPECT_CALL(cdm, OpenSession(_, _, _))
|
||||||
|
.WillRepeatedly(DoAll(SetArgPointee<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());
|
||||||
|
propertySet->set_session_sharing_id(sharingId);
|
||||||
|
EXPECT_EQ(sharingId, propertySet->session_sharing_id());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user