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:
@@ -6,6 +6,8 @@
|
||||
#include <sstream>
|
||||
|
||||
#include "cdm_session.h"
|
||||
#include "clock.h"
|
||||
#include "device_files.h"
|
||||
#include "license_protocol.pb.h"
|
||||
#include "log.h"
|
||||
#include "properties.h"
|
||||
@@ -14,16 +16,26 @@
|
||||
#include "wv_cdm_constants.h"
|
||||
#include "wv_cdm_event_listener.h"
|
||||
|
||||
namespace {
|
||||
const uint32_t kUpdateUsageInformationPeriod = 60; // seconds
|
||||
const size_t kMinNoncesPerSession = 4;
|
||||
} // unnamed namespace
|
||||
|
||||
namespace wvcdm {
|
||||
|
||||
CdmEngine::CdmEngine()
|
||||
: cert_provisioning_requested_security_level_(kLevelDefault) {
|
||||
: cert_provisioning_requested_security_level_(kLevelDefault),
|
||||
usage_session_(NULL),
|
||||
last_usage_information_update_time(0) {
|
||||
Properties::Init();
|
||||
}
|
||||
|
||||
CdmEngine::~CdmEngine() {
|
||||
CancelSessions();
|
||||
|
||||
if (NULL != usage_session_)
|
||||
delete usage_session_;
|
||||
|
||||
CdmSessionMap::iterator i(sessions_.begin());
|
||||
for (; i != sessions_.end(); ++i)
|
||||
delete i->second;
|
||||
@@ -482,15 +494,73 @@ CdmResponseType CdmEngine::HandleProvisioningResponse(
|
||||
wrapped_key);
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::GetSecureStops(
|
||||
CdmSecureStops* secure_stops) {
|
||||
// TODO(edwinwong, rfrias): add implementation
|
||||
return NO_ERROR;
|
||||
CdmResponseType CdmEngine::GetUsageInfo(CdmUsageInfo* usage_info) {
|
||||
if (NULL == usage_session_) {
|
||||
usage_session_ = new CdmSession(NULL);
|
||||
}
|
||||
|
||||
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: unable to initialize device files");
|
||||
return status;
|
||||
}
|
||||
|
||||
std::vector<std::pair<CdmKeyMessage, CdmKeyResponse> > license_info;
|
||||
if (!handle.RetrieveUsageInfo(&license_info)) {
|
||||
LOGE("CdmEngine::GetUsageInfo: unable to read usage information");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
if (0 == license_info.size()) {
|
||||
usage_info->resize(0);
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
std::string server_url;
|
||||
// rate limit secure stop messages based on minimum nonce
|
||||
// table size per session
|
||||
usage_info->resize(license_info.size() >= kMinNoncesPerSession - 1
|
||||
? kMinNoncesPerSession - 1
|
||||
: license_info.size());
|
||||
for (size_t i = 0; i < usage_info->size(); ++i) {
|
||||
status = usage_session_->RestoreUsageSession(license_info[i].first,
|
||||
license_info[i].second);
|
||||
if (KEY_ADDED != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: restore usage session error: %ld",
|
||||
status);
|
||||
usage_info->clear();
|
||||
return status;
|
||||
}
|
||||
status = usage_session_->GenerateReleaseRequest(&(*usage_info)[i],
|
||||
&server_url);
|
||||
if (KEY_MESSAGE != status) {
|
||||
LOGE("CdmEngine::GetUsageInfo: generate release request error: %ld",
|
||||
status);
|
||||
usage_info->clear();
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return KEY_MESSAGE;
|
||||
}
|
||||
|
||||
CdmResponseType CdmEngine::ReleaseSecureStops(
|
||||
const CdmSecureStopReleaseMessage& message) {
|
||||
// TODO(edwinwong, rfrias): add implementation
|
||||
CdmResponseType CdmEngine::ReleaseUsageInfo(
|
||||
const CdmUsageInfoReleaseMessage& message) {
|
||||
if (NULL == usage_session_) {
|
||||
LOGE("CdmEngine::ReleaseUsageInfo: cdm session not initialized");
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
|
||||
CdmResponseType status = usage_session_->ReleaseKey(message);
|
||||
if (NO_ERROR != status) {
|
||||
LOGE("CdmEngine::ReleaseUsageInfo: release key error: %ld", status);
|
||||
return UNKNOWN_ERROR;
|
||||
}
|
||||
return NO_ERROR;
|
||||
}
|
||||
|
||||
@@ -615,9 +685,31 @@ bool CdmEngine::CancelSessions() {
|
||||
}
|
||||
|
||||
void CdmEngine::OnTimerEvent() {
|
||||
Clock clock;
|
||||
uint64_t current_time = clock.GetCurrentTime();
|
||||
bool update_usage_information = false;
|
||||
|
||||
if (current_time - last_usage_information_update_time >
|
||||
kUpdateUsageInformationPeriod) {
|
||||
update_usage_information = true;
|
||||
last_usage_information_update_time = current_time;
|
||||
}
|
||||
|
||||
for (CdmSessionMap::iterator iter = sessions_.begin();
|
||||
iter != sessions_.end(); ++iter) {
|
||||
iter != sessions_.end(); ++iter) {
|
||||
iter->second->OnTimerEvent();
|
||||
|
||||
if (update_usage_information && iter->second->is_usage_update_needed()) {
|
||||
// usage is updated for all sessions so this needs to be
|
||||
// called only once per update usage information period
|
||||
CdmResponseType status = iter->second->UpdateUsageInformation();
|
||||
if (NO_ERROR != status) {
|
||||
LOGW("Update usage information failed: %u", status);
|
||||
} else {
|
||||
update_usage_information = false;
|
||||
}
|
||||
}
|
||||
iter->second->reset_is_usage_update_needed();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user