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:
Rahul Frias
2015-09-23 18:45:05 -07:00
parent ae5397ebcd
commit 3343f886a3
10 changed files with 71 additions and 48 deletions

View File

@@ -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();

View File

@@ -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_;

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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 =

View File

@@ -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()) {

View File

@@ -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_);

View File

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

View File

@@ -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