Merge of CLs
* Move Properties::Init into platform-specific code This enables a refactor where property initialization for CE CDM will use values provided by the application during library initialization. [ Merge of http://go/wvgerrit/14510/ ] * Add Properties::AlwaysUseKeySetIds(). When true, all sessions will have key set IDs and all session IDs will be the same as the corresponding key set ID. This will help the new CDM interface stick more closely to the EME APIs, in which there are no such things as key set IDs and sessions only have a single, random ID used for both streaming and offline. [ Merge of http://go/wvgerrit/14521/ ] * Reserve key set IDs in memory, rather than on the file system. This makes it more efficient to use key set IDs for non-offline sessions. [ Merge of http://go/wvgerrit/14535/ ] Change-Id: I765c3519619b17cc3c4ef95b1a6b125f479ee1d0
This commit is contained in:
@@ -23,7 +23,8 @@ class WvCdmEventListener;
|
||||
class CdmSession {
|
||||
public:
|
||||
CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
||||
const std::string& origin, WvCdmEventListener* event_listener);
|
||||
const std::string& origin, WvCdmEventListener* event_listener,
|
||||
CdmSessionId* forced_session_id);
|
||||
virtual ~CdmSession();
|
||||
|
||||
virtual CdmResponseType Init();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#define WVCDM_CORE_DEVICE_FILES_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "scoped_ptr.h"
|
||||
@@ -110,7 +111,6 @@ class DeviceFiles {
|
||||
static std::string GetCertificateFileName(const std::string& origin);
|
||||
static std::string GetLicenseFileNameExtension();
|
||||
static std::string GetUsageInfoFileName(const std::string& app_id);
|
||||
static std::string GetBlankFileData();
|
||||
static std::string GetFileNameSafeHash(const std::string& input);
|
||||
|
||||
// For testing only:
|
||||
@@ -122,7 +122,7 @@ class DeviceFiles {
|
||||
FRIEND_TEST(DeviceCertificateTest, HasCertificate);
|
||||
FRIEND_TEST(DeviceFilesStoreTest, StoreLicense);
|
||||
FRIEND_TEST(DeviceFilesTest, DeleteLicense);
|
||||
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIds);
|
||||
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem);
|
||||
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
|
||||
FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility);
|
||||
FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility);
|
||||
@@ -141,6 +141,8 @@ class DeviceFiles {
|
||||
FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest);
|
||||
#endif
|
||||
|
||||
static std::set<std::string> reserved_license_ids_;
|
||||
|
||||
scoped_ptr<File> file_;
|
||||
CdmSecurityLevel security_level_;
|
||||
bool initialized_;
|
||||
|
||||
@@ -54,6 +54,7 @@ class Properties {
|
||||
std::string* base_path);
|
||||
static bool GetFactoryKeyboxPath(std::string* keybox);
|
||||
static bool GetOEMCryptoPath(std::string* library_name);
|
||||
static bool AlwaysUseKeySetIds();
|
||||
static bool GetSecurityLevelDirectories(std::vector<std::string>* dirs);
|
||||
static bool GetApplicationId(const CdmSessionId& session_id,
|
||||
std::string* app_id);
|
||||
|
||||
@@ -91,8 +91,13 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
|
||||
return INVALID_PARAMETERS_ENG_1;
|
||||
}
|
||||
|
||||
CdmSessionId* forced_session_id = NULL;
|
||||
if (Properties::AlwaysUseKeySetIds() && !session_id->empty()) {
|
||||
forced_session_id = session_id;
|
||||
}
|
||||
|
||||
scoped_ptr<CdmSession> new_session(
|
||||
new CdmSession(property_set, origin, event_listener));
|
||||
new CdmSession(property_set, origin, event_listener, forced_session_id));
|
||||
if (new_session->session_id().empty()) {
|
||||
LOGE("CdmEngine::OpenSession: failure to generate session ID");
|
||||
return EMPTY_SESSION_ID;
|
||||
@@ -180,7 +185,10 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
|
||||
CdmSessionId id = session_id;
|
||||
CdmResponseType sts;
|
||||
|
||||
if (license_type == kLicenseTypeRelease) {
|
||||
// NOTE: If AlwaysUseKeySetIds() is true, there is no need to consult the
|
||||
// release_key_sets_ map for release licenses.
|
||||
if (license_type == kLicenseTypeRelease &&
|
||||
!Properties::AlwaysUseKeySetIds()) {
|
||||
if (key_set_id.empty()) {
|
||||
LOGE("CdmEngine::GenerateKeyRequest: invalid key set ID");
|
||||
return EMPTY_KEYSET_ID_ENG_2;
|
||||
@@ -666,7 +674,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
usage_property_set_->set_security_level(kLevelDefault);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL));
|
||||
CdmResponseType status = usage_session_->Init();
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: session init error");
|
||||
@@ -685,7 +693,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
usage_property_set_->set_security_level(kLevel3);
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL));
|
||||
status = usage_session_->Init();
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: session init error");
|
||||
@@ -754,7 +762,7 @@ CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
|
||||
usage_property_set_->set_app_id(app_id);
|
||||
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL, NULL));
|
||||
|
||||
CdmResponseType status = usage_session_->Init();
|
||||
if (NO_ERROR != status) {
|
||||
@@ -833,7 +841,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
|
||||
: kLevelDefault;
|
||||
usage_property_set_->set_security_level(security_level);
|
||||
usage_session_.reset(
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL));
|
||||
new CdmSession(usage_property_set_.get(), EMPTY_ORIGIN, NULL,
|
||||
NULL));
|
||||
CdmResponseType status2 = usage_session_->
|
||||
DeleteMultipleUsageInformation(provider_session_tokens);
|
||||
if (status2 != NO_ERROR) {
|
||||
|
||||
@@ -25,14 +25,13 @@ namespace wvcdm {
|
||||
|
||||
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
||||
const std::string& origin,
|
||||
WvCdmEventListener* event_listener)
|
||||
WvCdmEventListener* event_listener,
|
||||
CdmSessionId* forced_session_id)
|
||||
: initialized_(false),
|
||||
session_id_(GenerateSessionId()),
|
||||
origin_(origin),
|
||||
license_parser_(new CdmLicense),
|
||||
crypto_session_(new CryptoSession),
|
||||
policy_engine_(
|
||||
new PolicyEngine(session_id_, event_listener, crypto_session_.get())),
|
||||
file_handle_(new DeviceFiles),
|
||||
license_received_(false),
|
||||
is_offline_(false),
|
||||
@@ -43,6 +42,17 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
|
||||
has_decrypted_since_last_report_(false),
|
||||
is_initial_usage_update_(true),
|
||||
is_usage_update_needed_(false) {
|
||||
if (Properties::AlwaysUseKeySetIds()) {
|
||||
if (forced_session_id) {
|
||||
key_set_id_ = *forced_session_id;
|
||||
} else {
|
||||
bool ok = GenerateKeySetId(&key_set_id_);
|
||||
assert(ok);
|
||||
}
|
||||
session_id_ = key_set_id_;
|
||||
}
|
||||
policy_engine_.reset(new PolicyEngine(
|
||||
session_id_, event_listener, crypto_session_.get()));
|
||||
if (cdm_client_property_set) {
|
||||
if (cdm_client_property_set->security_level() ==
|
||||
QUERY_VALUE_SECURITY_LEVEL_L3) {
|
||||
@@ -203,7 +213,8 @@ CdmResponseType CdmSession::GenerateKeyRequest(
|
||||
LOGW("CdmSession::GenerateKeyRequest: init data absent");
|
||||
return INIT_DATA_NOT_FOUND;
|
||||
}
|
||||
if (is_offline_ && !GenerateKeySetId(&key_set_id_)) {
|
||||
if (is_offline_ && key_set_id_.empty() &&
|
||||
!GenerateKeySetId(&key_set_id_)) {
|
||||
LOGE("CdmSession::GenerateKeyRequest: Unable to generate key set ID");
|
||||
return KEY_REQUEST_ERROR_1;
|
||||
}
|
||||
|
||||
@@ -46,8 +46,6 @@ const char* kSecurityLevelPathCompatibilityExclusionList[] = {
|
||||
size_t kSecurityLevelPathCompatibilityExclusionListSize =
|
||||
sizeof(kSecurityLevelPathCompatibilityExclusionList) /
|
||||
sizeof(*kSecurityLevelPathCompatibilityExclusionList);
|
||||
// Some platforms cannot store a truly blank file, so we use a W for Widevine.
|
||||
const char kBlankFileData[] = "W";
|
||||
|
||||
bool Hash(const std::string& data, std::string* hash) {
|
||||
if (!hash) return false;
|
||||
@@ -64,6 +62,9 @@ bool Hash(const std::string& data, std::string* hash) {
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
// static
|
||||
std::set<std::string> DeviceFiles::reserved_license_ids_;
|
||||
|
||||
DeviceFiles::DeviceFiles()
|
||||
: file_(NULL),
|
||||
security_level_(kSecurityLevelUninitialized),
|
||||
@@ -228,6 +229,7 @@ bool DeviceFiles::StoreLicense(
|
||||
std::string serialized_file;
|
||||
file.SerializeToString(&serialized_file);
|
||||
|
||||
reserved_license_ids_.erase(key_set_id);
|
||||
return StoreFileWithHash(key_set_id + kLicenseFileNameExt, serialized_file);
|
||||
}
|
||||
|
||||
@@ -331,6 +333,8 @@ bool DeviceFiles::LicenseExists(const std::string& key_set_id) {
|
||||
return false;
|
||||
}
|
||||
return FileExists(key_set_id + kLicenseFileNameExt);
|
||||
return reserved_license_ids_.count(key_set_id) ||
|
||||
FileExists(key_set_id + kLicenseFileNameExt);
|
||||
}
|
||||
|
||||
bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) {
|
||||
@@ -338,7 +342,8 @@ bool DeviceFiles::ReserveLicenseId(const std::string& key_set_id) {
|
||||
LOGW("DeviceFiles::ReserveLicenseId: not initialized");
|
||||
return false;
|
||||
}
|
||||
return StoreFileRaw(key_set_id + kLicenseFileNameExt, kBlankFileData);
|
||||
reserved_license_ids_.insert(key_set_id);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
|
||||
@@ -804,8 +809,6 @@ std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) {
|
||||
return kUsageInfoFileNamePrefix + hash + kUsageInfoFileNameExt;
|
||||
}
|
||||
|
||||
std::string DeviceFiles::GetBlankFileData() { return kBlankFileData; }
|
||||
|
||||
std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {
|
||||
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
|
||||
const unsigned char* input_ptr =
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "log.h"
|
||||
#include "properties_configuration.h"
|
||||
#include "properties.h"
|
||||
#include "wv_cdm_constants.h"
|
||||
|
||||
namespace {
|
||||
@@ -16,17 +16,6 @@ bool Properties::use_certificates_as_identification_;
|
||||
bool Properties::security_level_path_backward_compatibility_support_;
|
||||
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_;
|
||||
|
||||
void Properties::Init() {
|
||||
oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers;
|
||||
oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo;
|
||||
oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers;
|
||||
use_certificates_as_identification_ =
|
||||
kPropertyUseCertificatesAsIdentification;
|
||||
security_level_path_backward_compatibility_support_ =
|
||||
kSecurityLevelPathBackwardCompatibilitySupport;
|
||||
session_property_set_.reset(new CdmClientPropertySetMap());
|
||||
}
|
||||
|
||||
bool Properties::AddSessionPropertySet(
|
||||
const CdmSessionId& session_id, const CdmClientPropertySet* property_set) {
|
||||
if (NULL == session_property_set_.get()) {
|
||||
|
||||
@@ -132,7 +132,7 @@ class MockCdmLicense : public CdmLicense {
|
||||
class CdmSessionTest : public ::testing::Test {
|
||||
protected:
|
||||
virtual void SetUp() {
|
||||
cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL));
|
||||
cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL, NULL));
|
||||
// Inject testing mocks.
|
||||
license_parser_ = new MockCdmLicense();
|
||||
cdm_session_->set_license_parser(license_parser_);
|
||||
|
||||
@@ -2118,26 +2118,15 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
|
||||
EXPECT_FALSE(device_files.LicenseExists(license_test_data[0].key_set_id));
|
||||
}
|
||||
|
||||
TEST_F(DeviceFilesTest, ReserveLicenseIds) {
|
||||
TEST_F(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem) {
|
||||
// Validate that ReserveLicenseIds does not touch the file system.
|
||||
MockFile file;
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_)))
|
||||
.Times(kNumberOfLicenses)
|
||||
.WillRepeatedly(Return(true));
|
||||
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))).Times(0);
|
||||
EXPECT_CALL(file, CreateDirectory(_)).Times(0);
|
||||
|
||||
for (size_t i = 0; i < kNumberOfLicenses; ++i) {
|
||||
std::string license_path = device_base_path_ +
|
||||
license_test_data[i].key_set_id +
|
||||
DeviceFiles::GetLicenseFileNameExtension();
|
||||
InSequence calls;
|
||||
EXPECT_CALL(file, Open(StrEq(license_path),
|
||||
AllOf(IsCreateFileFlagSet(), IsBinaryFileFlagSet())))
|
||||
.WillOnce(Return(true));
|
||||
EXPECT_CALL(file, Write(StrEq(DeviceFiles::GetBlankFileData()),
|
||||
DeviceFiles::GetBlankFileData().size()))
|
||||
.WillOnce(ReturnArg<1>());
|
||||
EXPECT_CALL(file, Close());
|
||||
}
|
||||
EXPECT_CALL(file, Open(_, _)).Times(0);
|
||||
EXPECT_CALL(file, Write(_, _)).Times(0);
|
||||
EXPECT_CALL(file, Close()).Times(0);
|
||||
EXPECT_CALL(file, Read(_, _)).Times(0);
|
||||
|
||||
DeviceFiles device_files;
|
||||
@@ -2145,6 +2134,8 @@ TEST_F(DeviceFilesTest, ReserveLicenseIds) {
|
||||
device_files.SetTestFile(&file);
|
||||
for (size_t i = 0; i < kNumberOfLicenses; i++) {
|
||||
EXPECT_TRUE(device_files.ReserveLicenseId(license_test_data[i].key_set_id));
|
||||
// Validate that the license IDs are actually reserved.
|
||||
EXPECT_TRUE(device_files.LicenseExists(license_test_data[i].key_set_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2013 Google Inc. All Rights Reserved.
|
||||
|
||||
#include "properties.h"
|
||||
#include "properties_configuration.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sstream>
|
||||
@@ -42,6 +43,17 @@ bool GetAndroidProperty(const char* key, std::string* value) {
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
void Properties::Init() {
|
||||
oem_crypto_use_secure_buffers_ = kPropertyOemCryptoUseSecureBuffers;
|
||||
oem_crypto_use_fifo_ = kPropertyOemCryptoUseFifo;
|
||||
oem_crypto_use_userspace_buffers_ = kPropertyOemCryptoUseUserSpaceBuffers;
|
||||
use_certificates_as_identification_ =
|
||||
kPropertyUseCertificatesAsIdentification;
|
||||
security_level_path_backward_compatibility_support_ =
|
||||
kSecurityLevelPathBackwardCompatibilitySupport;
|
||||
session_property_set_.reset(new CdmClientPropertySetMap());
|
||||
}
|
||||
|
||||
bool Properties::GetCompanyName(std::string* company_name) {
|
||||
if (!company_name) {
|
||||
LOGW("Properties::GetCompanyName: Invalid parameter");
|
||||
@@ -139,4 +151,8 @@ bool Properties::GetOEMCryptoPath(std::string* library_name) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Properties::AlwaysUseKeySetIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace wvcdm
|
||||
|
||||
Reference in New Issue
Block a user