Introduce UsageTableHeader class

[ Merge of http://go/wvgerrit/23820 ]

The UsageTableHeader class is a singleton that CDM sessions will share.
A separate object will be created for each security level. The class
synchronizes access to usage table header and associated data-structures
and controls when they are read in or written out to non-secure persistent
storage. Upgrades from a fixed size usage table (supported by previous
versions of the OEMCrypto API v9-12) are handled by this class.

b/34327459

Test: Verified by unit/integration tests on angler

Change-Id: Ifc5996985e76bc260c01e55bc12aab1248389a80
This commit is contained in:
Rahul Frias
2017-02-08 14:56:16 -08:00
parent e75d3a6512
commit 0db3a137e9
9 changed files with 786 additions and 1 deletions

View File

@@ -35,6 +35,7 @@ LOCAL_SRC_FILES := \
$(CORE_SRC_DIR)/policy_engine.cpp \
$(CORE_SRC_DIR)/privacy_crypto_openssl.cpp \
$(CORE_SRC_DIR)/service_certificate.cpp \
$(CORE_SRC_DIR)/usage_table_header.cpp \
$(SRC_DIR)/ami_adapter.cpp \
$(SRC_DIR)/wv_content_decryption_module.cpp \
$(METRICS_SRC_DIR)/distribution.cpp \

View File

@@ -62,6 +62,10 @@ class CdmLicense {
return is_offline_;
}
static bool ExtractProviderSessionToken(
const CdmKeyResponse& license_response,
std::string* provider_session_token);
private:
CdmResponseType HandleKeyErrorResponse(

View File

@@ -0,0 +1,109 @@
// Copyright 2017 Google Inc. All Rights Reserved.
#ifndef WVCDM_CORE_USAGE_TABLE_HEADER_H_
#define WVCDM_CORE_USAGE_TABLE_HEADER_H_
#include <string>
#include <vector>
#include "device_files.h"
#include "lock.h"
#include "metrics_group.h"
#include "scoped_ptr.h"
#include "timer_metric.h"
#include "wv_cdm_types.h"
namespace wvcdm {
class FileSystem;
class CryptoSession;
// The UsageTableHeader class is a singleton that CDM sessions will share.
// A separate object will be created for each security level.
// The class synchronizes access to usage table header and associated
// data-structures and controls when they are read in or written out to
// non-secure persistent storage.
// Upgrades from a fixed size usage table (supported by previous
// versions of the OEMCrypto API v9-12) are handled by this class.
// |usage_entry| and |usage_entry_number|s need to be saved in the license
// and usage info records by the caller.
class UsageTableHeader {
public:
// This methods instantiates or retrieves a usage table header singleton of
// appropriate security level as specified by the |crypto_session|
// object.
// |crypto_session| is used to create or load a usage master table and
// not cached beyound this call.
static UsageTableHeader* GetInstance(FileSystem* file_system,
CryptoSession* crypto_session_);
virtual ~UsageTableHeader() {}
// |persistent_license| false indicates usage info record
CdmResponseType AddEntry(CryptoSession* crypto_session,
bool persistent_license,
const CdmKeySetId& key_set_id,
const std::string& usage_info_filename,
uint32_t* usage_entry_number);
CdmResponseType LoadEntry(CryptoSession* crypto_session,
const CdmUsageEntry& usage_entry,
uint32_t usage_entry_number);
CdmResponseType UpdateEntry(CryptoSession* crypto_session,
CdmUsageEntry* usage_entry);
// The licenses or usage info records specified by |usage_entry_number|
// should not be in use by any open CryptoSession objects when calls
// to DeleteEntry and MoveEntry are made.
CdmResponseType DeleteEntry(uint32_t usage_entry_number);
CdmResponseType MoveEntry(uint32_t from_usage_entry_number,
const CdmUsageEntry& from_usage_entry,
uint32_t to_usage_entry_number);
private:
UsageTableHeader(FileSystem* file_system, CryptoSession* crypto_session,
CdmSecurityLevel security_level);
CdmResponseType GetEntry(uint32_t usage_entry_number,
CdmUsageEntry* usage_entry);
CdmResponseType StoreEntry(uint32_t usage_entry_number,
const CdmUsageEntry& usage_entry);
bool DeleteLastEntry();
CdmResponseType UpgradeFromUsageTable();
bool UpgradeLicensesFromUsageTable();
bool UpgradeUsageInfoFromUsageTable();
virtual bool is_inited() { return is_inited_; }
SecurityLevel GetSecurityLevel() {
return security_level_ == kSecurityLevelL3 ? kLevel3 : kLevelDefault;
}
static UsageTableHeader* usage_table_header_l1_;
static UsageTableHeader* usage_table_header_l3_;
scoped_ptr<DeviceFiles> file_handle_;
CdmSecurityLevel security_level_;
CdmUsageTableHeader usage_table_header_;
std::vector<CdmUsageEntryInfo> usage_entry_info_;
metrics::MetricsGroup metrics_;
metrics::TimerMetric life_span_;
// Lock to ensure that a single object is created for each security level
// and data member to represent whether an object has been correctly
// initialized.
bool is_inited_;
static Lock initialization_lock_;
// Synchonizes access to the Usage Table Header and bookkeeping
// data-structures
Lock usage_table_header_lock_;
CORE_DISALLOW_COPY_AND_ASSIGN(UsageTableHeader);
};
} // namespace wvcdm
#endif // WVCDM_CORE_USAGE_TABLE_HEADER_H_

View File

@@ -279,6 +279,17 @@ enum CdmResponseType {
INVALID_PARAMETERS_ENG_23,
USAGE_INFORMATION_SUPPORT_FAILED,
USAGE_SUPPORT_GET_API_FAILED,
UNEXPECTED_EMPTY_USAGE_ENTRY, /* 240 */
INVALID_USAGE_ENTRY_NUMBER_MODIFICATION,
USAGE_INVALID_NEW_ENTRY,
USAGE_INVALID_PARAMETERS_1,
USAGE_RETRIEVE_LICENSE_FAILED,
USAGE_RETRIEVE_USAGE_INFO_FAILED, /* 245 */
USAGE_RETRIEVE_INVALID_STORAGE_TYPE,
USAGE_ENTRY_NUMBER_MISMATCH,
USAGE_STORE_LICENSE_FAILED,
USAGE_STORE_USAGE_INFO_FAILED,
USAGE_INVALID_LOAD_ENTRY, /* 250 */
};
enum CdmKeyStatus {

View File

@@ -793,6 +793,43 @@ bool CdmLicense::IsKeyLoaded(const KeyId& key_id) {
return loaded_keys_.find(key_id) != loaded_keys_.end();
}
bool CdmLicense::ExtractProviderSessionToken(
const CdmKeyResponse& license_response,
std::string* provider_session_token) {
if (license_response.empty()) {
LOGW("CdmLicense::ExtractProviderSessionToken: empty license response");
return false;
}
SignedMessage signed_response;
if (!signed_response.ParseFromString(license_response)) {
LOGW(
"CdmLicense::ExtractProviderSessionToken: unable to parse signed "
"license response");
return false;
}
if (signed_response.type() != SignedMessage::LICENSE) {
LOGW("CdmLicense::ExtractProviderSessionToken: unrecognized signed message "
"type: %d", signed_response.type());
return false;
}
License license;
if (!license.ParseFromString(signed_response.msg())) {
LOGE("CdmLicense::ExtractProviderSessionToken: unable to parse license "
"response");
return false;
}
if (license.id().has_provider_session_token()) {
*provider_session_token = license.id().provider_session_token();
return true;
}
return false;
}
CdmResponseType CdmLicense::HandleKeyErrorResponse(
const SignedMessage& signed_message) {
LicenseError license_error;

View File

@@ -0,0 +1,564 @@
// Copyright 2017 Google Inc. All Rights Reserved.
#include "usage_table_header.h"
#include "crypto_session.h"
#include "license.h"
#include "log.h"
namespace {
std::string kEmptyString;
}
namespace wvcdm {
UsageTableHeader* UsageTableHeader::usage_table_header_l1_ = NULL;
UsageTableHeader* UsageTableHeader::usage_table_header_l3_ = NULL;
Lock UsageTableHeader::initialization_lock_;
UsageTableHeader* UsageTableHeader::GetInstance(FileSystem* file_system,
CryptoSession* crypto_session) {
LOGV("UsageTableHeader::GetInstance");
AutoLock auto_lock(initialization_lock_);
CdmSecurityLevel security_level = crypto_session->GetSecurityLevel();
switch (security_level) {
case kSecurityLevelL1:
if (usage_table_header_l1_ != NULL)
return usage_table_header_l1_;
break;
case kSecurityLevelL3:
if (usage_table_header_l3_ != NULL)
return usage_table_header_l3_;
break;
default:
LOGE("UsageTableHeader::GetInstance: unsupported security level: %d",
security_level);
return NULL;
}
UsageTableHeader* header =
new UsageTableHeader(file_system, crypto_session, security_level);
if (!header->is_inited()) {
delete header;
return NULL;
}
if (security_level == kSecurityLevelL1)
usage_table_header_l1_ = header;
else
usage_table_header_l3_ = header;
return header;
}
UsageTableHeader::UsageTableHeader(FileSystem* file_system,
CryptoSession* crypto_session,
CdmSecurityLevel security_level)
: file_handle_(new DeviceFiles(file_system)),
security_level_(security_level),
is_inited_(false) {
LOGV("UsageTableHeader::UsageTablerHeader: security level: %d",
security_level);
if (!file_handle_->RetrieveUsageTableInfo(&usage_table_header_,
&usage_entry_info_)) {
CdmResponseType status =
crypto_session->CreateUsageTableHeader(&usage_table_header_);
if (status != NO_ERROR) return;
} else {
CdmResponseType status =
crypto_session->LoadUsageTableHeader(usage_table_header_);
if (status != NO_ERROR) {
LOGE(
"UsageTableHeader::UsageTablerHeader: load usage table failed, "
"security level: %d",
security_level);
return;
}
}
is_inited_ = true;
}
CdmResponseType UsageTableHeader::AddEntry(
CryptoSession* crypto_session, bool persistent_license,
const CdmKeySetId& key_set_id, const std::string& usage_info_file_name,
uint32_t* usage_entry_number) {
LOGV("UsageTableHeader::AddEntry");
AutoLock auto_lock(usage_table_header_lock_);
CdmResponseType status = crypto_session->CreateUsageEntry(usage_entry_number);
if (status != NO_ERROR) return status;
if (*usage_entry_number < usage_entry_info_.size()) {
LOGE("UsageTableHeader::AddEntry: new entry %d smaller than table size: %d",
*usage_entry_number, usage_entry_info_.size());
return USAGE_INVALID_NEW_ENTRY;
}
if (*usage_entry_number > usage_entry_info_.size()) {
LOGW("UsageTableHeader::AddEntry: new entry %d larger than table size: %d",
*usage_entry_number, usage_entry_info_.size());
size_t number_of_entries = usage_entry_info_.size();
usage_entry_info_.resize(*usage_entry_number + 1);
for (size_t i = number_of_entries; i < usage_entry_info_.size() - 1; ++i) {
usage_entry_info_[i].storage_type = kStorageUnknown;
usage_entry_info_[i].key_set_id.clear();
usage_entry_info_[i].usage_info_file_name.clear();
}
} else /* *usage_entry_number == usage_entry_info_.size() */ {
usage_entry_info_.resize(*usage_entry_number + 1);
}
usage_entry_info_[*usage_entry_number].storage_type =
persistent_license ? kStorageLicense : kStorageUsageInfo;
usage_entry_info_[*usage_entry_number].key_set_id = key_set_id;
if (!persistent_license)
usage_entry_info_[*usage_entry_number].usage_info_file_name =
usage_info_file_name;
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return NO_ERROR;
}
CdmResponseType UsageTableHeader::LoadEntry(
CryptoSession* crypto_session, const CdmUsageEntry& usage_entry,
uint32_t usage_entry_number) {
LOGV("UsageTableHeader::LoadEntry");
AutoLock auto_lock(usage_table_header_lock_);
if (usage_entry_number >= usage_entry_info_.size()) {
LOGE("UsageTableHeader::LoadEntry: usage entry number %d larger than table size: %d",
usage_entry_number, usage_entry_info_.size());
return USAGE_INVALID_LOAD_ENTRY;
}
return crypto_session->LoadUsageEntry(usage_entry_number, usage_entry);
}
CdmResponseType UsageTableHeader::UpdateEntry(CryptoSession* crypto_session,
CdmUsageEntry* usage_entry) {
LOGV("UsageTableHeader::UpdateEntry");
AutoLock auto_lock(usage_table_header_lock_);
CdmUsageTableHeader usage_table_header;
CdmResponseType status =
crypto_session->UpdateUsageEntry(&usage_table_header_, usage_entry);
if (status != NO_ERROR) return status;
file_handle_->StoreUsageTableInfo(usage_table_header, usage_entry_info_);
return NO_ERROR;
}
CdmResponseType UsageTableHeader::DeleteEntry(uint32_t usage_entry_number) {
LOGV("UsageTableHeader::DeleteEntry");
AutoLock auto_lock(usage_table_header_lock_);
if (usage_entry_number >= usage_entry_info_.size())
return USAGE_INVALID_PARAMETERS_1;
// Find the last valid entry number, in order to swap
size_t swap_entry_number = usage_entry_info_.size() - 1;
CdmUsageEntry swap_usage_entry;
bool swap_usage_entry_valid = false;
for (; !swap_usage_entry_valid && swap_entry_number > usage_entry_number;
--swap_entry_number) {
switch (usage_entry_info_[swap_entry_number].storage_type) {
case kStorageLicense:
case kStorageUsageInfo: {
CdmResponseType status = GetEntry(swap_entry_number, &swap_usage_entry);
if (status == NO_ERROR) swap_usage_entry_valid = true;
break;
}
case kStorageUnknown:
default:
break;
}
}
uint32_t new_usage_table_size = 0;
if (swap_usage_entry_valid) {
MoveEntry(swap_entry_number, swap_usage_entry, usage_entry_number);
new_usage_table_size = swap_entry_number;
} else {
// No valid usage entries before entry to be deleted
new_usage_table_size = usage_entry_number;
}
usage_entry_info_.resize(new_usage_table_size);
CryptoSession crypto_session(&metrics_);
crypto_session.Open(GetSecurityLevel());
crypto_session.ShrinkUsageTableHeader(new_usage_table_size,
&usage_table_header_);
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return NO_ERROR;
}
CdmResponseType UsageTableHeader::MoveEntry(
uint32_t from_usage_entry_number, const CdmUsageEntry& from_usage_entry,
uint32_t to_usage_entry_number) {
LOGV("UsageTableHeader::MoveEntry");
AutoLock auto_lock(usage_table_header_lock_);
CryptoSession crypto_session(&metrics_);
crypto_session.Open(GetSecurityLevel());
CdmResponseType status =
crypto_session.LoadUsageEntry(from_usage_entry_number, from_usage_entry);
if (status != NO_ERROR) {
LOGE("UsageTableHeader::MoveEntry: Failed to load usage entry: %d",
from_usage_entry_number);
return status;
}
status = crypto_session.MoveUsageEntry(to_usage_entry_number);
if (status != NO_ERROR) {
LOGE("UsageTableHeader::MoveEntry: Failed to move usage entry: %d->%d",
from_usage_entry_number, to_usage_entry_number);
return status;
}
usage_entry_info_[to_usage_entry_number] =
usage_entry_info_[from_usage_entry_number];
CdmUsageEntry usage_entry;
status = crypto_session.UpdateUsageEntry(&usage_table_header_, &usage_entry);
if (status != NO_ERROR) {
LOGE("UsageTableHeader::MoveEntry: Failed to update usage entry: %d",
to_usage_entry_number);
return status;
}
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
StoreEntry(to_usage_entry_number, usage_entry);
return NO_ERROR;
}
CdmResponseType UsageTableHeader::GetEntry(uint32_t usage_entry_number,
CdmUsageEntry* usage_entry) {
uint32_t entry_number;
switch (usage_entry_info_[usage_entry_number].storage_type) {
case kStorageLicense: {
DeviceFiles::LicenseState license_state;
std::string init_data, key_request, key_response, key_renewal_request;
std::string key_renewal_response, release_server_url;
int64_t playback_start_time, last_playback_time, grace_period_end_time;
CdmAppParameterMap app_parameters;
if (!file_handle_->RetrieveLicense(
usage_entry_info_[usage_entry_number].key_set_id, &license_state,
&init_data, &key_request, &key_response, &key_renewal_request,
&key_renewal_response, &release_server_url, &playback_start_time,
&last_playback_time, &grace_period_end_time, &app_parameters,
usage_entry, &entry_number)) {
LOGE("UsageTableHeader::GetEntry: Failed to retrieve license");
return USAGE_RETRIEVE_LICENSE_FAILED;
}
break;
}
case kStorageUsageInfo: {
std::string provider_session_token;
CdmKeyMessage license_request;
CdmKeyResponse license_response;
if (!file_handle_->RetrieveUsageInfoByKeySetId(
usage_entry_info_[usage_entry_number].usage_info_file_name,
usage_entry_info_[usage_entry_number].key_set_id,
&provider_session_token, &license_request, &license_response,
usage_entry, &entry_number)) {
LOGE(
"UsageTableHeader::GetEntry: Failed to retrieve usage information");
return USAGE_RETRIEVE_USAGE_INFO_FAILED;
}
break;
}
case kStorageUnknown:
default:
LOGE(
"UsageTableHeader::GetEntry: Attempting to retrieve usage "
"information from unknown storage type: %d",
usage_entry_info_[usage_entry_number].storage_type);
return USAGE_RETRIEVE_INVALID_STORAGE_TYPE;
}
if (usage_entry_number != entry_number) {
LOGE("UsageTableHeader::GetEntry: entry number mismatch: (%d, %d)",
usage_entry_number, entry_number);
return USAGE_ENTRY_NUMBER_MISMATCH;
}
return NO_ERROR;
}
CdmResponseType UsageTableHeader::StoreEntry(uint32_t usage_entry_number,
const CdmUsageEntry& usage_entry) {
uint32_t entry_number;
switch (usage_entry_info_[usage_entry_number].storage_type) {
case kStorageLicense: {
DeviceFiles::LicenseState license_state;
std::string init_data, key_request, key_response, key_renewal_request;
std::string key_renewal_response, release_server_url;
int64_t playback_start_time, last_playback_time, grace_period_end_time;
CdmAppParameterMap app_parameters;
CdmUsageEntry entry;
if (!file_handle_->RetrieveLicense(
usage_entry_info_[usage_entry_number].key_set_id, &license_state,
&init_data, &key_request, &key_response, &key_renewal_request,
&key_renewal_response, &release_server_url, &playback_start_time,
&last_playback_time, &grace_period_end_time, &app_parameters,
&entry, &entry_number)) {
LOGE("UsageTableHeader::StoreEntry: Failed to retrieve license");
return USAGE_RETRIEVE_LICENSE_FAILED;
}
if (!file_handle_->StoreLicense(
usage_entry_info_[usage_entry_number].key_set_id, license_state,
init_data, key_request, key_response, key_renewal_request,
key_renewal_response, release_server_url, playback_start_time,
last_playback_time, grace_period_end_time, app_parameters,
usage_entry, usage_entry_number)) {
LOGE("UsageTableHeader::StoreEntry: Failed to store license");
return USAGE_STORE_LICENSE_FAILED;
}
break;
}
case kStorageUsageInfo: {
CdmUsageEntry entry;
std::string provider_session_token, init_data, key_request, key_response,
key_renewal_request;
if (!file_handle_->RetrieveUsageInfoByKeySetId(
usage_entry_info_[usage_entry_number].usage_info_file_name,
usage_entry_info_[usage_entry_number].key_set_id,
&provider_session_token, &key_request, &key_response, &entry,
&entry_number)) {
LOGE(
"UsageTableHeader::StoreEntry: Failed to retrieve usage "
"information");
return USAGE_RETRIEVE_USAGE_INFO_FAILED;
}
file_handle_->DeleteUsageInfo(
usage_entry_info_[usage_entry_number].usage_info_file_name,
provider_session_token);
if (!file_handle_->StoreUsageInfo(
provider_session_token, key_request, key_response,
usage_entry_info_[usage_entry_number].usage_info_file_name,
usage_entry_info_[usage_entry_number].key_set_id, usage_entry,
usage_entry_number)) {
LOGE("UsageTableHeader::StoreEntry: Failed to store usage information");
return USAGE_STORE_USAGE_INFO_FAILED;
}
break;
}
case kStorageUnknown:
default:
LOGE(
"UsageTableHeader::GetUsageEntry: Attempting to retrieve usage "
"information from unknown storage type: %d",
usage_entry_info_[usage_entry_number].storage_type);
return USAGE_RETRIEVE_INVALID_STORAGE_TYPE;
}
return NO_ERROR;
}
bool UsageTableHeader::DeleteLastEntry() {
if (usage_entry_info_.empty()) {
LOGW(
"UsageTableHeader::DeleteLastEntry: usage entry info table "
"unexpectedly empty");
return false;
}
usage_entry_info_.resize(usage_entry_info_.size() - 1);
CryptoSession crypto_session(&metrics_);
crypto_session.Open(GetSecurityLevel());
crypto_session.ShrinkUsageTableHeader(usage_entry_info_.size(),
&usage_table_header_);
file_handle_->StoreUsageTableInfo(usage_table_header_, usage_entry_info_);
return true;
}
CdmResponseType UsageTableHeader::UpgradeFromUsageTable() {
CryptoSession crypto_session(&metrics_);
CdmResponseType status = crypto_session.Open(GetSecurityLevel());
if (status != NO_ERROR) return status;
status = crypto_session.CreateUsageTableHeader(&usage_table_header_);
if (status != NO_ERROR) return status;
crypto_session.Close();
UpgradeLicensesFromUsageTable();
UpgradeUsageInfoFromUsageTable();
return NO_ERROR;
}
bool UsageTableHeader::UpgradeLicensesFromUsageTable() {
// Fetch the key set IDs for each offline license. For each license
// * retrieve the provider session token,
// * create a new usage entry
// * copy over the entry from the usage table
// * update the usage header table and entry numbers
// * save the usage table header and store the usage entry number and
// usage entry along with the license to persistent memory
std::vector<std::string> key_set_ids;
if (file_handle_->ListLicenses(&key_set_ids)) {
LOGW(
"UpgradeUsageTableHeader::UpgradeLicensesFromUsageTable: unable to "
"retrieve list of licenses");
return false;
}
for (size_t i = 0; i < key_set_ids.size(); ++i) {
DeviceFiles::LicenseState license_state;
std::string init_data, key_request, key_response, key_renewal_request;
std::string key_renewal_response, release_server_url;
int64_t playback_start_time, last_playback_time, grace_period_end_time;
CdmAppParameterMap app_parameters;
CdmUsageEntry usage_entry;
uint32_t usage_entry_number;
if (!file_handle_->RetrieveLicense(
key_set_ids[i], &license_state, &init_data, &key_request,
&key_response, &key_renewal_request, &key_renewal_response,
&release_server_url, &playback_start_time, &last_playback_time,
&grace_period_end_time, &app_parameters, &usage_entry,
&usage_entry_number)) {
LOGW(
"UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to "
"retrieve license");
continue;
}
std::string provider_session_token;
if (!CdmLicense::ExtractProviderSessionToken(key_response,
&provider_session_token)) {
LOGW(
"UsageTableHeader::UpgradeLicensesFromUsageTable: Failed to "
"retrieve provider session token");
continue;
}
if (provider_session_token.empty()) continue;
CryptoSession crypto_session(&metrics_);
CdmResponseType status = crypto_session.Open(GetSecurityLevel());
if (status != NO_ERROR) continue;
status = AddEntry(&crypto_session, true /* persistent license */,
key_set_ids[i], kEmptyString, &usage_entry_number);
if (status != NO_ERROR) continue;
status = crypto_session.CopyOldUsageEntry(provider_session_token);
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
continue;
}
status = UpdateEntry(&crypto_session, &usage_entry);
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
continue;
}
if (!file_handle_->StoreLicense(
key_set_ids[i], license_state, init_data, key_request, key_response,
key_renewal_request, key_renewal_response, release_server_url,
playback_start_time, last_playback_time, grace_period_end_time,
app_parameters, usage_entry, usage_entry_number)) {
LOGE("UsageTableHeader::StoreEntry: Failed to store license");
continue;
}
}
return NO_ERROR;
}
bool UsageTableHeader::UpgradeUsageInfoFromUsageTable() {
// Fetch all usage files. For each file retrieve all the usage info records
// within the file. For each piece of usage information
// * create a new usage entry
// * copy over the entry from the usage table and
// * update the usage header table and entry numbers
// * save the usage table header
// * once done processing all the usage records from a file, save the usage
// information to persistent memory along with usage entry number and usage
// entry.
std::vector<std::string> usage_info_file_names;
if (file_handle_->ListUsageInfoFiles(&usage_info_file_names)) {
LOGW(
"UpgradeUsageTableHeader::UpgradeUsageInfoFromUsageTable: Unable to "
"retrieve list of usage info file names");
return false;
}
for (size_t i = 0; i < usage_info_file_names.size(); ++i) {
std::vector<DeviceFiles::CdmUsageData> usage_data;
if (!file_handle_->RetrieveUsageInfo(usage_info_file_names[i],
&usage_data)) {
LOGW(
"UsageTableHeader::UpgradeUsageInfoFromUsageTable: Failed to "
"retrieve usage records from %s",
usage_info_file_names[i].c_str());
continue;
}
for (size_t j = 0; j < usage_data.size(); --j) {
if (usage_data[j].provider_session_token.empty()) {
LOGW(
"UsageTableHeader::UpgradeUsageInfoFromUsageTable: Provider "
"session id empty");
continue;
}
CryptoSession crypto_session(&metrics_);
CdmResponseType status = crypto_session.Open(GetSecurityLevel());
if (status != NO_ERROR) continue;
// TODO(rfrias): We need to fill in the app id, but it is hashed
// and we have no way to extract. Use the hased filename instead?
status = AddEntry(&crypto_session, false /* usage info */,
usage_data[j].key_set_id, kEmptyString,
&(usage_data[i].usage_entry_number));
if (status != NO_ERROR) continue;
status = crypto_session.CopyOldUsageEntry(
usage_data[i].provider_session_token);
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
continue;
}
status = UpdateEntry(&crypto_session, &(usage_data[i].usage_entry));
if (status != NO_ERROR) {
crypto_session.Close();
DeleteLastEntry();
continue;
}
}
if (!file_handle_->StoreUsageInfo(usage_info_file_names[i], usage_data)) {
LOGE(
"UsageTableHeader::StoreUsageInfo: Failed to store usage records to "
"%s",
usage_info_file_names[i].c_str());
continue;
}
}
return NO_ERROR;
}
} // namespace wvcdm

View File

@@ -528,6 +528,32 @@ void PrintTo(const enum CdmResponseType& value, ::std::ostream* os) {
case USAGE_SUPPORT_GET_API_FAILED:
*os << "USAGE_SUPPORT_GET_API_FAILED";
break;
case UNEXPECTED_EMPTY_USAGE_ENTRY:
*os << "UNEXPECTED_EMPTY_USAGE_ENTRY";
break;
case INVALID_USAGE_ENTRY_NUMBER_MODIFICATION:
*os << "INVALID_USAGE_ENTRY_NUMBER_MODIFICATION";
break;
case USAGE_INVALID_NEW_ENTRY: *os << "USAGE_INVALID_NEW_ENTRY";
break;
case USAGE_INVALID_PARAMETERS_1: *os << "USAGE_INVALID_PARAMETERS_1";
break;
case USAGE_RETRIEVE_LICENSE_FAILED: *os << "USAGE_RETRIEVE_LICENSE_FAILED";
break;
case USAGE_RETRIEVE_USAGE_INFO_FAILED:
*os << "USAGE_RETRIEVE_USAGE_INFO_FAILED";
break;
case USAGE_RETRIEVE_INVALID_STORAGE_TYPE:
*os << "USAGE_RETRIEVE_INVALID_STORAGE_TYPE";
break;
case USAGE_ENTRY_NUMBER_MISMATCH: *os << "USAGE_ENTRY_NUMBER_MISMATCH";
break;
case USAGE_STORE_LICENSE_FAILED: *os << "USAGE_STORE_LICENSE_FAILED";
break;
case USAGE_STORE_USAGE_INFO_FAILED: *os << "USAGE_STORE_USAGE_INFO_FAILED";
break;
case USAGE_INVALID_LOAD_ENTRY: *os << "USAGE_INVALID_LOAD_ENTRY";
break;
default:
*os << "Unknown CdmResponseType";

View File

@@ -244,10 +244,21 @@ enum {
kInvalidParametersEng23 = ERROR_DRM_VENDOR_MIN + 230,
kUsageInformationSupportFailed = ERROR_DRM_VENDOR_MIN + 231,
kUsageSupportGetApiFailed = ERROR_DRM_VENDOR_MIN + 232,
kUnexpectedEmptyUsageEntry = ERROR_DRM_VENDOR_MIN + 233,
kInvalidUsageEntryNumberModification = ERROR_DRM_VENDOR_MIN + 234,
kUsageInvalidNewEntry = ERROR_DRM_VENDOR_MIN + 235,
kUsageInvalidParameters1 = ERROR_DRM_VENDOR_MIN + 236,
kUsageRetrieveLicenseFailed = ERROR_DRM_VENDOR_MIN + 237,
kUsageRetrieveUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 238,
kUsageRetrieveInvalidStorageType = ERROR_DRM_VENDOR_MIN + 239,
kUsageEntryNumberMismatch = ERROR_DRM_VENDOR_MIN + 240,
kUsageStoreLicenseFailed = ERROR_DRM_VENDOR_MIN + 241,
kUsageStoreUsageInfoFailed = ERROR_DRM_VENDOR_MIN + 242,
kUsageInvalidLoadEntry = ERROR_DRM_VENDOR_MIN + 243,
// This should always follow the last error code.
// The offset value should be updated each time a new error code is added.
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 232,
kErrorWVDrmMaxErrorUsed = ERROR_DRM_VENDOR_MIN + 243,
// Used by crypto test mode
kErrorTestMode = ERROR_DRM_VENDOR_MAX,

View File

@@ -479,6 +479,28 @@ static android::status_t mapCdmResponseType(wvcdm::CdmResponseType res) {
return kUsageInformationSupportFailed;
case wvcdm::USAGE_SUPPORT_GET_API_FAILED:
return kUsageSupportGetApiFailed;
case wvcdm::UNEXPECTED_EMPTY_USAGE_ENTRY:
return kUnexpectedEmptyUsageEntry;
case wvcdm::INVALID_USAGE_ENTRY_NUMBER_MODIFICATION:
return kInvalidUsageEntryNumberModification;
case wvcdm::USAGE_INVALID_NEW_ENTRY:
return kUsageInvalidNewEntry;
case wvcdm::USAGE_INVALID_PARAMETERS_1:
return kUsageInvalidParameters1;
case wvcdm::USAGE_RETRIEVE_LICENSE_FAILED:
return kUsageRetrieveLicenseFailed;
case wvcdm::USAGE_RETRIEVE_USAGE_INFO_FAILED:
return kUsageRetrieveUsageInfoFailed;
case wvcdm::USAGE_RETRIEVE_INVALID_STORAGE_TYPE:
return kUsageRetrieveInvalidStorageType;
case wvcdm::USAGE_ENTRY_NUMBER_MISMATCH:
return kUsageEntryNumberMismatch;
case wvcdm::USAGE_STORE_LICENSE_FAILED:
return kUsageStoreLicenseFailed;
case wvcdm::USAGE_STORE_USAGE_INFO_FAILED:
return kUsageStoreUsageInfoFailed;
case wvcdm::USAGE_INVALID_LOAD_ENTRY:
return kUsageInvalidLoadEntry;
case wvcdm::UNUSED_1:
case wvcdm::UNUSED_2: