am 20191d99: Allow Secure Stops to be queried and deleted by application ID
* commit '20191d996c1aace4544e0b59466e3a0321e6b980': Allow Secure Stops to be queried and deleted by application ID
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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_;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 =
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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());
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 \
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user