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:
Fred Gylys-Colwell
2014-11-06 02:48:14 +00:00
committed by Android Git Automerger
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 uint32_t session_sharing_id() const = 0;
virtual void set_session_sharing_id(uint32_t id) = 0;
virtual const std::string& app_id() const = 0;
};
} // namespace wvcdm

View File

@@ -93,7 +93,16 @@ class CdmEngine {
virtual CdmResponseType Unprovision(CdmSecurityLevel security_level);
// 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(
const CdmUsageInfoReleaseMessage& message);
@@ -120,7 +129,8 @@ class CdmEngine {
private:
// private methods
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);
void OnKeyReleaseEvent(const CdmKeySetId& key_set_id);

View File

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

View File

@@ -62,11 +62,22 @@ class DeviceFiles {
virtual bool StoreUsageInfo(const std::string& provider_session_token,
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response);
virtual bool DeleteUsageInfo(const std::string& provider_session_token);
virtual bool DeleteUsageInfo();
const CdmKeyResponse& key_response,
const std::string& app_id);
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(
const std::string& app_id,
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:
bool StoreFile(const char* name, const std::string& serialized_file);
@@ -80,7 +91,7 @@ class DeviceFiles {
// For testing only:
static std::string GetCertificateFileName();
static std::string GetLicenseFileNameExtension();
static std::string GetUsageInfoFileName();
static std::string GetUsageInfoFileName(const std::string& app_id);
void SetTestFile(File* file);
#if defined(UNIT_TEST)
FRIEND_TEST(DeviceFilesSecurityLevelTest, SecurityLevel);

View File

@@ -53,6 +53,8 @@ class Properties {
static bool GetFactoryKeyboxPath(std::string* keybox);
static bool GetOEMCryptoPath(std::string* library_name);
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,
std::string* security_level);
static bool GetServiceCertificate(const CdmSessionId& session_id,

View File

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

View File

@@ -43,7 +43,11 @@ class UsagePropertySet : public CdmClientPropertySet {
virtual void set_session_sharing_id(uint32_t id) {
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:
std::string app_id_;
std::string security_level_;
const std::string empty_;
};
@@ -582,29 +586,95 @@ CdmResponseType CdmEngine::Unprovision(CdmSecurityLevel security_level) {
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
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())
return status;
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)
return NO_ERROR; // Valid scenario that one of the security
// levels has not been provisioned
return status;
}
CdmResponseType CdmEngine::GetUsageInfo(
SecurityLevel requested_security_level,
CdmUsageInfo* usage_info) {
CdmResponseType CdmEngine::GetUsageInfo(const std::string& app_id,
SecurityLevel requested_security_level,
CdmUsageInfo* usage_info) {
if (NULL == usage_property_set_.get()) {
usage_property_set_.reset(new UsagePropertySet());
}
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()));
@@ -617,11 +687,11 @@ CdmResponseType CdmEngine::GetUsageInfo(
DeviceFiles handle;
if (!handle.Init(usage_session_->GetSecurityLevel())) {
LOGE("CdmEngine::GetUsageInfo: unable to initialize device files");
return status;
return UNKNOWN_ERROR;
}
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");
return UNKNOWN_ERROR;
}
@@ -655,6 +725,23 @@ CdmResponseType CdmEngine::GetUsageInfo(
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(
const CdmUsageInfoReleaseMessage& message) {
if (NULL == usage_session_.get()) {

View File

@@ -81,6 +81,7 @@ void CdmSession::Create(
}
security_level_ = GetRequestedSecurityLevel() == kLevel3
? kSecurityLevelL3 : GetSecurityLevel();
app_id_.clear();
}
CdmSession::~CdmSession() { Properties::RemoveSessionPropertySet(session_id_); }
@@ -503,8 +504,10 @@ CdmResponseType CdmSession::StoreLicense() {
return UNKNOWN_ERROR;
}
std::string app_id;
GetApplicationId(&app_id);
if (!file_handle_->StoreUsageInfo(provider_session_token, key_request_,
key_response_)) {
key_response_, app_id)) {
LOGE("CdmSession::StoreLicense: Unable to store usage info");
return UNKNOWN_ERROR;
}
@@ -532,11 +535,14 @@ bool CdmSession::DeleteLicense() {
return false;
}
if (is_offline_)
if (is_offline_) {
return file_handle_->DeleteLicense(key_set_id_);
else
} else {
std::string app_id;
GetApplicationId(&app_id);
return file_handle_->DeleteUsageInfo(
license_parser_->provider_session_token());
app_id, license_parser_->provider_session_token());
}
}
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() {
std::string security_level;
if (Properties::GetSecurityLevel(session_id_, &security_level) &&
@@ -596,6 +608,20 @@ CdmSecurityLevel CdmSession::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() {
return crypto_session_->UpdateUsageInformation();
}

View File

@@ -8,6 +8,7 @@
# define SHA256_DIGEST_LENGTH CC_SHA256_DIGEST_LENGTH
#else
# include <openssl/sha.h>
#include <openssl/md5.h>
#endif
#include <cstring>
@@ -31,7 +32,8 @@ using video_widevine_client::sdk::UsageInfo_ProviderSession;
namespace {
const char kCertificateFileName[] = "cert.bin";
const char kUsageInfoFileName[] = "usage.bin";
const char kUsageInfoFileNamePrefix[] = "usage";
const char kUsageInfoFileNameExt[] = ".bin";
const char kLicenseFileNameExt[] = ".lic";
const char kWildcard[] = "*";
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,
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response) {
const CdmKeyResponse& key_response,
const std::string& app_id) {
if (!initialized_) {
LOGW("DeviceFiles::StoreUsageInfo: not initialized");
return false;
@@ -337,7 +340,8 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
std::string serialized_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_version(video_widevine_client::sdk::File::VERSION_1);
} else {
@@ -358,17 +362,19 @@ bool DeviceFiles::StoreUsageInfo(const std::string& provider_session_token,
key_response.size());
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_) {
LOGW("DeviceFiles::DeleteUsageInfo: not initialized");
return false;
}
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;
if (!file.ParseFromString(serialized_file)) {
@@ -400,27 +406,29 @@ bool DeviceFiles::DeleteUsageInfo(const std::string& provider_session_token) {
sessions->RemoveLast();
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_) {
LOGW("DeviceFiles::DeleteUsageInfo: not initialized");
LOGW("DeviceFiles::DeleteAllUsageInfoForApp: not initialized");
return false;
}
std::string 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;
}
path.append(kUsageInfoFileName);
std::string file_name = GetUsageInfoFileName(app_id);
path.append(file_name);
return file_->Remove(path);
}
bool DeviceFiles::RetrieveUsageInfo(std::vector<
std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info) {
bool DeviceFiles::RetrieveUsageInfo(
const std::string &app_id,
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> >* usage_info) {
if (!initialized_) {
LOGW("DeviceFiles::RetrieveUsageInfo: not initialized");
return false;
@@ -433,13 +441,14 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
}
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;
if (!Properties::GetDeviceFilesBasePath(security_level_, &path)) {
return false;
}
path += kUsageInfoFileName;
path += file_name;
if (!file_->Exists(path) || 0 == file_->FileSize(path)) {
usage_info->resize(0);
@@ -465,6 +474,42 @@ bool DeviceFiles::RetrieveUsageInfo(std::vector<
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,
const std::string& serialized_file) {
if (!file_.get()) {
@@ -671,8 +716,15 @@ std::string DeviceFiles::GetLicenseFileNameExtension() {
return kLicenseFileNameExt;
}
std::string DeviceFiles::GetUsageInfoFileName() {
return kUsageInfoFileName;
std::string DeviceFiles::GetUsageInfoFileName(const std::string& app_id) {
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) {

View File

@@ -60,6 +60,17 @@ const CdmClientPropertySet* Properties::GetCdmClientPropertySet(
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,
std::string* security_level) {
const CdmClientPropertySet* property_set =

View File

@@ -1747,7 +1747,8 @@ TEST_F(DeviceFilesTest, DeleteLicense) {
TEST_P(DeviceFilesUsageInfoTest, Read) {
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();
std::string data;
@@ -1777,7 +1778,7 @@ TEST_P(DeviceFilesUsageInfoTest, Read) {
device_files.SetTestFile(&file);
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) {
EXPECT_EQ(index, license_info.size());
for (size_t i = 0; i < license_info.size(); ++i) {
@@ -1799,10 +1800,11 @@ TEST_P(DeviceFilesUsageInfoTest, Read) {
TEST_P(DeviceFilesUsageInfoTest, Store) {
MockFile file;
std::string app_id; // TODO(fredgc): expand tests.
std::string pst(GenerateRandomData(kProviderSessionTokenLen));
std::string license_request(GenerateRandomData(kLicenseRequestLen));
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();
std::string data;
@@ -1836,12 +1838,13 @@ TEST_P(DeviceFilesUsageInfoTest, Store) {
EXPECT_TRUE(device_files.Init(kSecurityLevelL1));
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) {
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();
if (index < 0) return;
@@ -1886,9 +1889,9 @@ TEST_P(DeviceFilesUsageInfoTest, Delete) {
device_files.SetTestFile(&file);
if (index >= 1) {
ASSERT_TRUE(device_files.DeleteUsageInfo(pst));
ASSERT_TRUE(device_files.DeleteUsageInfo(app_id, pst));
} 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);
// 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(
const CdmUsageInfoReleaseMessage& message);

View File

@@ -159,8 +159,20 @@ CdmResponseType WvContentDecryptionModule::Unprovision(
}
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) {
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(

View File

@@ -1022,7 +1022,8 @@ TEST_P(WvCdmStreamingUsageReportTest, UsageTest) {
uint32_t num_usage_info = 0;
CdmUsageInfo usage_info;
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);
while (usage_info.size() > 0) {
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]);
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
}
status = decryptor_.GetUsageInfo(&usage_info);
status = decryptor_.GetUsageInfo(app_id, &usage_info);
switch (status) {
case KEY_MESSAGE:
EXPECT_FALSE(usage_info.empty());

View File

@@ -393,6 +393,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
session_sharing_id_(0) {}
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& service_certificate() const {
return service_certificate_;
@@ -403,6 +404,7 @@ class TestWvCdmClientPropertySet : public CdmClientPropertySet {
}
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) {
if (!security_level.compare(QUERY_VALUE_SECURITY_LEVEL_L1) ||
!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; }
private:
std::string app_id_;
std::string security_level_;
std::string service_certificate_;
bool use_privacy_mode_;
@@ -830,6 +833,14 @@ TEST_F(WvCdmRequestLicenseTest, PropertySetTest) {
EXPECT_TRUE(security_level.empty() ||
!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_L3);
decryptor_.CloseSession(session_id_Ln);
@@ -1202,7 +1213,7 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
EXPECT_TRUE(handle.Init(security_level));
File 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) {
SubSampleInfo* data = usage_info_data->sub_sample + i;
@@ -1236,7 +1247,8 @@ TEST_P(WvCdmUsageInfoTest, UsageInfo) {
uint32_t num_usage_info = 0;
CdmUsageInfo usage_info;
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);
while (usage_info.size() > 0) {
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]);
EXPECT_EQ(NO_ERROR, decryptor_.ReleaseUsageInfo(release_msg));
}
status = decryptor_.GetUsageInfo(&usage_info);
status = decryptor_.GetUsageInfo(property_set->app_id(), &usage_info);
switch (status) {
case KEY_MESSAGE: EXPECT_FALSE(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 getSecureStop(const Vector<uint8_t>& ssid,
Vector<uint8_t>& secureStop);
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 getPropertyString(const String8& name, String8& value) const;
@@ -219,6 +224,14 @@ class WVDrmPlugin : public android::DrmPlugin,
mSessionSharingId = id;
}
virtual const std::string& app_id() const {
return mAppId;
}
void set_app_id(const std::string& appId) {
mAppId = appId;
}
private:
DISALLOW_EVIL_CONSTRUCTORS(WVClientPropertySet);
@@ -227,6 +240,7 @@ class WVDrmPlugin : public android::DrmPlugin,
std::string mServiceCertificate;
bool mShareKeys;
uint32_t mSessionSharingId;
std::string mAppId;
} mPropertySet;
WvContentDecryptionModule* mCDM;

View File

@@ -23,7 +23,6 @@ namespace {
static const char* const kResetSecurityLevel = "";
static const char* const kEnable = "enable";
static const char* const kDisable = "disable";
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) {
CdmUsageInfo cdmUsageInfo;
CdmResponseType res = mCDM->GetUsageInfo(&cdmUsageInfo);
CdmResponseType res =
mCDM->GetUsageInfo(mPropertySet.app_id(), &cdmUsageInfo);
if (isCdmResponseTypeSuccess(res)) {
secureStops.clear();
for (CdmUsageInfo::const_iterator iter = cdmUsageInfo.begin();
@@ -414,6 +434,11 @@ status_t WVDrmPlugin::getSecureStops(List<Vector<uint8_t> >& secureStops) {
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) {
CdmUsageInfoReleaseMessage cdmMessage(ssRelease.begin(), ssRelease.end());
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.");
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 {
ALOGE("App set unknown string property %s", name.string());
return android::ERROR_DRM_CANNOT_HANDLE;

View File

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

View File

@@ -16,6 +16,7 @@
#include "wv_cdm_types.h"
#include "wv_content_decryption_module.h"
#include "WVDrmPlugin.h"
#include "WVErrors.h"
using namespace android;
using namespace std;
@@ -65,10 +66,17 @@ class MockCDM : public WvContentDecryptionModule {
MOCK_METHOD3(HandleProvisioningResponse,
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(ReleaseAllUsageInfo, CdmResponseType(const std::string&));
MOCK_METHOD1(ReleaseUsageInfo,
CdmResponseType(const CdmUsageInfoReleaseMessage&));
@@ -599,6 +607,8 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> 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 kStopCount = 7;
@@ -614,8 +624,8 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
cdmStops.push_back(string(stopsRaw[i], stopsRaw[i] + kStopSize));
}
EXPECT_CALL(cdm, GetUsageInfo(_))
.WillOnce(DoAll(SetArgPointee<0>(cdmStops),
EXPECT_CALL(cdm, GetUsageInfo(StrEq(app_id), _))
.WillOnce(DoAll(SetArgPointee<1>(cdmStops),
Return(wvcdm::NO_ERROR)));
List<Vector<uint8_t> > stops;
@@ -637,6 +647,21 @@ TEST_F(WVDrmPluginTest, GetsSecureStops) {
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) {
StrictMock<MockCDM> cdm;
StrictMock<MockCrypto> crypto;
@@ -1309,6 +1334,59 @@ TEST_F(WVDrmPluginTest, ProvidesExpectedDefaultPropertiesToCdm) {
EXPECT_EQ(0u, propertySet->service_certificate().size());
EXPECT_FALSE(propertySet->is_session_sharing_enabled());
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) {