Allow Secure Stops to be queried and deleted by application ID

This CL changes the WVDrmPlugin so that an application can segregate
its secure stops from those of other applications by setting an
application ID.

This CL is a merge of the following Widevine CLs:
https://widevine-internal-review.googlesource.com/#/c/11565/
Add getSecureStop by ssid

https://widevine-internal-review.googlesource.com/#/c/11572
Add getSecureStop by SSID and releaseAllSecureStops by app id.

https://widevine-internal-review.googlesource.com/#/c/11564/
Store Usage Info by App Id (device_file stubs)

https://widevine-internal-review.googlesource.com/#/c/11563/
Add application id to StoreUsageInfo.

https://widevine-internal-review.googlesource.com/#/c/11561/
Added Application ID to PropertySet for secure stop.

bug: 18053197
bug: 18076411
Change-Id: I5444baf67ba1b960dee2dc958bced8de82ab70a3
This commit is contained in:
Fred Gylys-Colwell
2014-11-05 17:39:44 -08:00
parent b3650a9661
commit 20191d996c
19 changed files with 421 additions and 54 deletions

View File

@@ -19,6 +19,7 @@ class CdmClientPropertySet {
virtual bool is_session_sharing_enabled() const = 0; virtual bool is_session_sharing_enabled() const = 0;
virtual uint32_t session_sharing_id() const = 0; virtual uint32_t session_sharing_id() const = 0;
virtual void set_session_sharing_id(uint32_t id) = 0; virtual void set_session_sharing_id(uint32_t id) = 0;
virtual const std::string& app_id() const = 0;
}; };
} // namespace wvcdm } // namespace wvcdm

View File

@@ -93,7 +93,16 @@ class CdmEngine {
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level); virtual CdmResponseType Unprovision(CdmSecurityLevel security_level);
// Usage related methods for streaming licenses // Usage related methods for streaming licenses
virtual CdmResponseType GetUsageInfo(CdmUsageInfo* usage_info); // Retrieve a random usage info from the list of all usage infos for this app
// id.
virtual CdmResponseType GetUsageInfo(const std::string& app_id,
CdmUsageInfo* usage_info);
// Retrieve the usage info for the specified pst.
// Returns UNKNOWN_ERROR if no usage info was found.
virtual CdmResponseType GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info);
virtual CdmResponseType ReleaseAllUsageInfo(const std::string& app_id);
virtual CdmResponseType ReleaseUsageInfo( virtual CdmResponseType ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message); const CdmUsageInfoReleaseMessage& message);
@@ -120,7 +129,8 @@ class CdmEngine {
private: private:
// private methods // private methods
bool ValidateKeySystem(const CdmKeySystem& key_system); bool ValidateKeySystem(const CdmKeySystem& key_system);
CdmResponseType GetUsageInfo(SecurityLevel requested_security_level, CdmResponseType GetUsageInfo(const std::string& app_id,
SecurityLevel requested_security_level,
CdmUsageInfo* usage_info); CdmUsageInfo* usage_info);
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id); void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);

View File

@@ -83,9 +83,11 @@ class CdmSession {
virtual void OnTimerEvent(bool update_usage); virtual void OnTimerEvent(bool update_usage);
virtual void OnKeyReleaseEvent(const CdmKeySetId& key_set_id); virtual void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);
virtual void GetApplicationId(std::string* app_id);
virtual SecurityLevel GetRequestedSecurityLevel(); virtual SecurityLevel GetRequestedSecurityLevel();
virtual CdmSecurityLevel GetSecurityLevel(); virtual CdmSecurityLevel GetSecurityLevel();
virtual CdmResponseType DeleteUsageInformation(const std::string& app_id);
virtual CdmResponseType UpdateUsageInformation(); virtual CdmResponseType UpdateUsageInformation();
virtual bool is_initial_usage_update() { return is_initial_usage_update_; } virtual bool is_initial_usage_update() { return is_initial_usage_update_; }
@@ -120,6 +122,7 @@ class CdmSession {
bool is_offline_; bool is_offline_;
bool is_release_; bool is_release_;
CdmSecurityLevel security_level_; CdmSecurityLevel security_level_;
std::string app_id_;
// decryption and usage flags // decryption and usage flags
bool is_initial_decryption_; bool is_initial_decryption_;

View File

@@ -62,11 +62,22 @@ class DeviceFiles {
virtual bool StoreUsageInfo(const std::string& provider_session_token, virtual bool StoreUsageInfo(const std::string& provider_session_token,
const CdmKeyMessage& key_request, const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response); const CdmKeyResponse& key_response,
virtual bool DeleteUsageInfo(const std::string& provider_session_token); const std::string& app_id);
virtual bool DeleteUsageInfo(); virtual bool DeleteUsageInfo(const std::string& app_id,
const std::string& provider_session_token);
virtual bool DeleteAllUsageInfoForApp(const std::string& app_id);
// Retrieve one usage info from the file. Subsequent calls will retrieve
// subsequent entries in the table for this app_id.
virtual bool RetrieveUsageInfo( virtual bool RetrieveUsageInfo(
const std::string& app_id,
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info); std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info);
// Retrieve the usage info entry specified by |provider_session_token|.
// Returns false if the entry could not be found.
virtual bool RetrieveUsageInfo(const std::string& app_id,
const std::string& provider_session_token,
CdmKeyMessage* license_request,
CdmKeyResponse* license_response);
private: private:
bool StoreFile(const char* name, const std::string& serialized_file); bool StoreFile(const char* name, const std::string& serialized_file);
@@ -80,7 +91,7 @@ class DeviceFiles {
// For testing only: // For testing only:
static std::string GetCertificateFileName(); static std::string GetCertificateFileName();
static std::string GetLicenseFileNameExtension(); static std::string GetLicenseFileNameExtension();
static std::string GetUsageInfoFileName(); static std::string GetUsageInfoFileName(const std::string& app_id);
void SetTestFile(File* file); void SetTestFile(File* file);
#if defined(UNIT_TEST) #if defined(UNIT_TEST)
FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel); FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel);

View File

@@ -53,6 +53,8 @@ class Properties {
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 GetSecurityLevelDirectories(std::vector<std::string>* dirs); static bool GetSecurityLevelDirectories(std::vector<std::string>* dirs);
static bool GetApplicationId(const CdmSessionId& session_id,
std::string* app_id);
static bool GetSecurityLevel(const CdmSessionId& session_id, static bool GetSecurityLevel(const CdmSessionId& session_id,
std::string* security_level); std::string* security_level);
static bool GetServiceCertificate(const CdmSessionId& session_id, static bool GetServiceCertificate(const CdmSessionId& session_id,

View File

@@ -15,6 +15,7 @@ typedef std::string CdmInitData;
typedef std::string CdmKeyMessage; typedef std::string CdmKeyMessage;
typedef std::string CdmKeyResponse; typedef std::string CdmKeyResponse;
typedef std::string KeyId; typedef std::string KeyId;
typedef std::string CdmSecureStopId;
typedef std::string CdmSessionId; typedef std::string CdmSessionId;
typedef std::string CdmKeySetId; typedef std::string CdmKeySetId;
typedef std::string RequestId; typedef std::string RequestId;

View File

@@ -43,7 +43,11 @@ class UsagePropertySet : public CdmClientPropertySet {
virtual void set_session_sharing_id(uint32_t id) { virtual void set_session_sharing_id(uint32_t id) {
id; // noop to suppress warning id; // noop to suppress warning
} }
virtual const std::string& app_id() const { return app_id_; }
void set_app_id(const std::string& appId) { app_id_ = appId; }
private: private:
std::string app_id_;
std::string security_level_; std::string security_level_;
const std::string empty_; const std::string empty_;
}; };
@@ -582,29 +586,95 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
return status; return status;
} }
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) { CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info) {
if (NULL == usage_property_set_.get()) {
usage_property_set_.reset(new UsagePropertySet());
}
usage_property_set_->set_security_level(kLevelDefault);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(usage_property_set_.get()));
CdmResponseType status = usage_session_->Init();
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
return status;
}
DeviceFiles handle;
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: device file init error");
return UNKNOWN_ERROR;
}
CdmKeyMessage license_request;
CdmKeyResponse license_response;
if (!handle.RetrieveUsageInfo(app_id, ssid, &license_request,
&license_response)) {
usage_property_set_->set_security_level(kLevel3);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(usage_property_set_.get()));
status = usage_session_->Init();
if (NO_ERROR != status) {
LOGE("CdmEngine::GetUsageInfo: session init error");
return status;
}
if (!handle.Reset(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: device file init error");
return UNKNOWN_ERROR;
}
if (!handle.RetrieveUsageInfo(app_id, ssid, &license_request,
&license_response)) {
// No entry found for that ssid.
return UNKNOWN_ERROR;
}
}
std::string server_url;
usage_info->resize(1);
status =
usage_session_->RestoreUsageSession(license_request, license_response);
if (KEY_ADDED != status) {
LOGE("CdmEngine::GetUsageInfo: restore usage session error %d", status);
usage_info->clear();
return status;
}
status =
usage_session_->GenerateReleaseRequest(&(*usage_info)[0], &server_url);
if (KEY_MESSAGE != status) {
LOGE("CdmEngine::GetUsageInfo: generate release request error: %d", status);
usage_info->clear();
return status;
}
return KEY_MESSAGE;
}
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
CdmUsageInfo* usage_info) {
// Return a random usage report from a random security level // Return a random usage report from a random security level
SecurityLevel security_level = ((rand() % 2) == 0) ? kLevelDefault : kLevel3; SecurityLevel security_level = ((rand() % 2) == 0) ? kLevelDefault : kLevel3;
CdmResponseType status = GetUsageInfo(security_level, usage_info); CdmResponseType status = GetUsageInfo(app_id, security_level, usage_info);
if (KEY_MESSAGE == status && !usage_info->empty()) if (KEY_MESSAGE == status && !usage_info->empty())
return status; return status;
security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3; security_level = (kLevel3 == security_level) ? kLevelDefault : kLevel3;
status = GetUsageInfo(security_level, usage_info); status = GetUsageInfo(app_id, security_level, usage_info);
if (NEED_PROVISIONING == status) if (NEED_PROVISIONING == status)
return NO_ERROR; // Valid scenario that one of the security return NO_ERROR; // Valid scenario that one of the security
// levels has not been provisioned // levels has not been provisioned
return status; return status;
} }
CdmResponseType CdmEngine::GetUsageInfo( CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
SecurityLevel requested_security_level, SecurityLevel requested_security_level,
CdmUsageInfo* usage_info) { CdmUsageInfo* usage_info) {
if (NULL == usage_property_set_.get()) { if (NULL == usage_property_set_.get()) {
usage_property_set_.reset(new UsagePropertySet()); usage_property_set_.reset(new UsagePropertySet());
} }
usage_property_set_->set_security_level(requested_security_level); usage_property_set_->set_security_level(requested_security_level);
usage_property_set_->set_app_id(app_id);
usage_session_.reset(new CdmSession(usage_property_set_.get())); usage_session_.reset(new CdmSession(usage_property_set_.get()));
@@ -617,11 +687,11 @@ CdmResponseType CdmEngine::GetUsageInfo(
DeviceFiles handle; DeviceFiles handle;
if (!handle.Init(usage_session_->GetSecurityLevel())) { if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: unable to initialize device files"); LOGE("CdmEngine::GetUsageInfo: unable to initialize device files");
return status; return UNKNOWN_ERROR;
} }
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info; std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
if (!handle.RetrieveUsageInfo(&license_info)) { if (!handle.RetrieveUsageInfo(app_id, &license_info)) {
LOGE("CdmEngine::GetUsageInfo: unable to read usage information"); LOGE("CdmEngine::GetUsageInfo: unable to read usage information");
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
@@ -655,6 +725,23 @@ CdmResponseType CdmEngine::GetUsageInfo(
return KEY_MESSAGE; return KEY_MESSAGE;
} }
CdmResponseType CdmEngine::ReleaseAllUsageInfo(const std::string& app_id) {
CdmResponseType status = NO_ERROR;
DeviceFiles handle[kSecurityLevelUnknown - kSecurityLevelL1];
for (int i = 0, j = kSecurityLevelL1; j < kSecurityLevelUnknown; ++i, ++j) {
if (handle[i].Init(static_cast<CdmSecurityLevel>(j))) {
if (!handle[i].DeleteAllUsageInfoForApp(app_id)) {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to delete L%d secure stops", j);
status = UNKNOWN_ERROR;
}
} else {
LOGE("CdmEngine::ReleaseAllUsageInfo: failed to initialize L%d device files", j);
status = UNKNOWN_ERROR;
}
}
return status;
}
CdmResponseType CdmEngine::ReleaseUsageInfo( CdmResponseType CdmEngine::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message) { const CdmUsageInfoReleaseMessage& message) {
if (NULL == usage_session_.get()) { if (NULL == usage_session_.get()) {

View File

@@ -81,6 +81,7 @@ void CdmSession::Create(
} }
security_level_ = GetRequestedSecurityLevel() == kLevel3 security_level_ = GetRequestedSecurityLevel() == kLevel3
? kSecurityLevelL3 : GetSecurityLevel(); ? kSecurityLevelL3 : GetSecurityLevel();
app_id_.clear();
} }
CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); } CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); }
@@ -503,8 +504,10 @@ CdmResponseType CdmSession::StoreLicense() {
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
std::string app_id;
GetApplicationId(&app_id);
if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_, if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_,
key_response_)) { key_response_, app_id)) {
LOGE("CdmSession::StoreLicense: Unable to store usage info"); LOGE("CdmSession::StoreLicense: Unable to store usage info");
return UNKNOWN_ERROR; return UNKNOWN_ERROR;
} }
@@ -532,11 +535,14 @@ bool CdmSession::DeleteLicense() {
return false; return false;
} }
if (is_offline_) if (is_offline_) {
return file_handle_->DeleteLicense(key_set_id_); return file_handle_->DeleteLicense(key_set_id_);
else } else {
std::string app_id;
GetApplicationId(&app_id);
return file_handle_->DeleteUsageInfo( return file_handle_->DeleteUsageInfo(
license_parser_->provider_session_token()); app_id, license_parser_->provider_session_token());
}
} }
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) { bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
@@ -579,6 +585,12 @@ void CdmSession::OnKeyReleaseEvent(const CdmKeySetId& key_set_id) {
} }
} }
void CdmSession::GetApplicationId(std::string* app_id) {
if (app_id && !Properties::GetApplicationId(session_id_, app_id)) {
*app_id = "";
}
}
SecurityLevel CdmSession::GetRequestedSecurityLevel() { SecurityLevel CdmSession::GetRequestedSecurityLevel() {
std::string security_level; std::string security_level;
if (Properties::GetSecurityLevel(session_id_, &security_level) && if (Properties::GetSecurityLevel(session_id_, &security_level) &&
@@ -596,6 +608,20 @@ CdmSecurityLevel CdmSession::GetSecurityLevel() {
return crypto_session_.get()->GetSecurityLevel(); return crypto_session_.get()->GetSecurityLevel();
} }
CdmResponseType CdmSession::DeleteUsageInformation(const std::string& app_id) {
if (!file_handle_->Reset(security_level_)) {
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
return UNKNOWN_ERROR;
}
if (file_handle_->DeleteAllUsageInfoForApp(app_id)) {
return NO_ERROR;
} else {
LOGE("CdmSession::DeleteUsageInformation: failed");
return UNKNOWN_ERROR;
}
}
CdmResponseType CdmSession::UpdateUsageInformation() { CdmResponseType CdmSession::UpdateUsageInformation() {
return crypto_session_->UpdateUsageInformation(); return crypto_session_->UpdateUsageInformation();
} }

View File

@@ -8,6 +8,7 @@
# define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH # define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
#else #else
# include <openssl/sha.h> # include <openssl/sha.h>
#include <openssl/md5.h>
#endif #endif
#include <cstring> #include <cstring>
@@ -31,7 +32,8 @@ using video_widevine_client::sdk::UsageInfo_ProviderSession;
namespace { namespace {
const char kCertificateFileName[] = "cert.bin"; const char kCertificateFileName[] = "cert.bin";
const char kUsageInfoFileName[] = "usage.bin"; const char kUsageInfoFileNamePrefix[] = "usage";
const char kUsageInfoFileNameExt[] = ".bin";
const char kLicenseFileNameExt[] = ".lic"; const char kLicenseFileNameExt[] = ".lic";
const char kWildcard[] = "*"; const char kWildcard[] = "*";
const char kDirectoryDelimiter = '/'; const char kDirectoryDelimiter = '/';
@@ -329,7 +331,8 @@ bool DeviceFiles::LicenseExists(const std::string& key_set_id) {
bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token, bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
const CdmKeyMessage& key_request, const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response) { const CdmKeyResponse& key_response,
const std::string& app_id) {
if (!initialized_) { if (!initialized_) {
LOGW("DeviceFiles::StoreUsageInfo: not initialized"); LOGW("DeviceFiles::StoreUsageInfo: not initialized");
return false; return false;
@@ -337,7 +340,8 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
std::string serialized_file; std::string serialized_file;
video_widevine_client::sdk::File file; video_widevine_client::sdk::File file;
if (!RetrieveFile(kUsageInfoFileName, &serialized_file)) { std::string file_name = GetUsageInfoFileName(app_id);
if (!RetrieveFile(file_name.c_str(), &serialized_file)) {
file.set_type(video_widevine_client::sdk::File::USAGE_INFO); file.set_type(video_widevine_client::sdk::File::USAGE_INFO);
file.set_version(video_widevine_client::sdk::File::VERSION_1); file.set_version(video_widevine_client::sdk::File::VERSION_1);
} else { } else {
@@ -358,17 +362,19 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
key_response.size()); key_response.size());
file.SerializeToString(&serialized_file); file.SerializeToString(&serialized_file);
return StoreFile(kUsageInfoFileName, serialized_file); return StoreFile(file_name.c_str(), serialized_file);
} }
bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) { bool DeviceFiles::DeleteUsageInfo(const std::string& app_id,
const std::string& provider_session_token) {
if (!initialized_) { if (!initialized_) {
LOGW("DeviceFiles::DeleteUsageInfo: not initialized"); LOGW("DeviceFiles::DeleteUsageInfo: not initialized");
return false; return false;
} }
std::string serialized_file; std::string serialized_file;
if (!RetrieveFile(kUsageInfoFileName, &serialized_file)) return false; std::string file_name = GetUsageInfoFileName(app_id);
if (!RetrieveFile(file_name.c_str(), &serialized_file)) return false;
video_widevine_client::sdk::File file; video_widevine_client::sdk::File file;
if (!file.ParseFromString(serialized_file)) { if (!file.ParseFromString(serialized_file)) {
@@ -400,27 +406,29 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
sessions->RemoveLast(); sessions->RemoveLast();
file.SerializeToString(&serialized_file); file.SerializeToString(&serialized_file);
return StoreFile(kUsageInfoFileName, serialized_file); return StoreFile(file_name.c_str(), serialized_file);
} }
bool DeviceFiles::DeleteUsageInfo() { bool DeviceFiles::DeleteAllUsageInfoForApp(const std::string& app_id) {
if (!initialized_) { if (!initialized_) {
LOGW("DeviceFiles::DeleteUsageInfo: not initialized"); LOGW("DeviceFiles::DeleteAllUsageInfoForApp: not initialized");
return false; return false;
} }
std::string path; std::string path;
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
LOGW("DeviceFiles::DeleteUsageInfo: Unable to get base path"); LOGW("DeviceFiles::DeleteAllUsageInfoForApp: Unable to get base path");
return false; return false;
} }
path.append(kUsageInfoFileName); std::string file_name = GetUsageInfoFileName(app_id);
path.append(file_name);
return file_->Remove(path); return file_->Remove(path);
} }
bool DeviceFiles::RetrieveUsageInfo(std::vector< bool DeviceFiles::RetrieveUsageInfo(
std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info) { const std::string &app_id,
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info) {
if (!initialized_) { if (!initialized_) {
LOGW("DeviceFiles::RetrieveUsageInfo: not initialized"); LOGW("DeviceFiles::RetrieveUsageInfo: not initialized");
return false; return false;
@@ -433,13 +441,14 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
} }
std::string serialized_file; std::string serialized_file;
if (!RetrieveFile(kUsageInfoFileName, &serialized_file)) { std::string file_name = GetUsageInfoFileName(app_id);
if (!RetrieveFile(file_name.c_str(), &serialized_file)) {
std::string path; std::string path;
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) { if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
return false; return false;
} }
path += kUsageInfoFileName; path += file_name;
if (!file_->Exists(path) || 0 == file_->FileSize(path)) { if (!file_->Exists(path) || 0 == file_->FileSize(path)) {
usage_info->resize(0); usage_info->resize(0);
@@ -465,6 +474,42 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
return true; return true;
} }
bool DeviceFiles::RetrieveUsageInfo(const std::string& app_id,
const std::string& provider_session_token,
CdmKeyMessage* license_request,
CdmKeyResponse* license_response) {
if (!initialized_) {
LOGW("DeviceFiles::RetrieveUsageInfo: not initialized");
return false;
}
std::string serialized_file;
std::string file_name = GetUsageInfoFileName(app_id);
if (!RetrieveFile(file_name.c_str(), &serialized_file)) return false;
video_widevine_client::sdk::File file;
if (!file.ParseFromString(serialized_file)) {
LOGW("DeviceFiles::RetrieveUsageInfo: Unable to parse file");
return false;
}
int index = 0;
bool found = false;
for (; index < file.usage_info().sessions_size(); ++index) {
if (file.usage_info().sessions(index).token().compare(
provider_session_token) == 0) {
found = true;
break;
}
}
if (!found) {
return false;
}
*license_request = file.usage_info().sessions(index).license_request();
*license_response = file.usage_info().sessions(index).license();
return true;
}
bool DeviceFiles::StoreFile(const char* name, bool DeviceFiles::StoreFile(const char* name,
const std::string& serialized_file) { const std::string& serialized_file) {
if (!file_.get()) { if (!file_.get()) {
@@ -671,8 +716,15 @@ std::string DeviceFiles::GetLicenseFileNameExtension() {
return kLicenseFileNameExt; return kLicenseFileNameExt;
} }
std::string DeviceFiles::GetUsageInfoFileName() { std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) {
return kUsageInfoFileName; if (app_id == "") return std::string(kUsageInfoFileNamePrefix)
+ std::string(kUsageInfoFileNameExt);
std::vector<uint8_t> hash(MD5_DIGEST_LENGTH);
const unsigned char* input =
reinterpret_cast<const unsigned char*>(app_id.data());
MD5(input, app_id.size(), &hash[0]);
return std::string(kUsageInfoFileNamePrefix) + wvcdm::Base64SafeEncode(hash) +
std::string(kUsageInfoFileNameExt);
} }
void DeviceFiles::SetTestFile(File* file) { void DeviceFiles::SetTestFile(File* file) {

View File

@@ -60,6 +60,17 @@ const CdmClientPropertySet* Properties::GetCdmClientPropertySet(
return NULL; return NULL;
} }
bool Properties::GetApplicationId(const CdmSessionId& session_id,
std::string* app_id) {
const CdmClientPropertySet* property_set =
GetCdmClientPropertySet(session_id);
if (NULL == property_set) {
return false;
}
*app_id = property_set->app_id();
return true;
}
bool Properties::GetSecurityLevel(const CdmSessionId& session_id, bool Properties::GetSecurityLevel(const CdmSessionId& session_id,
std::string* security_level) { std::string* security_level) {
const CdmClientPropertySet* property_set = const CdmClientPropertySet* property_set =

View File

@@ -1747,7 +1747,8 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
TEST_P(DeviceFilesUsageInfoTest, Read) { TEST_P(DeviceFilesUsageInfoTest, Read) {
MockFile file; MockFile file;
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(); std::string app_id; // TODO(fredgc): expand tests.
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id);
int index = GetParam(); int index = GetParam();
std::string data; std::string data;
@@ -1777,7 +1778,7 @@ TEST_P(DeviceFilesUsageInfoTest, Read) {
device_files.SetTestFile(&file); device_files.SetTestFile(&file);
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info; std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
ASSERT_TRUE(device_files.RetrieveUsageInfo(&license_info)); ASSERT_TRUE(device_files.RetrieveUsageInfo(app_id, &license_info));
if (index >= 0) { if (index >= 0) {
EXPECT_EQ(index, license_info.size()); EXPECT_EQ(index, license_info.size());
for (size_t i = 0; i < license_info.size(); ++i) { for (size_t i = 0; i < license_info.size(); ++i) {
@@ -1799,10 +1800,11 @@ TEST_P(DeviceFilesUsageInfoTest, Read) {
TEST_P(DeviceFilesUsageInfoTest, Store) { TEST_P(DeviceFilesUsageInfoTest, Store) {
MockFile file; MockFile file;
std::string app_id; // TODO(fredgc): expand tests.
std::string pst(GenerateRandomData(kProviderSessionTokenLen)); std::string pst(GenerateRandomData(kProviderSessionTokenLen));
std::string license_request(GenerateRandomData(kLicenseRequestLen)); std::string license_request(GenerateRandomData(kLicenseRequestLen));
std::string license(GenerateRandomData(kLicenseLen)); std::string license(GenerateRandomData(kLicenseLen));
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(); std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id);
int index = GetParam(); int index = GetParam();
std::string data; std::string data;
@@ -1836,12 +1838,13 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
EXPECT_TRUE(device_files.Init(kSecurityLevelL1)); EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
device_files.SetTestFile(&file); device_files.SetTestFile(&file);
ASSERT_TRUE(device_files.StoreUsageInfo(pst, license_request, license)); ASSERT_TRUE(device_files.StoreUsageInfo(pst, license_request, license, app_id));
} }
TEST_P(DeviceFilesUsageInfoTest, Delete) { TEST_P(DeviceFilesUsageInfoTest, Delete) {
MockFile file; MockFile file;
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(); std::string app_id; // TODO(fredgc): expand tests.
std::string path = device_base_path_ + DeviceFiles::GetUsageInfoFileName(app_id);
int index = GetParam(); int index = GetParam();
if (index < 0) return; if (index < 0) return;
@@ -1886,9 +1889,9 @@ TEST_P(DeviceFilesUsageInfoTest, Delete) {
device_files.SetTestFile(&file); device_files.SetTestFile(&file);
if (index >= 1) { if (index >= 1) {
ASSERT_TRUE(device_files.DeleteUsageInfo(pst)); ASSERT_TRUE(device_files.DeleteUsageInfo(app_id, pst));
} else { } else {
ASSERT_FALSE(device_files.DeleteUsageInfo(pst)); ASSERT_FALSE(device_files.DeleteUsageInfo(app_id, pst));
} }
} }

View File

@@ -85,7 +85,12 @@ class WvContentDecryptionModule : public TimerHandler {
virtual CdmResponseType Unprovision(CdmSecurityLevel level); virtual CdmResponseType Unprovision(CdmSecurityLevel level);
// Secure stop related methods // Secure stop related methods
virtual CdmResponseType GetUsageInfo(CdmUsageInfo* usage_info); virtual CdmResponseType GetUsageInfo(const std::string& app_id,
CdmUsageInfo* usage_info);
virtual CdmResponseType GetUsageInfo(const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info);
virtual CdmResponseType ReleaseAllUsageInfo(const std::string& app_id);
virtual CdmResponseType ReleaseUsageInfo( virtual CdmResponseType ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message); const CdmUsageInfoReleaseMessage& message);

View File

@@ -159,8 +159,20 @@ CdmResponseType WvContentDecryptionModule::Unprovision(
} }
CdmResponseType WvContentDecryptionModule::GetUsageInfo( CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, CdmUsageInfo* usage_info) {
return cdm_engine_->GetUsageInfo(app_id, usage_info);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id,
const CdmSecureStopId& ssid,
CdmUsageInfo* usage_info) { CdmUsageInfo* usage_info) {
return cdm_engine_->GetUsageInfo(usage_info); return cdm_engine_->GetUsageInfo(app_id, ssid, usage_info);
}
CdmResponseType WvContentDecryptionModule::ReleaseAllUsageInfo(
const std::string& app_id) {
return cdm_engine_->ReleaseAllUsageInfo(app_id);
} }
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo( CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(

View File

@@ -1022,7 +1022,8 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
uint32_t num_usage_info = 0; uint32_t num_usage_info = 0;
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = decryptor_.GetUsageInfo(&usage_info); std::string app_id;
CdmResponseType status = decryptor_.GetUsageInfo(app_id, &usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status); EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
while (usage_info.size() > 0) { while (usage_info.size() > 0) {
for (size_t i = 0; i < usage_info.size(); ++i) { for (size_t i = 0; i < usage_info.size(); ++i) {
@@ -1034,7 +1035,7 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]); GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]);
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg)); EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
} }
status = decryptor_.GetUsageInfo(&usage_info); status = decryptor_.GetUsageInfo(app_id, &usage_info);
switch (status) { switch (status) {
case KEY_MESSAGE: case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty()); EXPECT_FALSE(usage_info.empty());

View File

@@ -393,6 +393,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
session_sharing_id_(0) {} session_sharing_id_(0) {}
virtual ~TestWvCdmClientPropertySet() {} virtual ~TestWvCdmClientPropertySet() {}
virtual const std::string& app_id() const { return app_id_; }
virtual const std::string& security_level() const { return security_level_; } virtual const std::string& security_level() const { return security_level_; }
virtual const std::string& service_certificate() const { virtual const std::string& service_certificate() const {
return service_certificate_; return service_certificate_;
@@ -403,6 +404,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
} }
virtual uint32_t session_sharing_id() const { return session_sharing_id_; } virtual uint32_t session_sharing_id() const { return session_sharing_id_; }
void set_app_id(const std::string& app_id) { app_id_ = app_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) ||
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3)) { !security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3)) {
@@ -421,6 +423,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; } void set_session_sharing_id(uint32_t id) { session_sharing_id_ = id; }
private: private:
std::string app_id_;
std::string security_level_; std::string security_level_;
std::string service_certificate_; std::string service_certificate_;
bool use_privacy_mode_; bool use_privacy_mode_;
@@ -830,6 +833,14 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
EXPECT_TRUE(security_level.empty() || EXPECT_TRUE(security_level.empty() ||
!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3)); !security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L3));
std::string app_id = "not empty";
EXPECT_TRUE(Properties::GetApplicationId(session_id_Ln, &app_id));
EXPECT_STREQ("", app_id.c_str());
property_set_Ln.set_app_id("com.unittest.mock.app.id");
EXPECT_TRUE(Properties::GetApplicationId(session_id_Ln, &app_id));
EXPECT_STREQ("com.unittest.mock.app.id", app_id.c_str());
decryptor_.CloseSession(session_id_L1); decryptor_.CloseSession(session_id_L1);
decryptor_.CloseSession(session_id_L3); decryptor_.CloseSession(session_id_L3);
decryptor_.CloseSession(session_id_Ln); decryptor_.CloseSession(session_id_Ln);
@@ -1202,7 +1213,7 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
EXPECT_TRUE(handle.Init(security_level)); EXPECT_TRUE(handle.Init(security_level));
File file; File file;
handle.SetTestFile(&file); handle.SetTestFile(&file);
EXPECT_TRUE(handle.DeleteUsageInfo()); EXPECT_TRUE(handle.DeleteAllUsageInfoForApp("")); // default app_id.
for (size_t i = 0; i < usage_info_data->usage_info; ++i) { for (size_t i = 0; i < usage_info_data->usage_info; ++i) {
SubSampleInfo* data = usage_info_data->sub_sample + i; SubSampleInfo* data = usage_info_data->sub_sample + i;
@@ -1236,7 +1247,8 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
uint32_t num_usage_info = 0; uint32_t num_usage_info = 0;
CdmUsageInfo usage_info; CdmUsageInfo usage_info;
CdmUsageInfoReleaseMessage release_msg; CdmUsageInfoReleaseMessage release_msg;
CdmResponseType status = decryptor_.GetUsageInfo(&usage_info); CdmResponseType status =
decryptor_.GetUsageInfo(property_set->app_id(), &usage_info);
EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status); EXPECT_EQ(usage_info.empty() ? NO_ERROR : KEY_MESSAGE, status);
while (usage_info.size() > 0) { while (usage_info.size() > 0) {
for (size_t i = 0; i < usage_info.size(); ++i) { for (size_t i = 0; i < usage_info.size(); ++i) {
@@ -1244,7 +1256,7 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]); GetUsageInfoResponse(g_license_server, g_client_auth, usage_info[i]);
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg)); EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
} }
status = decryptor_.GetUsageInfo(&usage_info); status = decryptor_.GetUsageInfo(property_set->app_id(), &usage_info);
switch (status) { switch (status) {
case KEY_MESSAGE: EXPECT_FALSE(usage_info.empty()); break; case KEY_MESSAGE: EXPECT_FALSE(usage_info.empty()); break;
case NO_ERROR: EXPECT_TRUE(usage_info.empty()); break; case NO_ERROR: EXPECT_TRUE(usage_info.empty()); break;

View File

@@ -85,8 +85,13 @@ class WVDrmPlugin : public android::DrmPlugin,
virtual status_t unprovisionDevice(); virtual status_t unprovisionDevice();
virtual status_t getSecureStop(const Vector<uint8_t>& ssid,
Vector<uint8_t>& secureStop);
virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops); virtual status_t getSecureStops(List<Vector<uint8_t> >& secureStops);
virtual status_t releaseAllSecureStops();
virtual status_t releaseSecureStops(const Vector<uint8_t>& ssRelease); virtual status_t releaseSecureStops(const Vector<uint8_t>& ssRelease);
virtual status_t getPropertyString(const String8& name, String8& value) const; virtual status_t getPropertyString(const String8& name, String8& value) const;
@@ -219,6 +224,14 @@ class WVDrmPlugin : public android::DrmPlugin,
mSessionSharingId = id; mSessionSharingId = id;
} }
virtual const std::string& app_id() const {
return mAppId;
}
void set_app_id(const std::string& appId) {
mAppId = appId;
}
private: private:
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet); DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
@@ -227,6 +240,7 @@ class WVDrmPlugin : public android::DrmPlugin,
std::string mServiceCertificate; std::string mServiceCertificate;
bool mShareKeys; bool mShareKeys;
uint32_t mSessionSharingId; uint32_t mSessionSharingId;
std::string mAppId;
} mPropertySet; } mPropertySet;
WvContentDecryptionModule* mCDM; WvContentDecryptionModule* mCDM;

View File

@@ -23,7 +23,6 @@ namespace {
static const char* const kResetSecurityLevel = ""; static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable"; static const char* const kEnable = "enable";
static const char* const kDisable = "disable"; static const char* const kDisable = "disable";
static const std::string kPsshTag = "pssh"; static const std::string kPsshTag = "pssh";
} }
@@ -394,9 +393,30 @@ status_t WVDrmPlugin::unprovisionDevice() {
} }
} }
status_t WVDrmPlugin::getSecureStop(const Vector<uint8_t>& ssid,
Vector<uint8_t>& secureStop) {
CdmUsageInfo cdmUsageInfo;
CdmSecureStopId cdmSsid(ssid.begin(), ssid.end());
CdmResponseType res = mCDM->GetUsageInfo(
mPropertySet.app_id(), cdmSsid, &cdmUsageInfo);
if (isCdmResponseTypeSuccess(res)) {
secureStop.clear();
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin();
iter != cdmUsageInfo.end();
++iter) {
const string& cdmStop = *iter;
secureStop.appendArray(reinterpret_cast<const uint8_t*>(cdmStop.data()),
cdmStop.size());
}
}
return mapCdmResponseType(res);
}
status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) { status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
CdmUsageInfo cdmUsageInfo; CdmUsageInfo cdmUsageInfo;
CdmResponseType res = mCDM->GetUsageInfo(&cdmUsageInfo); CdmResponseType res =
mCDM->GetUsageInfo(mPropertySet.app_id(), &cdmUsageInfo);
if (isCdmResponseTypeSuccess(res)) { if (isCdmResponseTypeSuccess(res)) {
secureStops.clear(); secureStops.clear();
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin(); for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin();
@@ -414,6 +434,11 @@ status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
return mapCdmResponseType(res); return mapCdmResponseType(res);
} }
status_t WVDrmPlugin::releaseAllSecureStops() {
CdmResponseType res = mCDM->ReleaseAllUsageInfo(mPropertySet.app_id());
return mapCdmResponseType(res);
}
status_t WVDrmPlugin::releaseSecureStops(const Vector<uint8_t>& ssRelease) { status_t WVDrmPlugin::releaseSecureStops(const Vector<uint8_t>& ssRelease) {
CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end()); CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end());
CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage); CdmResponseType res = mCDM->ReleaseUsageInfo(cdmMessage);
@@ -628,6 +653,18 @@ status_t WVDrmPlugin::setPropertyString(const String8& name,
ALOGE("App tried to change key sharing while sessions are open."); ALOGE("App tried to change key sharing while sessions are open.");
return kErrorSessionIsOpen; return kErrorSessionIsOpen;
} }
} else if (name == "appId") {
size_t sessionCount = 0;
{
Mutex::Autolock lock(mCryptoSessionsMutex);
sessionCount = mCryptoSessions.size();
}
if (sessionCount == 0) {
mPropertySet.set_app_id(value.string());
} else {
ALOGE("App tried to set the application id while sessions are opened.");
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;

View File

@@ -12,6 +12,7 @@ LOCAL_C_INCLUDES := \
frameworks/native/include \ frameworks/native/include \
vendor/widevine/libwvdrmengine/cdm/core/include \ vendor/widevine/libwvdrmengine/cdm/core/include \
vendor/widevine/libwvdrmengine/cdm/include \ vendor/widevine/libwvdrmengine/cdm/include \
vendor/widevine/libwvdrmengine/include \
vendor/widevine/libwvdrmengine/mediadrm/include \ vendor/widevine/libwvdrmengine/mediadrm/include \
vendor/widevine/libwvdrmengine/oemcrypto/include \ vendor/widevine/libwvdrmengine/oemcrypto/include \
vendor/widevine/libwvdrmengine/test/gmock/include \ vendor/widevine/libwvdrmengine/test/gmock/include \

View File

@@ -16,6 +16,7 @@
#include "wv_cdm_types.h" #include "wv_cdm_types.h"
#include "wv_content_decryption_module.h" #include "wv_content_decryption_module.h"
#include "WVDrmPlugin.h" #include "WVDrmPlugin.h"
#include "WVErrors.h"
using namespace android; using namespace android;
using namespace std; using namespace std;
@@ -65,10 +66,17 @@ class MockCDM : public WvContentDecryptionModule {
MOCK_METHOD3(HandleProvisioningResponse, MOCK_METHOD3(HandleProvisioningResponse,
CdmResponseType(CdmProvisioningResponse&, std::string*, std::string*)); CdmResponseType(CdmProvisioningResponse&, std::string*, std::string*));
MOCK_METHOD1(GetUsageInfo, CdmResponseType(CdmUsageInfo*)); MOCK_METHOD2(GetUsageInfo, CdmResponseType(const std::string&,
CdmUsageInfo*));
MOCK_METHOD3(GetUsageInfo, CdmResponseType(const std::string&,
const CdmSecureStopId&,
CdmUsageInfo*));
MOCK_METHOD1(Unprovision, CdmResponseType(CdmSecurityLevel)); MOCK_METHOD1(Unprovision, CdmResponseType(CdmSecurityLevel));
MOCK_METHOD1(ReleaseAllUsageInfo, CdmResponseType(const std::string&));
MOCK_METHOD1(ReleaseUsageInfo, MOCK_METHOD1(ReleaseUsageInfo,
CdmResponseType(const CdmUsageInfoReleaseMessage&)); CdmResponseType(const CdmUsageInfoReleaseMessage&));
@@ -599,6 +607,8 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
StrictMock<MockCDM> cdm; StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto; StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto); WVDrmPlugin plugin(&cdm, &crypto);
const char* app_id = "my_app_id";
plugin.setPropertyString(String8("appId"), String8(app_id));
static const uint32_t kStopSize = 53; static const uint32_t kStopSize = 53;
static const uint32_t kStopCount = 7; static const uint32_t kStopCount = 7;
@@ -614,8 +624,8 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize)); cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize));
} }
EXPECT_CALL(cdm, GetUsageInfo(_)) EXPECT_CALL(cdm, GetUsageInfo(StrEq(app_id), _))
.WillOnce(DoAll(SetArgPointee<0>(cdmStops), .WillOnce(DoAll(SetArgPointee<1>(cdmStops),
Return(wvcdm::NO_ERROR))); Return(wvcdm::NO_ERROR)));
List<Vector<uint8_t> > stops; List<Vector<uint8_t> > stops;
@@ -637,6 +647,21 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
EXPECT_EQ(stops.end(), iter); EXPECT_EQ(stops.end(), iter);
} }
TEST_F(WVDrmPluginTest, ReleasesAllSecureStops) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
WVDrmPlugin plugin(&cdm, &crypto);
status_t res = plugin.setPropertyString(String8("appId"), String8(""));
ASSERT_EQ(OK, res);
EXPECT_CALL(cdm, ReleaseAllUsageInfo(StrEq("")))
.Times(1);
res = plugin.releaseAllSecureStops();
ASSERT_EQ(OK, res);
}
TEST_F(WVDrmPluginTest, ReleasesSecureStops) { TEST_F(WVDrmPluginTest, ReleasesSecureStops) {
StrictMock<MockCDM> cdm; StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto; StrictMock<MockCrypto> crypto;
@@ -1309,6 +1334,59 @@ TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
EXPECT_EQ(0u, propertySet->service_certificate().size()); EXPECT_EQ(0u, propertySet->service_certificate().size());
EXPECT_FALSE(propertySet->is_session_sharing_enabled()); EXPECT_FALSE(propertySet->is_session_sharing_enabled());
EXPECT_EQ(0u, propertySet->session_sharing_id()); EXPECT_EQ(0u, propertySet->session_sharing_id());
EXPECT_STREQ("", propertySet->app_id().c_str());
}
TEST_F(WVDrmPluginTest, CanSetAppId) {
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 setting an empty string
res = plugin.setPropertyString(String8("appId"), String8(""));
ASSERT_EQ(OK, res);
// Test setting an application id before a session is opened.
const String8 kAppId("com.unittest.mock.app.id");
res = plugin.setPropertyString(String8("appId"), kAppId);
ASSERT_EQ(OK, res);
plugin.openSession(sessionId);
ASSERT_THAT(propertySet, NotNull());
// Verify application id is set correctly.
EXPECT_STREQ(kAppId, propertySet->app_id().c_str());
// Test setting application id while session is opened, this should fail.
res = plugin.setPropertyString(String8("appId"), kAppId);
ASSERT_EQ(kErrorSessionIsOpen, res);
} }
TEST_F(WVDrmPluginTest, CanSetSecurityLevel) { TEST_F(WVDrmPluginTest, CanSetSecurityLevel) {