Files
android/libwvdrmengine/cdm/src/wv_content_decryption_module.cpp
Fred Gylys-Colwell 938bc7bbad Use MediaDrm property to ignore installed keybox
Merge from Widevine repo of http://go/wvgerrit/135984

If the MediaDrm property string debugIgnoreKeyboxCount is set to 1,
then the keybox will be ignored on the next initialization. This will
force an OTA keybox reprovisioning.

Equivalently, a 1 may be written to the file
L1/debug_ignore_keybox_count.txt.

In order to test a failed reprovisioning step, a value of 2 may be
used.

Bug: 187646550
Change-Id: Ie7d34a8b355398855f4ec43dd95dd73c5907bdeb
2021-10-14 03:12:16 +00:00

649 lines
25 KiB
C++

// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary
// source code may only be used and distributed under the Widevine License
// Agreement.
#include "wv_content_decryption_module.h"
#include <algorithm>
#include <iterator>
#include "cdm_client_property_set.h"
#include "cdm_engine.h"
#include "cdm_engine_factory.h"
#include "initialization_data.h"
#include "license.h"
#include "log.h"
#include "properties.h"
#include "service_certificate.h"
#include "string_conversions.h"
#include "wv_cdm_constants.h"
#include "wv_cdm_event_listener.h"
#include "wv_metrics.pb.h"
namespace {
const int kCdmTimerDurationSeconds = 1;
}
namespace wvcdm {
std::mutex WvContentDecryptionModule::session_sharing_id_generation_lock_;
WvContentDecryptionModule::WvContentDecryptionModule() {}
WvContentDecryptionModule::~WvContentDecryptionModule() {
CryptoSession::DisableDelayedTermination();
CloseAllCdms();
CryptoSession::TryTerminate();
DisableTimerAndWaitForExit();
}
bool WvContentDecryptionModule::IsSupported(const std::string& init_data_type) {
return InitializationData(init_data_type).is_supported();
}
bool WvContentDecryptionModule::IsCenc(const std::string& init_data_type) {
return InitializationData(init_data_type).is_cenc();
}
bool WvContentDecryptionModule::IsWebm(const std::string& init_data_type) {
return InitializationData(init_data_type).is_webm();
}
bool WvContentDecryptionModule::IsHls(const std::string& init_data_type) {
return InitializationData(init_data_type).is_hls();
}
bool WvContentDecryptionModule::IsAudio(const std::string& init_data_type) {
return InitializationData(init_data_type).is_audio();
}
CdmResponseType WvContentDecryptionModule::OpenSession(
const CdmKeySystem& key_system, CdmClientPropertySet* property_set,
const CdmIdentifier& identifier, WvCdmEventListener* event_listener,
CdmSessionId* session_id) {
if (property_set && property_set->is_session_sharing_enabled()) {
std::unique_lock<std::mutex> auto_lock(session_sharing_id_generation_lock_);
if (property_set->session_sharing_id() == 0)
property_set->set_session_sharing_id(GenerateSessionSharingId());
}
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
CdmResponseType sts = cdm_engine->OpenSession(key_system, property_set,
event_listener, session_id);
if (sts == NO_ERROR) {
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
cdm_by_session_id_[*session_id] = cdm_engine;
}
return sts;
}
CdmResponseType WvContentDecryptionModule::CloseSession(
const CdmSessionId& session_id) {
LOGV("Closing session ID: %s", session_id.c_str());
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
// TODO(rfrias): Avoid reusing the error codes from CdmEngine.
if (!cdm_engine) return SESSION_NOT_FOUND_1;
const CdmResponseType sts = cdm_engine->CloseSession(session_id);
if (sts == NO_ERROR) {
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
cdm_by_session_id_.erase(session_id);
}
return sts;
}
bool WvContentDecryptionModule::IsOpenSession(const CdmSessionId& session_id) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
return cdm_engine && cdm_engine->IsOpenSession(session_id);
}
CdmResponseType WvContentDecryptionModule::GenerateKeyRequest(
const CdmSessionId& session_id, const CdmKeySetId& key_set_id,
const std::string& init_data_type, const CdmInitData& init_data,
const CdmLicenseType license_type, CdmAppParameterMap& app_parameters,
CdmClientPropertySet* property_set, const CdmIdentifier& identifier,
CdmKeyRequest* key_request) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
CdmResponseType sts;
if (license_type == kLicenseTypeRelease) {
sts = cdm_engine->OpenKeySetSession(key_set_id, property_set, nullptr);
if (sts != NO_ERROR) return sts;
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
cdm_by_session_id_[key_set_id] = cdm_engine;
}
const SecurityLevel requested_security_level =
property_set && property_set->security_level().compare(
wvcdm::QUERY_VALUE_SECURITY_LEVEL_L3) == 0
? wvcdm::kLevel3
: wvcdm::kLevelDefault;
std::string oec_version;
sts = cdm_engine->QueryStatus(requested_security_level,
QUERY_KEY_OEMCRYPTO_API_VERSION, &oec_version);
if (sts != NO_ERROR) {
return sts;
}
InitializationData initialization_data(init_data_type, init_data,
oec_version);
sts = cdm_engine->GenerateKeyRequest(session_id, key_set_id,
initialization_data, license_type,
app_parameters, key_request);
if (license_type == kLicenseTypeRelease && sts != KEY_MESSAGE) {
cdm_engine->CloseKeySetSession(key_set_id);
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
cdm_by_session_id_.erase(key_set_id);
}
return sts;
}
CdmResponseType WvContentDecryptionModule::AddKey(
const CdmSessionId& session_id, const CdmKeyResponse& key_data,
CdmKeySetId* key_set_id) {
CdmEngine* cdm_engine = session_id.empty() ? GetCdmForSessionId(*key_set_id)
: GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_3;
// Save key_set_id, as CDM will return an empty key_set_id on release
CdmKeySetId release_key_set_id;
if (session_id.empty() && key_set_id != nullptr) {
release_key_set_id = *key_set_id;
}
CdmResponseType sts;
CdmLicenseType license_type;
sts = cdm_engine->AddKey(session_id, key_data, &license_type, key_set_id);
// Empty session id indicates license type release.
if (sts == KEY_ADDED && session_id.empty()) {
cdm_engine->CloseKeySetSession(release_key_set_id);
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
cdm_by_session_id_.erase(release_key_set_id);
}
return sts;
}
CdmResponseType WvContentDecryptionModule::RestoreKey(
const CdmSessionId& session_id, const CdmKeySetId& key_set_id) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_4;
CdmResponseType sts;
sts = cdm_engine->RestoreKey(session_id, key_set_id);
return sts;
}
CdmResponseType WvContentDecryptionModule::RemoveKeys(
const CdmSessionId& session_id) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_5;
CdmResponseType sts = cdm_engine->RemoveKeys(session_id);
return sts;
}
CdmResponseType WvContentDecryptionModule::QueryStatus(
SecurityLevel security_level, const std::string& key, std::string* value) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(kDefaultCdmIdentifier);
return cdm_engine->QueryStatus(security_level, key, value);
}
CdmResponseType WvContentDecryptionModule::QuerySessionStatus(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_8;
return cdm_engine->QuerySessionStatus(session_id, key_info);
}
CdmResponseType WvContentDecryptionModule::QueryKeyStatus(
const CdmSessionId& session_id, CdmQueryMap* key_info) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_9;
CdmResponseType sts;
sts = cdm_engine->QueryKeyStatus(session_id, key_info);
return sts;
}
CdmResponseType WvContentDecryptionModule::QueryOemCryptoSessionId(
const CdmSessionId& session_id, CdmQueryMap* response) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_10;
return cdm_engine->QueryOemCryptoSessionId(session_id, response);
}
bool WvContentDecryptionModule::IsSecurityLevelSupported(
CdmSecurityLevel level) {
return CdmEngine::IsSecurityLevelSupported(level);
}
CdmResponseType WvContentDecryptionModule::GetProvisioningRequest(
CdmCertificateType cert_type, const std::string& cert_authority,
const CdmIdentifier& identifier, const std::string& service_certificate,
SecurityLevel requested_security_level, CdmProvisioningRequest* request,
std::string* default_url) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->GetProvisioningRequest(
cert_type, cert_authority, service_certificate, requested_security_level,
request, default_url);
}
CdmResponseType WvContentDecryptionModule::HandleProvisioningResponse(
const CdmIdentifier& identifier, CdmProvisioningResponse& response,
SecurityLevel requested_security_level, std::string* cert,
std::string* wrapped_key) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->HandleProvisioningResponse(
response, requested_security_level, cert, wrapped_key);
}
CdmResponseType WvContentDecryptionModule::Unprovision(
CdmSecurityLevel level, const CdmIdentifier& identifier) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
// Persistent state is deleted on unprovisioning. The L3 OEMCrypto device
// key may however remain in memory until |OEMCrypto_Terminate| is called.
// It is not regenerated until |OEMCrypto_Initialize| is called.
// Enable immediate OEMCrypto termination and re-initalization on
// unprovisioning.
CryptoSession::DisableDelayedTermination();
return cdm_engine->Unprovision(level);
}
bool WvContentDecryptionModule::IsProvisioned(CdmSecurityLevel security_level,
const std::string& origin,
const std::string& spoid,
bool atsc_mode_enabled) {
FileSystem file_system;
file_system.set_origin(origin);
file_system.set_identifier(spoid + origin);
DeviceFiles device_files(&file_system);
device_files.Init(security_level);
return device_files.HasCertificate(atsc_mode_enabled);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, const CdmIdentifier& identifier,
CdmUsageInfo* usage_info) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
int error_detail = NO_ERROR;
return cdm_engine->GetUsageInfo(app_id, &error_detail, usage_info);
}
CdmResponseType WvContentDecryptionModule::GetUsageInfo(
const std::string& app_id, const CdmSecureStopId& ssid,
const CdmIdentifier& identifier, CdmUsageInfo* usage_info) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
int error_detail = NO_ERROR;
return cdm_engine->GetUsageInfo(app_id, ssid, &error_detail, usage_info);
}
CdmResponseType WvContentDecryptionModule::RemoveAllUsageInfo(
const std::string& app_id, const CdmIdentifier& identifier) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->RemoveAllUsageInfo(app_id);
}
CdmResponseType WvContentDecryptionModule::RemoveUsageInfo(
const std::string& app_id, const CdmIdentifier& identifier,
const CdmSecureStopId& secure_stop_id) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->RemoveUsageInfo(app_id, secure_stop_id);
}
CdmResponseType WvContentDecryptionModule::ReleaseUsageInfo(
const CdmUsageInfoReleaseMessage& message,
const CdmIdentifier& identifier) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->ReleaseUsageInfo(message);
}
CdmResponseType WvContentDecryptionModule::GetSecureStopIds(
const std::string& app_id, const CdmIdentifier& identifier,
std::vector<CdmSecureStopId>* ssids) {
if (ssids == nullptr) {
LOGE("Secure stop IDs destination not provided");
return PARAMETER_NULL;
}
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
const CdmResponseType sts =
cdm_engine->ListUsageIds(app_id, kSecurityLevelL1, nullptr, ssids);
std::vector<CdmSecureStopId> secure_stop_ids;
const CdmResponseType sts_l3 = cdm_engine->ListUsageIds(
app_id, kSecurityLevelL3, nullptr, &secure_stop_ids);
ssids->insert(ssids->end(), secure_stop_ids.begin(), secure_stop_ids.end());
return sts_l3 != NO_ERROR ? sts_l3 : sts;
}
CdmResponseType WvContentDecryptionModule::Decrypt(
const CdmSessionId& session_id, bool validate_key_id,
const CdmDecryptionParameters& parameters) {
return DecryptV16(session_id, validate_key_id,
CdmDecryptionParametersV16::from_v15(parameters));
}
CdmResponseType WvContentDecryptionModule::DecryptV16(
const CdmSessionId& session_id, bool validate_key_id,
const CdmDecryptionParametersV16& parameters) {
// First find the CdmEngine that has the given session_id. If we are using
// key sharing, the shared session will still be in the same CdmEngine.
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) {
LOGE("Decrypt session ID not found: %s", session_id.c_str());
return SESSION_NOT_FOUND_18;
}
CdmSessionId local_session_id = session_id;
if (validate_key_id && Properties::GetSessionSharingId(session_id) != 0) {
bool status =
cdm_engine->FindSessionForKey(parameters.key_id, &local_session_id);
if (!status) {
bool is_any_protected = std::any_of(
std::begin(parameters.samples), std::end(parameters.samples),
[](const CdmDecryptionSample& sample) -> bool {
return std::any_of(
std::begin(sample.subsamples), std::end(sample.subsamples),
[](const CdmDecryptionSubsample& subsample) -> bool {
return subsample.protected_bytes > 0;
});
});
// A key does not need to be loaded if
// (a) the content consists of one or more samples and is entirely
// clear data
// (b) (legacy) the content consists of clear lead/frame in a single
// subsample. In earlier releases content was presented for decryption
// as individual subsamples. If the clear frame is broken up across
// multiple subsamples decryption, requests should be rejected
// (b/110251447)
// TODO(b/149524614): Remove support for the legacy case
if (is_any_protected ||
(parameters.observe_legacy_fields && parameters.samples.size() == 1 &&
parameters.samples[0].subsamples.size() == 1 &&
!(parameters.samples[0].subsamples[0].flags &
OEMCrypto_FirstSubsample &&
parameters.samples[0].subsamples[0].flags &
OEMCrypto_LastSubsample))) {
return KEY_NOT_FOUND_IN_SESSION;
}
}
}
return cdm_engine->DecryptV16(local_session_id, parameters);
}
void WvContentDecryptionModule::NotifyResolution(const CdmSessionId& session_id,
uint32_t width,
uint32_t height) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return;
cdm_engine->NotifyResolution(session_id, width, height);
}
bool WvContentDecryptionModule::IsValidServiceCertificate(
const std::string& certificate) {
ServiceCertificate cert;
CdmResponseType status = cert.Init(certificate);
if (status != NO_ERROR) return false;
return cert.has_certificate();
}
CdmResponseType WvContentDecryptionModule::GetMetrics(
std::vector<drm_metrics::WvCdmMetrics>* metrics, bool* full_list_returned) {
if (!metrics || !full_list_returned) {
return PARAMETER_NULL;
}
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
for (auto& key_value_pair : cdms_) {
const CdmIdentifier& identifier = key_value_pair.first;
drm_metrics::WvCdmMetrics metric;
const CdmResponseType status = GetMetricsInternal(identifier, &metric);
if (status == NO_ERROR) {
metrics->push_back(metric);
} else {
LOGD("GetMetrics call failed: cdm identifier=%u, error=%d",
identifier.unique_id, status);
}
}
// With no streaming activities, |cdms_| size would be zero,
// treat it as a non full list in that case.
*full_list_returned = !cdms_.empty() && metrics->size() == cdms_.size();
// We only return error if no metrics is returned when cdms_ is not empty.
// - metrics && cdms_ sizes can both be zero, returns NO_ERROR
// - metrics size <= cdms_, returns NO_ERROR
// - metrics is empty, but cdms_ is not, returns UNKNOWN_ERROR
return (metrics->empty() && !cdms_.empty()) ? UNKNOWN_ERROR : NO_ERROR;
}
CdmResponseType WvContentDecryptionModule::GetMetrics(
const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) {
if (!metrics) {
return PARAMETER_NULL;
}
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
return GetMetricsInternal(identifier, metrics);
}
CdmResponseType WvContentDecryptionModule::GetMetricsInternal(
const CdmIdentifier& identifier, drm_metrics::WvCdmMetrics* metrics) {
// Note: Caller should lock before calling.
auto it = cdms_.find(identifier);
if (it == cdms_.end()) {
LOGE("Cdm Identifier not found");
// TODO(blueeyes): Add a better error.
return UNKNOWN_ERROR;
}
return it->second.cdm_engine->GetMetricsSnapshot(metrics) ? NO_ERROR
: UNKNOWN_ERROR;
}
WvContentDecryptionModule::CdmInfo::CdmInfo()
: cdm_engine(CdmEngineFactory::CreateCdmEngine(&file_system)) {}
CdmEngine* WvContentDecryptionModule::EnsureCdmForIdentifier(
const CdmIdentifier& identifier) {
CdmEngine* cdm_engine;
bool enable_timer = false;
{
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
if (cdms_.size() == 0) enable_timer = true;
if (cdms_.find(identifier) == cdms_.end()) {
// Accessing the map entry will create a new instance using the default
// constructor. We then need to provide it with two pieces of info: The
// origin provided by the app and an identifier that uniquely identifies
// this CDM. We concatenate all pieces of the CdmIdentifier in order to
// create an ID that is unique to that identifier.
cdms_[identifier].file_system.set_origin(identifier.origin);
cdms_[identifier].file_system.set_identifier(identifier.spoid +
identifier.origin);
cdms_[identifier].cdm_engine->SetAppPackageName(
identifier.app_package_name);
cdms_[identifier].cdm_engine->SetSpoid(identifier.spoid);
cdms_[identifier].cdm_engine->SetUserId(identifier.user_id);
}
cdm_engine = cdms_[identifier].cdm_engine.get();
}
// Do not enable timer while holding on to the |cdms_lock_|
if (enable_timer) EnableTimer();
return cdm_engine;
}
CdmEngine* WvContentDecryptionModule::GetCdmForSessionId(
const std::string& session_id) {
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
// Use find to avoid creating empty entries when not found.
auto it = cdm_by_session_id_.find(session_id);
if (it == cdm_by_session_id_.end()) return nullptr;
return it->second;
}
void WvContentDecryptionModule::CloseAllCdms() {
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
cdm_by_session_id_.clear();
cdms_.clear();
}
CdmResponseType WvContentDecryptionModule::CloseCdm(
const CdmIdentifier& cdm_identifier) {
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
auto it = cdms_.find(cdm_identifier);
if (it == cdms_.end()) {
LOGE("Cdm Identifier not found");
// TODO(blueeyes): Create a better error.
return UNKNOWN_ERROR;
}
// Remove any sessions that point to this engine.
for (auto session_it = cdm_by_session_id_.begin();
session_it != cdm_by_session_id_.end();) {
if (session_it->second == it->second.cdm_engine.get()) {
session_it = cdm_by_session_id_.erase(session_it);
} else {
++session_it;
}
}
cdms_.erase(it);
return NO_ERROR;
}
CdmResponseType WvContentDecryptionModule::SetDebugIgnoreKeyboxCount(
uint32_t count) {
return CdmEngine::SetDebugIgnoreKeyboxCount(count);
}
CdmResponseType WvContentDecryptionModule::SetDecryptHash(
const std::string& hash_data, CdmSessionId* id) {
if (id == nullptr) {
LOGE("Cdm session ID not provided");
return PARAMETER_NULL;
}
uint32_t frame_number;
std::string hash;
CdmResponseType res =
CdmEngine::ParseDecryptHashString(hash_data, id, &frame_number, &hash);
if (res != NO_ERROR) return res;
CdmEngine* cdm_engine = GetCdmForSessionId(*id);
if (!cdm_engine) {
LOGE("Unable to find CdmEngine");
return SESSION_NOT_FOUND_20;
}
res = cdm_engine->SetDecryptHash(*id, frame_number, hash);
return res;
}
CdmResponseType WvContentDecryptionModule::GetDecryptHashError(
const CdmSessionId& session_id, std::string* hash_error_string) {
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) {
LOGE("Unable to find CdmEngine");
return SESSION_NOT_FOUND_20;
}
return cdm_engine->GetDecryptHashError(session_id, hash_error_string);
}
void WvContentDecryptionModule::EnableTimer() {
std::unique_lock<std::mutex> auto_lock(timer_lock_);
if (!timer_.IsRunning()) timer_.Start(this, kCdmTimerDurationSeconds);
}
void WvContentDecryptionModule::DisableTimer() {
std::unique_lock<std::mutex> auto_lock(timer_lock_);
if (timer_.IsRunning()) {
timer_.Stop(false);
}
}
void WvContentDecryptionModule::DisableTimerAndWaitForExit() {
std::unique_lock<std::mutex> auto_lock(timer_lock_);
if (timer_.IsRunning()) {
timer_.Stop(true);
}
}
void WvContentDecryptionModule::OnTimerEvent() {
bool disable_timer = false;
{
std::unique_lock<std::mutex> auto_lock(cdms_lock_);
for (auto it = cdms_.begin(); it != cdms_.end(); ++it) {
LoggingUidSetter set_uid(it->first.user_id);
it->second.cdm_engine->OnTimerEvent();
}
if (cdms_.empty()) {
// The following code cannot be attributed to any app uid.
LoggingUidSetter set_uid(UNKNOWN_UID);
if (CryptoSession::TryTerminate()) {
// If CryptoSession is in a state to be terminated, try acquiring the
// |timer_lock_| before deciding whether to disable the timer. If the
// lock cannot be acquired, there is no need to disable the timer.
// The |timer_lock_| is either being held by
// * EnableTimer - This does not appear possible, but if it did
// happen |OnTimerEvent| will be called again. The timer can be
// disabled during a future call.
// * DisableTimer - If so, allow that call to disable the timer. No
// need to call to disable it here.
// * DisableTimerAndWaitForExit - If so, allow that call to disable
// the timer. No need to call to disable it here. Note that
// |DisableTimerAndWaitForExit| will try to stop the timer but
// wait for it to exit. This might kick off the timer thread one
// last time, which will call into OnTimerEvent. Calling
// |DisableTimer| here will result in deadlock.
if (timer_lock_.try_lock()) {
disable_timer = true;
timer_lock_.unlock();
}
}
}
}
// Release |cdms_lock_| before attempting to disable the timer
if (disable_timer) {
DisableTimer();
}
}
uint32_t WvContentDecryptionModule::GenerateSessionSharingId() {
static int next_session_sharing_id = 0;
return ++next_session_sharing_id;
}
CdmResponseType WvContentDecryptionModule::ListStoredLicenses(
CdmSecurityLevel security_level, const CdmIdentifier& identifier,
std::vector<CdmKeySetId>* key_set_ids) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->ListStoredLicenses(security_level, key_set_ids);
}
CdmResponseType WvContentDecryptionModule::GetOfflineLicenseState(
const CdmKeySetId& key_set_id, CdmSecurityLevel security_level,
const CdmIdentifier& identifier, CdmOfflineLicenseState* license_state) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->GetOfflineLicenseState(key_set_id, security_level,
license_state);
}
CdmResponseType WvContentDecryptionModule::RemoveOfflineLicense(
const CdmKeySetId& key_set_id, CdmSecurityLevel security_level,
const CdmIdentifier& identifier) {
CdmEngine* cdm_engine = EnsureCdmForIdentifier(identifier);
return cdm_engine->RemoveOfflineLicense(key_set_id, security_level);
}
CdmResponseType WvContentDecryptionModule::SetPlaybackId(
const CdmSessionId& session_id, const std::string& playback_id) {
LOGV("Setting session ID %s playback ID %s", session_id.c_str(),
playback_id.c_str());
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_23;
return cdm_engine->SetPlaybackId(session_id, playback_id);
}
CdmResponseType WvContentDecryptionModule::GetSessionUserId(
const CdmSessionId& session_id, uint32_t* user_id) {
if (!user_id) return PARAMETER_NULL;
CdmEngine* cdm_engine = GetCdmForSessionId(session_id);
if (!cdm_engine) return SESSION_NOT_FOUND_23;
*user_id = cdm_engine->GetUserId();
return NO_ERROR;
}
} // namespace wvcdm