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 { class CdmSession {
public: public:
CdmSession(const CdmClientPropertySet* cdm_client_property_set, 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 ~CdmSession();
virtual CdmResponseType Init(); virtual CdmResponseType Init();

View File

@@ -4,6 +4,7 @@
#define WVCDM_CORE_DEVICE_FILES_H_ #define WVCDM_CORE_DEVICE_FILES_H_
#include <unistd.h> #include <unistd.h>
#include <set>
#include <string> #include <string>
#include "scoped_ptr.h" #include "scoped_ptr.h"
@@ -110,7 +111,6 @@ class DeviceFiles {
static std::string GetCertificateFileName(const std::string& origin); static std::string GetCertificateFileName(const std::string& origin);
static std::string GetLicenseFileNameExtension(); static std::string GetLicenseFileNameExtension();
static std::string GetUsageInfoFileName(const std::string& app_id); static std::string GetUsageInfoFileName(const std::string& app_id);
static std::string GetBlankFileData();
static std::string GetFileNameSafeHash(const std::string& input); static std::string GetFileNameSafeHash(const std::string& input);
// For testing only: // For testing only:
@@ -122,7 +122,7 @@ class DeviceFiles {
FRIEND_TEST(DeviceCertificateTest, HasCertificate); FRIEND_TEST(DeviceCertificateTest, HasCertificate);
FRIEND_TEST(DeviceFilesStoreTest, StoreLicense); FRIEND_TEST(DeviceFilesStoreTest, StoreLicense);
FRIEND_TEST(DeviceFilesTest, DeleteLicense); FRIEND_TEST(DeviceFilesTest, DeleteLicense);
FRIEND_TEST(DeviceFilesTest, ReserveLicenseIds); FRIEND_TEST(DeviceFilesTest, ReserveLicenseIdsDoesNotUseFileSystem);
FRIEND_TEST(DeviceFilesTest, RetrieveLicenses); FRIEND_TEST(DeviceFilesTest, RetrieveLicenses);
FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility); FRIEND_TEST(DeviceFilesTest, AppParametersBackwardCompatibility);
FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility); FRIEND_TEST(DeviceFilesTest, SecurityLevelPathBackwardCompatibility);
@@ -141,6 +141,8 @@ class DeviceFiles {
FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest); FRIEND_TEST(WvCdmExtendedDurationTest, UsageOverflowTest);
#endif #endif
static std::set<std::string> reserved_license_ids_;
scoped_ptr<File> file_; scoped_ptr<File> file_;
CdmSecurityLevel security_level_; CdmSecurityLevel security_level_;
bool initialized_; bool initialized_;

View File

@@ -54,6 +54,7 @@ class Properties {
std::string* base_path); std::string* base_path);
static bool GetFactoryKeyboxPath(std::string* keybox); static bool GetFactoryKeyboxPath(std::string* keybox);
static bool GetOEMCryptoPath(std::string* library_name); static bool GetOEMCryptoPath(std::string* library_name);
static bool AlwaysUseKeySetIds();
static bool GetSecurityLevelDirectories(std::vector<std::string>* dirs); static bool GetSecurityLevelDirectories(std::vector<std::string>* dirs);
static bool GetApplicationId(const CdmSessionId& session_id, static bool GetApplicationId(const CdmSessionId& session_id,
std::string* app_id); std::string* app_id);

View File

@@ -91,8 +91,13 @@ CdmResponseType CdmEngine::OpenSession(const CdmKeySystem& key_system,
return INVALID_PARAMETERS_ENG_1; 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( 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()) { if (new_session->session_id().empty()) {
LOGE("CdmEngine::OpenSession: failure to generate session ID"); LOGE("CdmEngine::OpenSession: failure to generate session ID");
return EMPTY_SESSION_ID; return EMPTY_SESSION_ID;
@@ -180,7 +185,10 @@ CdmResponseType CdmEngine::GenerateKeyRequest(
CdmSessionId id = session_id; CdmSessionId id = session_id;
CdmResponseType sts; 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()) { if (key_set_id.empty()) {
LOGE("CdmEngine::GenerateKeyRequest: invalid key set ID"); LOGE("CdmEngine::GenerateKeyRequest: invalid key set ID");
return EMPTY_KEYSET_ID_ENG_2; 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_security_level(kLevelDefault);
usage_property_set_->set_app_id(app_id); usage_property_set_->set_app_id(app_id);
usage_session_.reset( 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(); CdmResponseType status = usage_session_->Init();
if (NO_ERROR != status) { if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error"); 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_security_level(kLevel3);
usage_property_set_->set_app_id(app_id); usage_property_set_->set_app_id(app_id);
usage_session_.reset( 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(); status = usage_session_->Init();
if (NO_ERROR != status) { if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error"); 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_property_set_->set_app_id(app_id);
usage_session_.reset( 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(); CdmResponseType status = usage_session_->Init();
if (NO_ERROR != status) { if (NO_ERROR != status) {
@@ -833,7 +841,8 @@ CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
: kLevelDefault; : kLevelDefault;
usage_property_set_->set_security_level(security_level); usage_property_set_->set_security_level(security_level);
usage_session_.reset( 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_-> CdmResponseType status2 = usage_session_->
DeleteMultipleUsageInformation(provider_session_tokens); DeleteMultipleUsageInformation(provider_session_tokens);
if (status2 != NO_ERROR) { if (status2 != NO_ERROR) {

View File

@@ -25,14 +25,13 @@ namespace wvcdm {
CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set, CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
const std::string& origin, const std::string& origin,
WvCdmEventListener* event_listener) WvCdmEventListener* event_listener,
CdmSessionId* forced_session_id)
: initialized_(false), : initialized_(false),
session_id_(GenerateSessionId()), session_id_(GenerateSessionId()),
origin_(origin), origin_(origin),
license_parser_(new CdmLicense), license_parser_(new CdmLicense),
crypto_session_(new CryptoSession), crypto_session_(new CryptoSession),
policy_engine_(
new PolicyEngine(session_id_, event_listener, crypto_session_.get())),
file_handle_(new DeviceFiles), file_handle_(new DeviceFiles),
license_received_(false), license_received_(false),
is_offline_(false), is_offline_(false),
@@ -43,6 +42,17 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set,
has_decrypted_since_last_report_(false), has_decrypted_since_last_report_(false),
is_initial_usage_update_(true), is_initial_usage_update_(true),
is_usage_update_needed_(false) { 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) {
if (cdm_client_property_set->security_level() == if (cdm_client_property_set->security_level() ==
QUERY_VALUE_SECURITY_LEVEL_L3) { QUERY_VALUE_SECURITY_LEVEL_L3) {
@@ -203,7 +213,8 @@ CdmResponseType CdmSession::GenerateKeyRequest(
LOGW("CdmSession::GenerateKeyRequest: init data absent"); LOGW("CdmSession::GenerateKeyRequest: init data absent");
return INIT_DATA_NOT_FOUND; 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"); LOGE("CdmSession::GenerateKeyRequest: Unable to generate key set ID");
return KEY_REQUEST_ERROR_1; return KEY_REQUEST_ERROR_1;
} }

View File

@@ -46,8 +46,6 @@ const char* kSecurityLevelPathCompatibilityExclusionList[] = {
size_t kSecurityLevelPathCompatibilityExclusionListSize = size_t kSecurityLevelPathCompatibilityExclusionListSize =
sizeof(kSecurityLevelPathCompatibilityExclusionList) / sizeof(kSecurityLevelPathCompatibilityExclusionList) /
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) { bool Hash(const std::string& data, std::string* hash) {
if (!hash) return false; if (!hash) return false;
@@ -64,6 +62,9 @@ bool Hash(const std::string& data, std::string* hash) {
namespace wvcdm { namespace wvcdm {
// static
std::set<std::string> DeviceFiles::reserved_license_ids_;
DeviceFiles::DeviceFiles() DeviceFiles::DeviceFiles()
: file_(NULL), : file_(NULL),
security_level_(kSecurityLevelUninitialized), security_level_(kSecurityLevelUninitialized),
@@ -228,6 +229,7 @@ bool DeviceFiles::StoreLicense(
std::string serialized_file; std::string serialized_file;
file.SerializeToString(&serialized_file); file.SerializeToString(&serialized_file);
reserved_license_ids_.erase(key_set_id);
return StoreFileWithHash(key_set_id + kLicenseFileNameExt, serialized_file); return StoreFileWithHash(key_set_id + kLicenseFileNameExt, serialized_file);
} }
@@ -331,6 +333,8 @@ bool DeviceFiles::LicenseExists(const std::string& key_set_id) {
return false; return false;
} }
return FileExists(key_set_id + kLicenseFileNameExt); 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) { 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"); LOGW("DeviceFiles::ReserveLicenseId: not initialized");
return false; 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, 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; return kUsageInfoFileNamePrefix + hash + kUsageInfoFileNameExt;
} }
std::string DeviceFiles::GetBlankFileData() { return kBlankFileData; }
std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) { std::string DeviceFiles::GetFileNameSafeHash(const std::string& input) {
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH); std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
const unsigned char* input_ptr = const unsigned char* input_ptr =

View File

@@ -1,7 +1,7 @@
// Copyright 2013 Google Inc. All Rights Reserved. // Copyright 2013 Google Inc. All Rights Reserved.
#include "log.h" #include "log.h"
#include "properties_configuration.h" #include "properties.h"
#include "wv_cdm_constants.h" #include "wv_cdm_constants.h"
namespace { namespace {
@@ -16,17 +16,6 @@ bool Properties::use_certificates_as_identification_;
bool Properties::security_level_path_backward_compatibility_support_; bool Properties::security_level_path_backward_compatibility_support_;
scoped_ptr<CdmClientPropertySetMap> Properties::session_property_set_; 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( bool Properties::AddSessionPropertySet(
const CdmSessionId& session_id, const CdmClientPropertySet* property_set) { const CdmSessionId& session_id, const CdmClientPropertySet* property_set) {
if (NULL == session_property_set_.get()) { if (NULL == session_property_set_.get()) {

View File

@@ -132,7 +132,7 @@ class MockCdmLicense : public CdmLicense {
class CdmSessionTest : public ::testing::Test { class CdmSessionTest : public ::testing::Test {
protected: protected:
virtual void SetUp() { virtual void SetUp() {
cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL)); cdm_session_.reset(new CdmSession(NULL, kTestOrigin, NULL, NULL));
// Inject testing mocks. // Inject testing mocks.
license_parser_ = new MockCdmLicense(); license_parser_ = new MockCdmLicense();
cdm_session_->set_license_parser(license_parser_); 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)); 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; MockFile file;
EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))) EXPECT_CALL(file, IsDirectory(StrEq(device_base_path_))).Times(0);
.Times(kNumberOfLicenses)
.WillRepeatedly(Return(true));
EXPECT_CALL(file, CreateDirectory(_)).Times(0); EXPECT_CALL(file, CreateDirectory(_)).Times(0);
for (size_t i = 0; i < kNumberOfLicenses; ++i) { EXPECT_CALL(file, Open(_, _)).Times(0);
std::string license_path = device_base_path_ + EXPECT_CALL(file, Write(_, _)).Times(0);
license_test_data[i].key_set_id + EXPECT_CALL(file, Close()).Times(0);
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, Read(_, _)).Times(0); EXPECT_CALL(file, Read(_, _)).Times(0);
DeviceFiles device_files; DeviceFiles device_files;
@@ -2145,6 +2134,8 @@ TEST_F(DeviceFilesTest, ReserveLicenseIds) {
device_files.SetTestFile(&file); device_files.SetTestFile(&file);
for (size_t i = 0; i < kNumberOfLicenses; i++) { for (size_t i = 0; i < kNumberOfLicenses; i++) {
EXPECT_TRUE(device_files.ReserveLicenseId(license_test_data[i].key_set_id)); 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. // Copyright 2013 Google Inc. All Rights Reserved.
#include "properties.h" #include "properties.h"
#include "properties_configuration.h"
#include <unistd.h> #include <unistd.h>
#include <sstream> #include <sstream>
@@ -42,6 +43,17 @@ bool GetAndroidProperty(const char* key, std::string* value) {
namespace wvcdm { 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) { bool Properties::GetCompanyName(std::string* company_name) {
if (!company_name) { if (!company_name) {
LOGW("Properties::GetCompanyName: Invalid parameter"); LOGW("Properties::GetCompanyName: Invalid parameter");
@@ -139,4 +151,8 @@ bool Properties::GetOEMCryptoPath(std::string* library_name) {
return true; return true;
} }
bool Properties::AlwaysUseKeySetIds() {
return false;
}
} // namespace wvcdm } // namespace wvcdm