Enable usage reporting

[ Merge from Widevine CDM repo of
  https://widevine-internal-review.googlesource.com/#/c/10171/ and
  https://widevine-internal-review.googlesource.com/#/c/10172/ ]

Updated license_protocol.proto from constituent protos in google3

These changes make use of OEMCrypto v9 changes to support usage reporting.
Usage reporting may be enabled for streaming (by means of secure stops) and
offline playback by a provider session token specified in the license.

Changes include periodically updating usage information for relevant
sessions and reporting and releasing usage information as needed.

The CDM has removed all references to Secure Stops. This change
updates the Android API implementation to comply.

b/11987015

Change-Id: Ibb6f2ced4ef20ee349ca1ae6412ce686b2b5d085
This commit is contained in:
Rahul Frias
2014-05-17 09:31:41 -07:00
parent d68e1f8307
commit e56e58fbf5
20 changed files with 1573 additions and 261 deletions

View File

@@ -31,7 +31,9 @@ CdmSession::CdmSession(const CdmClientPropertySet* cdm_client_property_set)
crypto_session_(NULL),
license_received_(false),
reinitialize_session_(false),
license_type_(kLicenseTypeStreaming),
is_offline_(false),
is_release_(false),
is_usage_update_needed_(false),
is_certificate_loaded_(false) {
if (cdm_client_property_set) {
Properties::AddSessionPropertySet(session_id_, cdm_client_property_set);
@@ -48,9 +50,8 @@ CdmResponseType CdmSession::Init() {
std::string token;
if (Properties::use_certificates_as_identification()) {
File file;
DeviceFiles handle;
if (!handle.Init(&file, session.get()->GetSecurityLevel()) ||
if (!handle.Init(session.get()->GetSecurityLevel()) ||
!handle.RetrieveCertificate(&token, &wrapped_key_)) {
return NEED_PROVISIONING;
}
@@ -72,15 +73,14 @@ CdmResponseType CdmSession::RestoreOfflineSession(
key_set_id_ = key_set_id;
// Retrieve license information from persistent store
File file;
DeviceFiles handle;
if (!handle.Init(&file, crypto_session_->GetSecurityLevel()))
if (!handle.Init(crypto_session_->GetSecurityLevel()))
return UNKNOWN_ERROR;
DeviceFiles::LicenseState license_state;
if (!handle.RetrieveLicense(key_set_id, &license_state, &offline_init_data_,
&offline_key_request_, &offline_key_response_,
&key_request_, &key_response_,
&offline_key_renewal_request_,
&offline_key_renewal_response_,
&offline_release_server_url_)) {
@@ -103,14 +103,39 @@ CdmResponseType CdmSession::RestoreOfflineSession(
}
}
if (!license_parser_.RestoreOfflineLicense(offline_key_request_,
offline_key_response_,
if (!license_parser_.RestoreOfflineLicense(key_request_, key_response_,
offline_key_renewal_response_)) {
return UNKNOWN_ERROR;
}
license_received_ = true;
license_type_ = license_type;
is_offline_ = true;
is_release_ = license_type == kLicenseTypeRelease;
return KEY_ADDED;
}
CdmResponseType CdmSession::RestoreUsageSession(
const CdmKeyMessage& key_request,
const CdmKeyResponse& key_response) {
key_request_ = key_request;
key_response_ = key_response;
if (Properties::use_certificates_as_identification()) {
if (is_certificate_loaded_ ||
crypto_session_->LoadCertificatePrivateKey(wrapped_key_)) {
is_certificate_loaded_ = true;
} else {
return NEED_PROVISIONING;
}
}
if (!license_parser_.RestoreUsageLicense(key_request_, key_response_)) {
return UNKNOWN_ERROR;
}
license_received_ = true;
is_offline_ = false;
is_release_ = true;
return KEY_ADDED;
}
@@ -143,9 +168,17 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return UNKNOWN_ERROR;
}
license_type_ = license_type;
switch (license_type) {
case kLicenseTypeStreaming: is_offline_ = false; break;
case kLicenseTypeOffline: is_offline_ = true; break;
case kLicenseTypeRelease: is_release_ = true; break;
default:
LOGE("CdmSession::GenerateKeyRequest: unrecognized license type: %ld",
license_type);
return UNKNOWN_ERROR;
}
if (license_type_ == kLicenseTypeRelease) {
if (is_release_) {
return GenerateReleaseRequest(key_request, server_url);
} else if (license_received_) { // renewal
return Properties::require_explicit_renew_request()
@@ -178,9 +211,9 @@ CdmResponseType CdmSession::GenerateKeyRequest(
return KEY_ERROR;
}
if (license_type_ == kLicenseTypeOffline) {
key_request_ = *key_request;
if (is_offline_) {
offline_init_data_ = init_data.data();
offline_key_request_ = *key_request;
offline_release_server_url_ = *server_url;
}
@@ -201,7 +234,7 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
return UNKNOWN_ERROR;
}
if (license_type_ == kLicenseTypeRelease) {
if (is_release_) {
return ReleaseKey(key_response);
} else if (license_received_) { // renewal
return Properties::require_explicit_renew_request()
@@ -213,25 +246,11 @@ CdmResponseType CdmSession::AddKey(const CdmKeyResponse& key_response,
if (sts != KEY_ADDED) return sts;
license_received_ = true;
key_response_ = key_response;
if (license_type_ == kLicenseTypeOffline) {
offline_key_response_ = key_response;
if (!GenerateKeySetId(&key_set_id_)) {
LOGE("CdmSession::AddKey: Unable to generate key set Id");
return UNKNOWN_ERROR;
}
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) {
LOGE("CdmSession::AddKey: Unable to store license");
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::AddKey: Reinitialization failed");
return sts;
}
key_set_id_.clear();
return UNKNOWN_ERROR;
}
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
sts = StoreLicense();
if (sts != NO_ERROR) return sts;
}
*key_set_id = key_set_id_;
@@ -314,6 +333,14 @@ CdmResponseType CdmSession::Decrypt(const CdmDecryptionParameters& params) {
return NEED_KEY;
}
}
if (NO_ERROR == status) {
if (!is_usage_update_needed_) {
is_usage_update_needed_ =
!license_parser_.provider_session_token().empty();
}
}
return status;
}
@@ -327,7 +354,7 @@ CdmResponseType CdmSession::GenerateRenewalRequest(CdmKeyMessage* key_request,
return KEY_ERROR;
}
if (license_type_ == kLicenseTypeOffline) {
if (is_offline_) {
offline_key_renewal_request_ = *key_request;
}
return KEY_MESSAGE;
@@ -339,7 +366,7 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
license_parser_.HandleKeyUpdateResponse(true, key_response);
if (sts != KEY_ADDED) return sts;
if (license_type_ == kLicenseTypeOffline) {
if (is_offline_) {
offline_key_renewal_response_ = key_response;
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) return UNKNOWN_ERROR;
}
@@ -348,23 +375,28 @@ CdmResponseType CdmSession::RenewKey(const CdmKeyResponse& key_response) {
CdmResponseType CdmSession::GenerateReleaseRequest(CdmKeyMessage* key_request,
std::string* server_url) {
if (license_parser_.PrepareKeyUpdateRequest(false, key_request, server_url)) {
// Mark license as being released
if (StoreLicense(DeviceFiles::kLicenseStateReleasing)) return KEY_MESSAGE;
is_release_ = true;
if (!license_parser_.PrepareKeyUpdateRequest(false, key_request, server_url))
return UNKNOWN_ERROR;
if (is_offline_) { // Mark license as being released
if (!StoreLicense(DeviceFiles::kLicenseStateReleasing))
return UNKNOWN_ERROR;
}
return UNKNOWN_ERROR;
return KEY_MESSAGE;
}
// ReleaseKey() - Accept release response and release license.
CdmResponseType CdmSession::ReleaseKey(const CdmKeyResponse& key_response) {
CdmResponseType sts =
license_parser_.HandleKeyUpdateResponse(false, key_response);
File file;
DeviceFiles handle;
if (handle.Init(&file, crypto_session_->GetSecurityLevel()))
handle.DeleteLicense(key_set_id_);
CdmResponseType sts = license_parser_.HandleKeyUpdateResponse(false,
key_response);
if (NO_ERROR != sts)
return sts;
return sts;
if (is_offline_ || !license_parser_.provider_session_token().empty()) {
DeleteLicense();
}
return NO_ERROR;
}
bool CdmSession::IsKeyLoaded(const KeyId& key_id) {
@@ -387,9 +419,8 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
std::vector<uint8_t> random_data(
(kKeySetIdLength - sizeof(KEY_SET_ID_PREFIX)) / 2, 0);
File file;
DeviceFiles handle;
if (!handle.Init(&file, crypto_session_->GetSecurityLevel()))
if (!handle.Init(crypto_session_->GetSecurityLevel()))
return false;
while (key_set_id->empty()) {
@@ -406,18 +437,75 @@ bool CdmSession::GenerateKeySetId(CdmKeySetId* key_set_id) {
return true;
}
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
File file;
CdmResponseType CdmSession::StoreLicense() {
if (is_offline_) {
if (!GenerateKeySetId(&key_set_id_)) {
LOGE("CdmSession::StoreLicense: Unable to generate key set Id");
return UNKNOWN_ERROR;
}
if (!StoreLicense(DeviceFiles::kLicenseStateActive)) {
LOGE("CdmSession::StoreLicense: Unable to store license");
CdmResponseType sts = Init();
if (sts != NO_ERROR) {
LOGW("CdmSession::StoreLicense: Reinitialization failed");
return sts;
}
key_set_id_.clear();
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
std::string provider_session_token = license_parser_.provider_session_token();
if (provider_session_token.empty()) {
LOGE("CdmSession::StoreLicense: No provider session token and not offline");
return UNKNOWN_ERROR;
}
DeviceFiles handle;
if (!handle.Init(&file, crypto_session_->GetSecurityLevel()))
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
LOGE("CdmSession::StoreLicense: Unable to initialize device files");
return UNKNOWN_ERROR;
}
if (!handle.StoreUsageInfo(provider_session_token, key_request_,
key_response_)) {
LOGE("CdmSession::StoreLicense: Unable to store usage info");
return UNKNOWN_ERROR;
}
return NO_ERROR;
}
bool CdmSession::StoreLicense(DeviceFiles::LicenseState state) {
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel()))
return false;
return handle.StoreLicense(
key_set_id_, state, offline_init_data_, offline_key_request_,
offline_key_response_, offline_key_renewal_request_,
key_set_id_, state, offline_init_data_, key_request_,
key_response_, offline_key_renewal_request_,
offline_key_renewal_response_, offline_release_server_url_);
}
bool CdmSession::DeleteLicense() {
if (!is_offline_ && license_parser_.provider_session_token().empty())
return false;
DeviceFiles handle;
if (!handle.Init(crypto_session_->GetSecurityLevel())) {
LOGE("CdmSession::DeleteLicense: Unable to initialize device files");
return false;
}
if (is_offline_)
return handle.DeleteLicense(key_set_id_);
else
return handle.DeleteUsageInfo(
license_parser_.provider_session_token());
}
bool CdmSession::AttachEventListener(WvCdmEventListener* listener) {
std::pair<CdmEventListenerIter, bool> result = listeners_.insert(listener);
return result.second;
@@ -459,4 +547,15 @@ SecurityLevel CdmSession::GetRequestedSecurityLevel() {
return kLevelDefault;
}
CdmSecurityLevel CdmSession::GetSecurityLevel() {
if (NULL == crypto_session_.get())
return kSecurityLevelUninitialized;
return crypto_session_.get()->GetSecurityLevel();
}
CdmResponseType CdmSession::UpdateUsageInformation() {
return crypto_session_->UpdateUsageInformation();
}
} // namespace wvcdm