Source release 14.0.0
This commit is contained in:
90
cdm/cdm.gyp
90
cdm/cdm.gyp
@@ -7,24 +7,30 @@
|
||||
|
||||
{
|
||||
'variables': {
|
||||
# Override if you intend to link against a different OEMCrypto API version.
|
||||
'oemcrypto_version%': 13,
|
||||
|
||||
# Override if you can't depend on OpenSSL for privacy features.
|
||||
# If set to 'dummy', privacy mode in the CDM will fail.
|
||||
'privacy_crypto_impl%': 'openssl',
|
||||
|
||||
# There are two openssl configurations:
|
||||
# Override this to indicate what CPU architecture's assembly-language files
|
||||
# should be used when building assembly language files. Or, set it to
|
||||
# "none" to turn off the use of assembly language. The default is "none" for
|
||||
# compatibility, but we strongly recommend overriding this value to
|
||||
# improve performance. Turning it off or leaving it turned off is not
|
||||
# recommended unless your CPU architecture is unsupported or you are using
|
||||
# a tool that does not play nice with assembly language, like Address
|
||||
# Sanitizer.
|
||||
#
|
||||
# 1) openssl_config == 'system'
|
||||
# Use the openssl headers found in the sysroot and link the system library.
|
||||
#
|
||||
# 2) openssl_config == 'target'
|
||||
# Use the openssl implementation in an existing GYP target.
|
||||
# Specify the openssl target in openssl_target. This target should forward
|
||||
# the include path to its headers to its dependents.
|
||||
'openssl_config%': 'system',
|
||||
'openssl_target%': '',
|
||||
# Valid values are:
|
||||
# * x86
|
||||
# * x86-64
|
||||
# * arm
|
||||
# * arm64
|
||||
# * ppc64
|
||||
# * none
|
||||
'asm_target_arch%': 'none',
|
||||
|
||||
# Override this only if you have an alternative privacy crypto
|
||||
# implementation other than the default. This should nearly always be left
|
||||
# alone. If set to 'dummy', the CDM will compile, but privacy mode in the
|
||||
# CDM will fail.
|
||||
'privacy_crypto_impl%': 'boringssl',
|
||||
'boringssl_dependency%': '../third_party/boringssl/boringssl.gyp:crypto',
|
||||
|
||||
# There are three protobuf configurations:
|
||||
#
|
||||
@@ -116,46 +122,16 @@
|
||||
'../third_party/jsmn/jsmn.c',
|
||||
],
|
||||
'conditions': [
|
||||
['oemcrypto_version < 10', {
|
||||
'sources': [
|
||||
# Include APIs introduced in v10.
|
||||
'../core/src/oemcrypto_adapter_static_v10.cpp',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_version < 11', {
|
||||
'sources': [
|
||||
# Include APIs introduced in v11.
|
||||
'../core/src/oemcrypto_adapter_static_v11.cpp',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_version < 12', {
|
||||
'sources': [
|
||||
# Include APIs introduced in v12.
|
||||
'../core/src/oemcrypto_adapter_static_v12.cpp',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_version < 13', {
|
||||
'sources': [
|
||||
# Include APIs introduced in v13.
|
||||
'../core/src/oemcrypto_adapter_static_v13.cpp',
|
||||
],
|
||||
}],
|
||||
['privacy_crypto_impl=="openssl"', {
|
||||
'conditions': [
|
||||
['openssl_config == "target"', {
|
||||
'dependencies': [
|
||||
'<(openssl_target)',
|
||||
],
|
||||
}, {
|
||||
# openssl_config == "system"
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-lcrypto',
|
||||
],
|
||||
},
|
||||
}],
|
||||
], # conditions
|
||||
}], # privacy_crypto_impl=="openssl"
|
||||
['privacy_crypto_impl=="boringssl"', {
|
||||
'dependencies': [
|
||||
'<(boringssl_dependency)',
|
||||
], # dependencies
|
||||
}], # privacy_crypto_impl=="boringssl"
|
||||
['privacy_crypto_impl=="apple"', {
|
||||
'dependencies': [
|
||||
'<(boringssl_dependency)',
|
||||
], # dependencies
|
||||
}], # privacy_crypto_impl=="apple"
|
||||
], # conditions
|
||||
}, # widevine_cdm_core target
|
||||
{
|
||||
|
||||
@@ -5,8 +5,9 @@
|
||||
{
|
||||
'variables': {
|
||||
'oemcrypto_stubs%': '',
|
||||
'openssl_config%': 'system',
|
||||
'openssl_target%': '',
|
||||
'boringssl_dependency%': '../third_party/boringssl/boringssl.gyp:legacy_ssl',
|
||||
'metrics_target%': 'cdm.gyp:metrics_proto',
|
||||
'device_files_target%': 'cdm.gyp:device_files',
|
||||
},
|
||||
'targets': [
|
||||
{
|
||||
@@ -31,20 +32,19 @@
|
||||
],
|
||||
'dependencies': [
|
||||
'cdm.gyp:widevine_ce_cdm_shared',
|
||||
'cdm.gyp:widevine_cdm_core',
|
||||
'../third_party/gmock.gyp:gmock',
|
||||
'../third_party/gmock.gyp:gtest',
|
||||
],
|
||||
'conditions': [
|
||||
['oemcrypto_stubs!=""', {
|
||||
'dependencies': [
|
||||
'../oemcrypto/stubs/stubs.gyp:oec_stubs_v<(oemcrypto_version)',
|
||||
'../oemcrypto/stubs/stubs.gyp:oec_stubs_v14',
|
||||
],
|
||||
}, {
|
||||
'conditions': [
|
||||
['oemcrypto_lib=="mock"', {
|
||||
'dependencies': [
|
||||
'../oemcrypto/mock/oec_mock.gyp:oec_mock',
|
||||
'../oemcrypto/mock/oec_mock.gyp:oec_mock_shared',
|
||||
],
|
||||
}],
|
||||
['oemcrypto_lib=="level3"', {
|
||||
@@ -52,7 +52,7 @@
|
||||
# The test impl of OEMCrypto_Level3FileSystem and its factory.
|
||||
'test/level3_file_system_ce_test.h',
|
||||
'test/level3_file_system_ce_test.cpp',
|
||||
'test/level3_file_system_test_factory.cpp',
|
||||
'test/level3_file_system_ce_test_factory.cpp',
|
||||
],
|
||||
'conditions': [
|
||||
['oemcrypto_adapter=="static"', {
|
||||
|
||||
@@ -24,19 +24,7 @@
|
||||
'UNIT_TEST',
|
||||
'CDM_TESTS',
|
||||
],
|
||||
'conditions': [
|
||||
# OpenSSL needed for http_socket
|
||||
['openssl_config == "target"', {
|
||||
'dependencies': [
|
||||
'<(openssl_target)',
|
||||
],
|
||||
}, {
|
||||
# openssl_config == "system"
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-lssl',
|
||||
],
|
||||
},
|
||||
}],
|
||||
'dependencies': [
|
||||
'<(boringssl_dependency)',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -11,12 +11,16 @@
|
||||
'../core/include/cdm_session.h',
|
||||
'../core/include/cdm_session_map.h',
|
||||
'../core/include/certificate_provisioning.h',
|
||||
'../core/include/client_identification.h',
|
||||
'../core/include/clock.h',
|
||||
'../core/include/content_key_session.h',
|
||||
'../core/include/crypto_key.h',
|
||||
'../core/include/crypto_session.h',
|
||||
'../core/include/device_files.h',
|
||||
'../core/include/entitlement_key_session.h',
|
||||
'../core/include/file_store.h',
|
||||
'../core/include/initialization_data.h',
|
||||
'../core/include/key_session.h',
|
||||
'../core/include/license_key_status.h',
|
||||
'../core/include/license.h',
|
||||
'../core/include/lock.h',
|
||||
@@ -28,6 +32,7 @@
|
||||
'../core/include/scoped_ptr.h',
|
||||
'../core/include/service_certificate.h',
|
||||
'../core/include/string_conversions.h',
|
||||
'../core/include/sublicense_key_session.h',
|
||||
'../core/include/wv_cdm_constants.h',
|
||||
'../core/include/wv_cdm_event_listener.h',
|
||||
'../core/include/wv_cdm_types.h',
|
||||
@@ -37,17 +42,21 @@
|
||||
'../core/src/cdm_session.cpp',
|
||||
'../core/src/cdm_session_map.cpp',
|
||||
'../core/src/certificate_provisioning.cpp',
|
||||
'../core/src/client_identification.cpp',
|
||||
'../core/src/content_key_session.cpp',
|
||||
'../core/src/crypto_session.cpp',
|
||||
'../core/src/device_files.cpp',
|
||||
'../core/src/entitlement_key_session.cpp',
|
||||
'../core/src/initialization_data.cpp',
|
||||
'../core/src/license.cpp',
|
||||
'../core/src/license_key_status.cpp',
|
||||
'../core/src/policy_engine.cpp',
|
||||
'../core/src/privacy_crypto_openssl.cpp',
|
||||
'../core/src/properties.cpp',
|
||||
'../core/src/service_certificate.cpp',
|
||||
'../core/src/string_conversions.cpp',
|
||||
'../core/src/sublicense_key_session.cpp',
|
||||
'../core/src/usage_table_header.cpp',
|
||||
'../metrics/src/attribute_handler.cpp',
|
||||
'../metrics/src/counter_metric.cpp',
|
||||
'../metrics/src/distribution.cpp',
|
||||
'../metrics/src/event_metric.cpp',
|
||||
|
||||
@@ -9,7 +9,9 @@
|
||||
'../core/test/cdm_engine_test.cpp',
|
||||
'../core/test/cdm_session_unittest.cpp',
|
||||
'../core/test/config_test_env.cpp',
|
||||
'../core/test/crypto_session_unittest.cpp',
|
||||
'../core/test/device_files_unittest.cpp',
|
||||
# TODO(fredgc): generic tests don't work with prov 3.0.
|
||||
# '../core/test/generic_crypto_unittest.cpp', # currently keybox only
|
||||
'../core/test/http_socket.cpp',
|
||||
'../core/test/initialization_data_unittest.cpp',
|
||||
@@ -39,22 +41,8 @@
|
||||
'CORE_TESTS',
|
||||
],
|
||||
'dependencies': [
|
||||
'cdm.gyp:metrics_proto',
|
||||
'cdm.gyp:device_files',
|
||||
],
|
||||
'conditions': [
|
||||
# OpenSSL needed for http_socket
|
||||
['openssl_config == "target"', {
|
||||
'dependencies': [
|
||||
'<(openssl_target)',
|
||||
],
|
||||
}, {
|
||||
# openssl_config == "system"
|
||||
'link_settings': {
|
||||
'libraries': [
|
||||
'-lssl',
|
||||
],
|
||||
},
|
||||
}],
|
||||
'<(boringssl_dependency)',
|
||||
'<(metrics_target)',
|
||||
'<(device_files_target)',
|
||||
],
|
||||
}
|
||||
|
||||
@@ -127,6 +127,16 @@ class CDM_EXPORT Cdm : public ITimerClient {
|
||||
kReleased = 5,
|
||||
} KeyStatus;
|
||||
|
||||
// These are the possible HDCP levels supported by Widevine.
|
||||
// For ease of comparison, these values are kept in ascending order by version
|
||||
// number.
|
||||
typedef enum {
|
||||
kHdcp1_x = 0,
|
||||
kHdcp2_0 = 1,
|
||||
kHdcp2_1 = 2,
|
||||
kHdcp2_2 = 3,
|
||||
} HdcpVersion;
|
||||
|
||||
// Permissible usages for a key. Returned as a set of flags; multiple
|
||||
// flags may be set. The specific settings are defined in the license
|
||||
// and the OEMCrypto Key Control Block. The CDM uses settings in the
|
||||
@@ -187,7 +197,8 @@ class CDM_EXPORT Cdm : public ITimerClient {
|
||||
const std::string& message) = 0;
|
||||
|
||||
// There has been a change in the keys in the session or their status.
|
||||
virtual void onKeyStatusesChange(const std::string& session_id) = 0;
|
||||
virtual void onKeyStatusesChange(const std::string& session_id,
|
||||
bool has_new_usable_key) = 0;
|
||||
|
||||
// A remove() operation has been completed.
|
||||
virtual void onRemoveComplete(const std::string& session_id) = 0;
|
||||
@@ -406,6 +417,11 @@ class CDM_EXPORT Cdm : public ITimerClient {
|
||||
// CDM's current IStorage object.
|
||||
virtual Status deleteAllUsageRecords() = 0;
|
||||
|
||||
// Checks whether the device is capable of supporting a given HDCP version.
|
||||
// If successful, |key_status| is set to either kUsable or kOutputRestricted.
|
||||
virtual Status getStatusForHdcpVersion(HdcpVersion hdcp,
|
||||
KeyStatus* key_status) = 0;
|
||||
|
||||
// Creates a new session.
|
||||
// Do not use this to load an existing persistent session (use load()).
|
||||
// If successful, the session_id is returned via |sessionId|.
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
// Widevine CE CDM Version
|
||||
#define CDM_VERSION "v3.5.0-0-gc0ea5d51-ce"
|
||||
#define CDM_VERSION "14.0.0"
|
||||
#define EME_VERSION "https://www.w3.org/TR/2017/REC-encrypted-media-20170918"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
'defines': [
|
||||
'OEMCRYPTO_TESTS',
|
||||
],
|
||||
'libraries': [
|
||||
'-lcrypto',
|
||||
'dependencies': [
|
||||
'<(boringssl_dependency)',
|
||||
],
|
||||
}
|
||||
|
||||
174
cdm/src/cdm.cpp
174
cdm/src/cdm.cpp
@@ -138,6 +138,9 @@ class CdmImpl : public Cdm,
|
||||
|
||||
virtual Status deleteAllUsageRecords() OVERRIDE;
|
||||
|
||||
virtual Status getStatusForHdcpVersion(HdcpVersion hdcp,
|
||||
KeyStatus* key_status) OVERRIDE;
|
||||
|
||||
virtual Status createSession(SessionType session_type,
|
||||
std::string* session_id) OVERRIDE;
|
||||
|
||||
@@ -220,11 +223,13 @@ class CdmImpl : public Cdm,
|
||||
|
||||
private:
|
||||
KeyAllowedUsageFlags KeyAllowedFlags(const CdmKeyAllowedUsage& usages);
|
||||
bool SendProvisioningRequest(const std::string& session_id);
|
||||
Cdm::Status SendProvisioningRequest(const std::string& session_id);
|
||||
CdmEncryptionAlgorithm ConvertEncryptionAlgorithm(
|
||||
GenericEncryptionAlgorithmType algorithm);
|
||||
CdmSigningAlgorithm ConvertSigningAlgorithm(
|
||||
GenericSigningAlgorithmType algorithm);
|
||||
Cdm::Status ConvertHdcpLevel(const std::string& query_value,
|
||||
Cdm::HdcpVersion* result);
|
||||
|
||||
IEventListener* listener_;
|
||||
bool policy_timer_enabled_;
|
||||
@@ -251,12 +256,14 @@ class CdmImpl : public Cdm,
|
||||
InitDataType init_data_type;
|
||||
bool has_init_data;
|
||||
bool is_load;
|
||||
bool quota_overrun;
|
||||
|
||||
UnprovisionedSessionMetadata()
|
||||
: type((SessionType)-1),
|
||||
init_data_type((InitDataType)-1),
|
||||
has_init_data(false),
|
||||
is_load(false) {}
|
||||
is_load(false),
|
||||
quota_overrun(false) {}
|
||||
};
|
||||
typedef std::map<std::string, UnprovisionedSessionMetadata> UnprovisionedMap;
|
||||
|
||||
@@ -279,6 +286,8 @@ CdmImpl::~CdmImpl() {
|
||||
host.timer->cancel(this);
|
||||
}
|
||||
|
||||
// TODO(gmorgan): Add separate interfaces to set license/provisioning
|
||||
// service certificates. Right now this sets both.
|
||||
Cdm::Status CdmImpl::setServiceCertificate(const std::string& certificate) {
|
||||
|
||||
if (certificate.empty()) {
|
||||
@@ -287,14 +296,12 @@ Cdm::Status CdmImpl::setServiceCertificate(const std::string& certificate) {
|
||||
}
|
||||
|
||||
// Verify that the certificate is properly signed and well-formed.
|
||||
ServiceCertificate service_certificate;
|
||||
CdmResponseType status = service_certificate.Init(certificate);
|
||||
CdmResponseType status =
|
||||
cdm_engine_.SetProvisioningServiceCertificate(certificate);
|
||||
if (status != NO_ERROR) {
|
||||
LOGE("Invalid service certificate! Error code = %d", status);
|
||||
return kTypeError;
|
||||
}
|
||||
// TODO(gmorgan): remove when provisioning service certificate is added
|
||||
cdm_engine_.SetServiceCertificate(certificate);
|
||||
property_set_.set_service_certificate(certificate);
|
||||
return kSuccess;
|
||||
}
|
||||
@@ -379,13 +386,38 @@ Cdm::Status CdmImpl::deleteUsageRecord(const std::string& key_set_id) {
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::deleteAllUsageRecords() {
|
||||
if (cdm_engine_.ReleaseAllUsageInfo(
|
||||
if (cdm_engine_.RemoveAllUsageInfo(
|
||||
property_set_.app_id(), kSecurityLevelL1) != NO_ERROR) {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::getStatusForHdcpVersion(Cdm::HdcpVersion hdcp,
|
||||
Cdm::KeyStatus* key_status) {
|
||||
std::string query_value;
|
||||
if (cdm_engine_.QueryStatus(kLevelDefault,
|
||||
QUERY_KEY_MAX_HDCP_LEVEL,
|
||||
&query_value) != NO_ERROR) {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
|
||||
if (query_value == QUERY_VALUE_HDCP_NONE ||
|
||||
query_value == QUERY_VALUE_HDCP_LEVEL_UNKNOWN) {
|
||||
*key_status = Cdm::kOutputRestricted;
|
||||
} else if (query_value == QUERY_VALUE_HDCP_NO_DIGITAL_OUTPUT) {
|
||||
*key_status = Cdm::kUsable;
|
||||
} else {
|
||||
Cdm::HdcpVersion max_hdcp;
|
||||
if (ConvertHdcpLevel(query_value, &max_hdcp) != kSuccess) {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
|
||||
*key_status = (hdcp <= max_hdcp ? Cdm::kUsable : Cdm::kOutputRestricted);
|
||||
}
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::createSession(SessionType session_type,
|
||||
std::string* session_id) {
|
||||
if (session_id == NULL) {
|
||||
@@ -449,20 +481,26 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
||||
// We are not provisioned yet, save the init data and send a provisioning
|
||||
// request if needed.
|
||||
if (unprovisioned_sessions_[session_id].has_init_data) {
|
||||
LOGE("Request already generated: %s", session_id.c_str());
|
||||
return kInvalidState;
|
||||
if (!unprovisioned_sessions_[session_id].quota_overrun) {
|
||||
LOGE("Request already generated: %s", session_id.c_str());
|
||||
return kInvalidState;
|
||||
}
|
||||
} else {
|
||||
unprovisioned_sessions_[session_id].has_init_data = true;
|
||||
unprovisioned_sessions_[session_id].init_data_type = init_data_type;
|
||||
unprovisioned_sessions_[session_id].init_data = init_data;
|
||||
}
|
||||
|
||||
unprovisioned_sessions_[session_id].has_init_data = true;
|
||||
unprovisioned_sessions_[session_id].init_data_type = init_data_type;
|
||||
unprovisioned_sessions_[session_id].init_data = init_data;
|
||||
|
||||
if (provision_request_sent_)
|
||||
return kDeferred;
|
||||
|
||||
if (!SendProvisioningRequest(session_id))
|
||||
return kUnexpectedError;
|
||||
return kSuccess;
|
||||
Cdm::Status status = SendProvisioningRequest(session_id);
|
||||
if (status == kQuotaExceeded) {
|
||||
unprovisioned_sessions_[session_id].quota_overrun = true;
|
||||
} else {
|
||||
unprovisioned_sessions_[session_id].quota_overrun = false;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,7 +550,13 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
||||
return kTypeError;
|
||||
}
|
||||
|
||||
InitializationData init_data_obj(init_data_type_name, init_data);
|
||||
std::string oec_version;
|
||||
if (cdm_engine_.QueryStatus(wvcdm::kLevelDefault,
|
||||
QUERY_KEY_OEMCRYPTO_API_VERSION,
|
||||
&oec_version) != NO_ERROR) {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
InitializationData init_data_obj(init_data_type_name, init_data, oec_version);
|
||||
if (init_data_obj.IsEmpty()) {
|
||||
// Note that InitializationData's idea of "empty" includes "failed to find
|
||||
// and parse a Widevine PSSH". This should not happen for WebM init data,
|
||||
@@ -527,6 +571,11 @@ Cdm::Status CdmImpl::generateRequest(const std::string& session_id,
|
||||
session_id, session_id, init_data_obj,
|
||||
license_type, app_parameters_, &key_request);
|
||||
|
||||
if (result == LICENSE_REQUEST_NONCE_GENERATION_ERROR) {
|
||||
LOGE("Nonce quota exceeded");
|
||||
return kQuotaExceeded;
|
||||
}
|
||||
|
||||
if (result != KEY_MESSAGE) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
return kUnexpectedError;
|
||||
@@ -564,10 +613,7 @@ Cdm::Status CdmImpl::load(const std::string& session_id) {
|
||||
|
||||
// Send a provisioning request right away. Then we will load the session
|
||||
// again in |update|.
|
||||
if (!SendProvisioningRequest(session_id))
|
||||
return kUnexpectedError;
|
||||
|
||||
return kSuccess;
|
||||
return SendProvisioningRequest(session_id);
|
||||
default:
|
||||
LOGE("Unexpected error %d", result);
|
||||
return kUnexpectedError;
|
||||
@@ -632,7 +678,14 @@ Cdm::Status CdmImpl::load(const std::string& session_id,
|
||||
return kTypeError;
|
||||
}
|
||||
|
||||
InitializationData init_data_obj(CENC_INIT_DATA_FORMAT, init_data);
|
||||
std::string oec_version;
|
||||
if (cdm_engine_.QueryStatus(wvcdm::kLevelDefault,
|
||||
QUERY_KEY_OEMCRYPTO_API_VERSION,
|
||||
&oec_version) != NO_ERROR) {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
InitializationData init_data_obj(CENC_INIT_DATA_FORMAT, init_data,
|
||||
oec_version);
|
||||
if (init_data_obj.IsEmpty()) {
|
||||
// Note that InitializationData's idea of "empty" includes "failed to find
|
||||
// and parse a Widevine PSSH". This should not happen for WebM init data,
|
||||
@@ -643,9 +696,15 @@ Cdm::Status CdmImpl::load(const std::string& session_id,
|
||||
|
||||
CdmKeyRequest key_request;
|
||||
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
|
||||
session_id, session_id, init_data_obj, kLicenseTypeSubSession,
|
||||
session_id, session_id, init_data_obj, kLicenseTypeEmbeddedKeyData,
|
||||
app_parameters_, &key_request);
|
||||
if (result != KEY_MESSAGE) {
|
||||
|
||||
if (result == LICENSE_REQUEST_NONCE_GENERATION_ERROR) {
|
||||
LOGE("Nonce quota exceeded");
|
||||
return kQuotaExceeded;
|
||||
}
|
||||
if (result != KEY_ADDED) {
|
||||
LOGE("Unexpected Failure: GenerateKeyRequest() returned %lu", result);
|
||||
return kUnexpectedError;
|
||||
}
|
||||
return kSuccess;
|
||||
@@ -664,8 +723,11 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
|
||||
LOGE("Unexpected error %d", result);
|
||||
return kUnexpectedError;
|
||||
}
|
||||
}
|
||||
|
||||
// We are now provisioned, we need to recreate the unprovisioned sessions.
|
||||
// Check to see if any sessions have been waiting for provisioning.
|
||||
// If so, try to recreate those sessions and generate their requests.
|
||||
if (unprovisioned_sessions_.size() > 0) {
|
||||
Cdm::Status ret = kSuccess;
|
||||
for (UnprovisionedMap::iterator it = unprovisioned_sessions_.begin();
|
||||
it != unprovisioned_sessions_.end();) {
|
||||
@@ -679,8 +741,8 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
|
||||
continue;
|
||||
}
|
||||
|
||||
result = cdm_engine_.OpenSession("com.widevine.alpha", &property_set_,
|
||||
it->first, this);
|
||||
CdmResponseType result = cdm_engine_.OpenSession(
|
||||
"com.widevine.alpha", &property_set_, it->first, this);
|
||||
if (result != NO_ERROR) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
if (it->first == session_id)
|
||||
@@ -699,11 +761,16 @@ Cdm::Status CdmImpl::update(const std::string& session_id,
|
||||
if (it->second.has_init_data) {
|
||||
Cdm::Status generate_status = generateRequest(
|
||||
it->first, it->second.init_data_type, it->second.init_data);
|
||||
if (it->first != session_id)
|
||||
if (it->first != session_id) {
|
||||
listener_->onDeferredComplete(it->first, generate_status);
|
||||
else if (generate_status != kSuccess)
|
||||
} else if (generate_status == Cdm::kQuotaExceeded) {
|
||||
// Close session. We'll re-open it again on the next call to update.
|
||||
cdm_engine_.CloseSession(session_id);
|
||||
return Cdm::kQuotaExceeded;
|
||||
} else if (generate_status != kSuccess) {
|
||||
// Still erase the item because the session exists in |cdm_engine_|.
|
||||
ret = generate_status;
|
||||
}
|
||||
}
|
||||
unprovisioned_sessions_.erase(it++);
|
||||
}
|
||||
@@ -926,6 +993,11 @@ Cdm::Status CdmImpl::remove(const std::string& session_id) {
|
||||
CdmResponseType result = cdm_engine_.GenerateKeyRequest(
|
||||
session_id, session_id, empty_initialization_data,
|
||||
kLicenseTypeRelease, app_parameters_, &key_request);
|
||||
|
||||
if (result == LICENSE_REQUEST_NONCE_GENERATION_ERROR) {
|
||||
LOGE("Nonce quota exceeded");
|
||||
return kQuotaExceeded;
|
||||
}
|
||||
if (result != KEY_MESSAGE) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
cdm_engine_.CloseSession(session_id);
|
||||
@@ -1142,6 +1214,13 @@ void CdmImpl::OnSessionRenewalNeeded(const CdmSessionId& session_id) {
|
||||
CdmKeyRequest key_request;
|
||||
CdmResponseType result =
|
||||
cdm_engine_.GenerateRenewalRequest(session_id, &key_request);
|
||||
if (result == LICENSE_RENEWAL_NONCE_GENERATION_ERROR) {
|
||||
// TODO(b/73606893): this error should be recoverable. Rather
|
||||
// than just giving up here, we should reset the event timer for
|
||||
// a second later and try again.
|
||||
LOGE("Nonce quota exceeded");
|
||||
return;
|
||||
}
|
||||
if (result != KEY_MESSAGE) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
return;
|
||||
@@ -1154,7 +1233,7 @@ void CdmImpl::OnSessionRenewalNeeded(const CdmSessionId& session_id) {
|
||||
|
||||
void CdmImpl::OnSessionKeysChange(const CdmSessionId& session_id,
|
||||
const CdmKeyStatusMap& keys_status,
|
||||
bool /* has_new_usable_key */) {
|
||||
bool has_new_usable_key) {
|
||||
KeyStatusMap& map = sessions_[session_id].key_statuses;
|
||||
|
||||
CdmKeyStatusMap::const_iterator it;
|
||||
@@ -1189,7 +1268,7 @@ void CdmImpl::OnSessionKeysChange(const CdmSessionId& session_id,
|
||||
}
|
||||
}
|
||||
|
||||
listener_->onKeyStatusesChange(session_id);
|
||||
listener_->onKeyStatusesChange(session_id, has_new_usable_key);
|
||||
}
|
||||
|
||||
void CdmImpl::OnExpirationUpdate(const CdmSessionId& session_id,
|
||||
@@ -1214,7 +1293,7 @@ Cdm::KeyAllowedUsageFlags CdmImpl::KeyAllowedFlags(
|
||||
return flags;
|
||||
}
|
||||
|
||||
bool CdmImpl::SendProvisioningRequest(const std::string& session_id) {
|
||||
Cdm::Status CdmImpl::SendProvisioningRequest(const std::string& session_id) {
|
||||
// Generate a provisioning request.
|
||||
std::string empty_authority;
|
||||
std::string ignored_base_url;
|
||||
@@ -1222,14 +1301,17 @@ bool CdmImpl::SendProvisioningRequest(const std::string& session_id) {
|
||||
CdmResponseType result = cdm_engine_.GetProvisioningRequest(
|
||||
kCertificateWidevine, empty_authority, &signed_request,
|
||||
&ignored_base_url);
|
||||
if (result == CERT_PROVISIONING_NONCE_GENERATION_ERROR) {
|
||||
LOGE("Nonce quota exceeded");
|
||||
return kQuotaExceeded;
|
||||
}
|
||||
if (result != NO_ERROR) {
|
||||
LOGE("Unexpected error %d", result);
|
||||
return false;
|
||||
return kUnexpectedError;
|
||||
}
|
||||
listener_->onDirectIndividualizationRequest(session_id, signed_request);
|
||||
provision_request_sent_ = true;
|
||||
|
||||
return true;
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
CdmEncryptionAlgorithm CdmImpl::ConvertEncryptionAlgorithm(
|
||||
@@ -1252,6 +1334,22 @@ CdmSigningAlgorithm CdmImpl::ConvertSigningAlgorithm(
|
||||
}
|
||||
}
|
||||
|
||||
Cdm::Status CdmImpl::ConvertHdcpLevel(const std::string& query_value,
|
||||
Cdm::HdcpVersion* result) {
|
||||
if (query_value == QUERY_VALUE_HDCP_V1) {
|
||||
*result = kHdcp1_x;
|
||||
} else if (query_value == QUERY_VALUE_HDCP_V2_0) {
|
||||
*result = kHdcp2_0;
|
||||
} else if (query_value == QUERY_VALUE_HDCP_V2_1) {
|
||||
*result = kHdcp2_1;
|
||||
} else if (query_value == QUERY_VALUE_HDCP_V2_2) {
|
||||
*result = kHdcp2_2;
|
||||
} else {
|
||||
return kUnexpectedError;
|
||||
}
|
||||
return kSuccess;
|
||||
}
|
||||
|
||||
bool VerifyL1() {
|
||||
CryptoSession cs(NULL);
|
||||
return cs.GetSecurityLevel() == kSecurityLevelL1;
|
||||
@@ -1338,8 +1436,10 @@ Cdm* Cdm::create(IEventListener* listener,
|
||||
LOGE("No listener!");
|
||||
return NULL;
|
||||
}
|
||||
if (!storage)
|
||||
storage = host.storage;
|
||||
if (!storage) {
|
||||
LOGE("No storage!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new CdmImpl(listener, storage, privacy_mode);
|
||||
}
|
||||
|
||||
@@ -85,7 +85,6 @@ void Properties::Init() {
|
||||
oem_crypto_use_fifo_ = use_fifo_;
|
||||
oem_crypto_use_userspace_buffers_ = use_userspace_buffers_;
|
||||
provisioning_messages_are_binary_ = set_provisioning_messages_to_binary_;
|
||||
security_level_path_backward_compatibility_support_ = false;
|
||||
allow_service_certificate_requests_ = false;
|
||||
session_property_set_.reset(new CdmClientPropertySetMap());
|
||||
}
|
||||
|
||||
@@ -81,6 +81,80 @@ const std::string kHlsInitData =
|
||||
"lc3QiLA0KICAgImNvbnRlbnRfaWQiOiAiWW1sblluVmphMkoxYm01NSIsDQogICAia2V5X2lkc"
|
||||
"yI6IFsNCiAgICAgICI5Yjc1OTA0MDMyMWE0MDhhNWM3NzY4YjQ1MTEyODdhNiINCiAgIF0NCn0"
|
||||
"=\",IV=0x75537a79fa41abc7b598ea72aba0c26f";
|
||||
const std::string kCencEntitlementInitData1 = a2bs_hex(
|
||||
"000001fb" // blob size
|
||||
"70737368" // "pssh"
|
||||
"00000000" // flags
|
||||
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
||||
"000001db" // pssh data size
|
||||
// pssh data:
|
||||
"220b47726f7570563254657374381448"
|
||||
"e3dc959b065002580272580a10668093"
|
||||
"381a8c5be48a0168ce372726ac1210c8"
|
||||
"326486bb5d5c4a958f00b1111afc811a"
|
||||
"20082cd9d3aed3ebe6239d30fbcf0b22"
|
||||
"1d28cbb0360ea1295c2363973346ec00"
|
||||
"512210914781334e864c8eb7f768cf26"
|
||||
"49073872580a10f872d11d5b1052f2bd"
|
||||
"a94e60a0e383021210450897c987a85c"
|
||||
"2e9579f968554a12991a2097e603ceea"
|
||||
"f35ed8cef1029eae7a0a54701e3d6db6"
|
||||
"80e7da1de3b22a8db347fb2210b41c34"
|
||||
"29b7bb96972bbaf6587bc0ddf172580a"
|
||||
"10bac58b9fce9e5929a42a180e529f19"
|
||||
"4712103f11f22988d25659b145ce4854"
|
||||
"3e6b141a20416e22768e5a57b08d155e"
|
||||
"5210d00658056947ff06d626668bceb3"
|
||||
"5eb01c6b57221081fb2ff3fef79d332f"
|
||||
"f98be46233596972580a101261c8036d"
|
||||
"ae5c8caa968858aa0ca9cc12106d583c"
|
||||
"b37c1456519843a81cf49912221a20c2"
|
||||
"1116bb54a226e8d879a4cd41d8879920"
|
||||
"2ae85b80d83b1b4447e5d7fcad6f6a22"
|
||||
"100b27a4c3f44771d2b0c7c34c66af35"
|
||||
"b572580a10ab1c8c259c6b5967991389"
|
||||
"65bff5ac0c1210b5b4473658565d3786"
|
||||
"efaf4b85d8e6e21a203ce6a9085285c2"
|
||||
"ece0b650dc83dd7aa8ac849611a8e3f8"
|
||||
"3c8f389223c0f3621522101946f0c2a3"
|
||||
"d543101cc842bbec2d0b30");
|
||||
const std::string kCencEntitlementInitData2 = a2bs_hex(
|
||||
"000001fb" // blob size
|
||||
"70737368" // "pssh"
|
||||
"00000000" // flags
|
||||
"edef8ba979d64acea3c827dcd51d21ed" // Widevine system id
|
||||
"000001db" // pssh data size
|
||||
// pssh data:
|
||||
"220b47726f7570563254657374381548"
|
||||
"e3dc959b065002580272580a10668093"
|
||||
"381a8c5be48a0168ce372726ac1210f8"
|
||||
"488775a99855ff94b93ec5bd4993561a"
|
||||
"20d15ba631c20e95da0d4857f6a1d25a"
|
||||
"a3bccbd3fde18b3fdc1dd8c4f0ede76f"
|
||||
"402210d6dd3675f0d1150052e81b9107"
|
||||
"6d7fc172580a10f872d11d5b1052f2bd"
|
||||
"a94e60a0e383021210ad1f93ad921e53"
|
||||
"b097c415b2bf1ef1c61a20b2087b60a2"
|
||||
"d253ac2158a1bfa789b150b79701b29e"
|
||||
"c852a2662560f8b8977a4c2210051ed3"
|
||||
"2628671fbda58f506ba5ea713972580a"
|
||||
"10bac58b9fce9e5929a42a180e529f19"
|
||||
"47121027cdda7bfe5e5fd4bff2ebc9c7"
|
||||
"c020701a20f2cb1184d648a2404517e6"
|
||||
"7a39d698332aae6bb890a69bf7ddb536"
|
||||
"75b8ac41c62210a80ed7f9b728fdd566"
|
||||
"0b01b173ace26372580a101261c8036d"
|
||||
"ae5c8caa968858aa0ca9cc1210769a70"
|
||||
"0442a25bf5ae17174c70f4cb8e1a206c"
|
||||
"7b2012723fc47c83b003ea214204915f"
|
||||
"9a63dc373bf219f36ccf5697589aa422"
|
||||
"10bcc3c16e836cca264d5493a0c334d3"
|
||||
"4872580a10ab1c8c259c6b5967991389"
|
||||
"65bff5ac0c1210894b04aef78557c6a7"
|
||||
"e6e8855febbcc91a2025cc545ee3cd0c"
|
||||
"c323586610ff6a8f8f22a78f5fade2f2"
|
||||
"1083f152c52208f16d2210257aacacec"
|
||||
"512a2e769396b10e6d9dfa");
|
||||
|
||||
// This Key ID must match the key retrieved from the license server by
|
||||
// kCencInitData.
|
||||
@@ -90,6 +164,12 @@ const std::vector<uint8_t> kKeyIdCtr = a2b_hex(
|
||||
// kHlsInitData.
|
||||
const std::vector<uint8_t> kKeyIdCbc = a2b_hex(
|
||||
"9b759040321a408a5c7768b4511287a6");
|
||||
// This Key ID must match a key embedded in kCencEntitlementInitData1.
|
||||
const std::vector<uint8_t> kKeyIdEntitlement1 = a2b_hex(
|
||||
"c8326486bb5d5c4a958f00b1111afc81");
|
||||
// This Key ID must match a key embedded in kCencEntitlementInitData2.
|
||||
const std::vector<uint8_t> kKeyIdEntitlement2 = a2b_hex(
|
||||
"f8488775a99855ff94b93ec5bd499356");
|
||||
|
||||
// A default pattern object disables patterns during decryption.
|
||||
const Cdm::Pattern kPatternNone;
|
||||
@@ -118,8 +198,8 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
void(const std::string& session_id,
|
||||
Cdm::MessageType message_type,
|
||||
const std::string& message));
|
||||
MOCK_METHOD1(onKeyStatusesChange,
|
||||
void(const std::string& session_id));
|
||||
MOCK_METHOD2(onKeyStatusesChange,
|
||||
void(const std::string& session_id, bool has_new_usable_key));
|
||||
MOCK_METHOD1(onRemoveComplete,
|
||||
void(const std::string& session_id));
|
||||
MOCK_METHOD2(onDeferredComplete,
|
||||
@@ -179,7 +259,7 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
}
|
||||
|
||||
void CreateAdditionalCdm(bool privacy_mode, scoped_ptr<Cdm>* cdm) {
|
||||
cdm->reset(Cdm::create(this, NULL, privacy_mode));
|
||||
cdm->reset(Cdm::create(this, g_host, privacy_mode));
|
||||
ASSERT_NE((Cdm*)0, cdm->get());
|
||||
}
|
||||
|
||||
@@ -297,9 +377,9 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
}
|
||||
ASSERT_FALSE(init_data.empty());
|
||||
|
||||
EXPECT_CALL(*this, onMessage(*session_id, Cdm::kLicenseRequest, _)).
|
||||
WillOnce(SaveArg<2>(message));
|
||||
status = cdm_->generateRequest(*session_id, init_data_type, init_data);
|
||||
EXPECT_CALL(*this, onMessage(*session_id, Cdm::kLicenseRequest, _))
|
||||
.WillOnce(SaveArg<2>(message));
|
||||
status = generateRequestWithRetry(*session_id, init_data_type, init_data);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -328,8 +408,8 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
std::string response;
|
||||
ASSERT_NO_FATAL_FAILURE(CreateSessionAndFetchLicense(
|
||||
session_type, init_data_type, session_id, &response));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(*session_id));
|
||||
Cdm::Status status = cdm_->update(*session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(*session_id, true));
|
||||
Cdm::Status status = updateWithRetry(*session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -342,8 +422,8 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
g_license_server, message, &response));
|
||||
|
||||
// This license should be accepted, but the keys are not expected to change.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
Cdm::Status status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -366,6 +446,41 @@ class CdmTest : public Test, public Cdm::IEventListener {
|
||||
return reply;
|
||||
}
|
||||
|
||||
// This calls cdm->update, and retries several times if there is a
|
||||
// failure due to nonce flood errors.
|
||||
Cdm::Status updateWithRetry(const std::string& session_id,
|
||||
const std::string& response) {
|
||||
const int num_retries = 5;
|
||||
for (int i = 0; i < num_retries; i++) {
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
if (status == Cdm::kQuotaExceeded) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return Cdm::kQuotaExceeded;
|
||||
}
|
||||
|
||||
// This calls cdm->generateRequest, and retries several times if there is a
|
||||
// failure due to nonce flood errors.
|
||||
Cdm::Status generateRequestWithRetry(const std::string& session_id,
|
||||
Cdm::InitDataType init_data_type,
|
||||
const std::string& init_data) {
|
||||
const int num_retries = 5;
|
||||
for (int i = 0; i < num_retries; i++) {
|
||||
LOGD("attempt %d", i);
|
||||
Cdm::Status status =
|
||||
cdm_->generateRequest(session_id, init_data_type, init_data);
|
||||
if (status == Cdm::kQuotaExceeded) {
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
return Cdm::kQuotaExceeded;
|
||||
}
|
||||
|
||||
scoped_ptr<Cdm> cdm_;
|
||||
};
|
||||
|
||||
@@ -599,7 +714,7 @@ TEST_F(CdmTest, Provision) {
|
||||
// Creating a session should succeed.
|
||||
std::string session_id;
|
||||
Cdm::Status status;
|
||||
status = cdm_->setServiceCertificate(g_license_service_certificate);
|
||||
status = cdm_->setServiceCertificate(g_provisioning_service_certificate);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -608,7 +723,7 @@ TEST_F(CdmTest, Provision) {
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -617,7 +732,7 @@ TEST_F(CdmTest, Provision) {
|
||||
ASSERT_FALSE(reply.empty());
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
status = cdm_->update(session_id, reply);
|
||||
status = updateWithRetry(session_id, reply);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -660,13 +775,13 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
|
||||
// Generate a license request for CENC.
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Can't call generateRequest more than once on a session.
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kInvalidState, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -674,7 +789,7 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kWebM, kWebMInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kWebM, kWebMInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -682,7 +797,7 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, Cdm::kKeyIds, kKeyIdsInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kKeyIds, kKeyIdsInitData);
|
||||
EXPECT_EQ(Cdm::kNotSupported, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -690,7 +805,7 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kHls, kHlsInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kHls, kHlsInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -698,14 +813,14 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, kBogusInitDataType, "asdf");
|
||||
status = generateRequestWithRetry(session_id, kBogusInitDataType, "asdf");
|
||||
EXPECT_EQ(Cdm::kTypeError, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// This same session should still be usable with a supported init data type
|
||||
// after failing with an unsupported or bogus type.
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -713,7 +828,7 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, "");
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, "");
|
||||
EXPECT_EQ(Cdm::kTypeError, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -721,7 +836,8 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kInvalidCencInitData);
|
||||
status =
|
||||
generateRequestWithRetry(session_id, Cdm::kCenc, kInvalidCencInitData);
|
||||
EXPECT_EQ(Cdm::kNotSupported, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -729,14 +845,14 @@ TEST_F(CdmTest, GenerateRequest) {
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc,
|
||||
kNonWidevineCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc,
|
||||
kNonWidevineCencInitData);
|
||||
EXPECT_EQ(Cdm::kNotSupported, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Try a bogus session ID.
|
||||
EXPECT_CALL(*this, onMessage(_, _, _)).Times(0);
|
||||
status = cdm_->generateRequest(kBogusSessionId, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(kBogusSessionId, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -757,23 +873,23 @@ TEST_F(CdmTest, Update) {
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
status = updateWithRetry(session_id, response);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Try updating a bogus session ID.
|
||||
status = cdm_->update(kBogusSessionId, response);
|
||||
status = updateWithRetry(kBogusSessionId, response);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
|
||||
// Try updating with an empty response.
|
||||
status = cdm_->update(session_id, "");
|
||||
status = updateWithRetry(session_id, "");
|
||||
EXPECT_EQ(Cdm::kTypeError, status);
|
||||
|
||||
// Create a new session and try updating before generating a request.
|
||||
status = cdm_->createSession(Cdm::kTemporary, &session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->update(session_id, response);
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kInvalidState, status);
|
||||
}
|
||||
|
||||
@@ -789,7 +905,7 @@ TEST_F(CdmTest, Close) {
|
||||
|
||||
// Can't generate a license request after close.
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(0);
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -813,8 +929,8 @@ TEST_F(CdmTest, LoadTemporary) {
|
||||
Cdm::kTemporary, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the temporary session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -837,22 +953,22 @@ TEST_F(CdmTest, DISABLED_LoadPersistent) {
|
||||
Cdm::kPersistentLicense, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the persistent session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after closing it.
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
@@ -861,7 +977,7 @@ TEST_F(CdmTest, DISABLED_LoadPersistent) {
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
g_host->Reset();
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
@@ -877,12 +993,12 @@ TEST_F(CdmTest, DISABLED_LoadWillFireExpiration) {
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
ASSERT_EQ(Cdm::kSuccess, cdm_->load(session_id));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Let the key expire, make sure we get a key status update.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRenewal, _))
|
||||
.Times(AtLeast(1));
|
||||
g_host->ElapseTime(kOfflineLicenseDurationMs);
|
||||
@@ -897,7 +1013,7 @@ TEST_F(CdmTest, DISABLED_PerOriginLoadPersistent) {
|
||||
Cdm::kPersistentLicense, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update and close the persistent session.
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
Cdm::Status status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
@@ -916,7 +1032,7 @@ TEST_F(CdmTest, DISABLED_PerOriginLoadPersistent) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// Should not be able to load from another origin.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
status = other_cdm->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
@@ -931,8 +1047,8 @@ TEST_F(CdmTest, DISABLED_LoadUsageRecord) {
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
Cdm::Status status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -941,7 +1057,7 @@ TEST_F(CdmTest, DISABLED_LoadUsageRecord) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -949,7 +1065,7 @@ TEST_F(CdmTest, DISABLED_LoadUsageRecord) {
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -959,7 +1075,7 @@ TEST_F(CdmTest, DISABLED_LoadUsageRecord) {
|
||||
status = cdm_->close(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
g_host->Reset();
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
@@ -974,8 +1090,8 @@ TEST_F(CdmTest, DISABLED_DestroyUsageRecord) {
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
Cdm::Status status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -984,7 +1100,7 @@ TEST_F(CdmTest, DISABLED_DestroyUsageRecord) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -992,7 +1108,7 @@ TEST_F(CdmTest, DISABLED_DestroyUsageRecord) {
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->deleteUsageRecord(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1009,8 +1125,8 @@ TEST_F(CdmTest, DISABLED_DestroyAllUsageRecords) {
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
Cdm::Status status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1019,7 +1135,7 @@ TEST_F(CdmTest, DISABLED_DestroyAllUsageRecords) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1027,7 +1143,7 @@ TEST_F(CdmTest, DISABLED_DestroyAllUsageRecords) {
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->deleteAllUsageRecords();
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1044,8 +1160,8 @@ TEST_F(CdmTest, DISABLED_ListUsageRecords) {
|
||||
Cdm::kPersistentUsageRecord, Cdm::kCenc, &session_id, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
Cdm::Status status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
Cdm::Status status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1054,7 +1170,7 @@ TEST_F(CdmTest, DISABLED_ListUsageRecords) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
// There should be no usable keys after loading this session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1062,7 +1178,7 @@ TEST_F(CdmTest, DISABLED_ListUsageRecords) {
|
||||
|
||||
// Should be able to load the session again after recreating the CDM.
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
|
||||
std::vector<std::string> ksids;
|
||||
@@ -1078,7 +1194,7 @@ TEST_F(CdmTest, DISABLED_ListUsageRecords) {
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, LoadBogus) {
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(_)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(_, _)).Times(0);
|
||||
Cdm::Status status = cdm_->load(kBogusSessionId);
|
||||
EXPECT_EQ(Cdm::kSessionNotFound, status);
|
||||
}
|
||||
@@ -1100,7 +1216,7 @@ TEST_F(CdmTest, GetKeyStatuses) {
|
||||
EXPECT_EQ(expected_key_id, map.begin()->first);
|
||||
|
||||
// Let the key expire.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRenewal, _)).Times(
|
||||
AtLeast(1));
|
||||
g_host->ElapseTime(kExpirationTestDelayMs);
|
||||
@@ -1131,7 +1247,7 @@ TEST_F(CdmTest, GetExpiration) {
|
||||
int64_t original_expiration = expiration;
|
||||
|
||||
// Let the key expire.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRenewal, _)).Times(
|
||||
AtLeast(1));
|
||||
g_host->ElapseTime(kExpirationTestDelayMs);
|
||||
@@ -1159,7 +1275,7 @@ TEST_F(CdmTest, DISABLED_Remove) {
|
||||
|
||||
// Remove the session. This causes a release message to be generated.
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
Cdm::Status status = cdm_->remove(session_id);
|
||||
@@ -1179,7 +1295,7 @@ TEST_F(CdmTest, DISABLED_Remove) {
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onRemoveComplete(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1214,7 +1330,7 @@ TEST_F(CdmTest, DISABLED_RemoveUsageRecord) {
|
||||
|
||||
// Remove the session. This causes a release message to be generated.
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
Cdm::Status status = cdm_->remove(session_id);
|
||||
@@ -1234,7 +1350,7 @@ TEST_F(CdmTest, DISABLED_RemoveUsageRecord) {
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onRemoveComplete(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1251,7 +1367,7 @@ TEST_F(CdmTest, DISABLED_RemoveIncomplete) {
|
||||
|
||||
// Remove the session. This causes a release message to be generated.
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
Cdm::Status status = cdm_->remove(session_id);
|
||||
@@ -1269,7 +1385,7 @@ TEST_F(CdmTest, DISABLED_RemoveIncomplete) {
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
|
||||
// Load the partially removed session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1282,7 +1398,7 @@ TEST_F(CdmTest, DISABLED_RemoveIncomplete) {
|
||||
|
||||
// Remove the session again to fire the release message.
|
||||
message.clear();
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
status = cdm_->remove(session_id);
|
||||
@@ -1296,9 +1412,9 @@ TEST_F(CdmTest, DISABLED_RemoveIncomplete) {
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onRemoveComplete(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1315,7 +1431,7 @@ TEST_F(CdmTest, DISABLED_RemoveUsageRecordIncomplete) {
|
||||
|
||||
// Remove the session. This causes a release message to be generated.
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
Cdm::Status status = cdm_->remove(session_id);
|
||||
@@ -1333,7 +1449,7 @@ TEST_F(CdmTest, DISABLED_RemoveUsageRecordIncomplete) {
|
||||
ASSERT_NO_FATAL_FAILURE(RecreateCdm(true /* privacy_mode */));
|
||||
|
||||
// Load the partially removed session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).Times(0);
|
||||
status = cdm_->load(session_id);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
@@ -1341,7 +1457,7 @@ TEST_F(CdmTest, DISABLED_RemoveUsageRecordIncomplete) {
|
||||
|
||||
// Remove the session again to fire a release message.
|
||||
message.clear();
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRelease, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
status = cdm_->remove(session_id);
|
||||
@@ -1360,9 +1476,9 @@ TEST_F(CdmTest, DISABLED_RemoveUsageRecordIncomplete) {
|
||||
g_license_server, message, &response));
|
||||
|
||||
// Update the session.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id)).Times(0);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, _)).Times(0);
|
||||
EXPECT_CALL(*this, onRemoveComplete(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
status = updateWithRetry(session_id, response);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1397,9 +1513,9 @@ TEST_F(CdmTest, RequestPersistentLicenseWithWrongInitData) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _))
|
||||
.WillOnce(SaveArg<2>(&message));
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1418,10 +1534,10 @@ TEST_F(CdmTest, DISABLED_RequestTemporaryLicenseWithWrongInitData) {
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc,
|
||||
kCencPersistentInitData);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _))
|
||||
.WillOnce(SaveArg<2>(&message));
|
||||
status =
|
||||
generateRequestWithRetry(session_id, Cdm::kCenc, kCencPersistentInitData);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1431,8 +1547,8 @@ TEST_F(CdmTest, DISABLED_RequestTemporaryLicenseWithWrongInitData) {
|
||||
g_license_server, message, &response));
|
||||
|
||||
// This license should not be accepted.
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
status = cdm_->update(session_id, response);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, false));
|
||||
status = updateWithRetry(session_id, response);
|
||||
EXPECT_EQ(Cdm::kRangeError, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -1524,9 +1640,9 @@ TEST_F(CdmTest, SetAppParameters) {
|
||||
|
||||
// Send a generate request to ensure the parameter is in the message.
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).WillOnce(
|
||||
SaveArg<2>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _))
|
||||
.WillOnce(SaveArg<2>(&message));
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
EXPECT_TRUE(!message.empty() && message.find(kValue) != std::string::npos);
|
||||
Mock::VerifyAndClear(this);
|
||||
@@ -1583,6 +1699,99 @@ TEST_F(CdmTest, SetVideoResolutionOverflow) {
|
||||
cdm_->close(session_id);
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, GetStatusForHdcpResolution) {
|
||||
// Unfortunately, since we cannot mock the HDCP state, we cannot validate
|
||||
// the validity of the values returned here, only that meaningful values are
|
||||
// returned.
|
||||
Cdm::KeyStatus key_status;
|
||||
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->getStatusForHdcpVersion(Cdm::kHdcp1_x, &key_status));
|
||||
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
|
||||
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_0, &key_status));
|
||||
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
|
||||
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_1, &key_status));
|
||||
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
|
||||
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->getStatusForHdcpVersion(Cdm::kHdcp2_2, &key_status));
|
||||
EXPECT_THAT(key_status, AnyOf(Cdm::kUsable, Cdm::kOutputRestricted));
|
||||
}
|
||||
|
||||
TEST_F(CdmTest, HandlesKeyRotationWithOnlyOneLicenseRequest) {
|
||||
std::string session_id;
|
||||
|
||||
// TODO(b/77152154):
|
||||
// The CreateSessionAndX helpers need to be reworked so this function can use
|
||||
// them.
|
||||
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->setServiceCertificate(g_license_service_certificate));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->createSession(Cdm::kTemporary, &session_id));
|
||||
|
||||
// Generate a license request for the 1st entitlement init data.
|
||||
std::string license_request;
|
||||
{
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _))
|
||||
.WillOnce(SaveArg<2>(&license_request));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
generateRequestWithRetry(session_id,
|
||||
Cdm::kCenc,
|
||||
kCencEntitlementInitData1));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
// Send the request to the license server and receive the license response.
|
||||
std::string license_response;
|
||||
FetchLicense(g_license_server, license_request, &license_response);
|
||||
|
||||
// Update the session with the new keys.
|
||||
{
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
updateWithRetry(session_id, license_response));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
// Set up decrypt input and output.
|
||||
Cdm::InputBuffer input;
|
||||
input.data = kInput.data();
|
||||
input.data_length = kInput.size();
|
||||
input.encryption_scheme = Cdm::kAesCtr;
|
||||
input.pattern = kPatternNone;
|
||||
|
||||
Cdm::OutputBuffer output;
|
||||
std::vector<uint8_t> output_buffer(input.data_length);
|
||||
output.data = &(output_buffer[0]);
|
||||
output.data_length = output_buffer.size();
|
||||
|
||||
// Attempt decrypt with a key from the first license.
|
||||
input.key_id = kKeyIdEntitlement1.data();
|
||||
input.key_id_length = kKeyIdEntitlement1.size();
|
||||
input.iv = kIvEntitlement1.data();
|
||||
input.iv_length = kIvEntitlement1.size();
|
||||
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(input, output));
|
||||
EXPECT_EQ(kOutputEntitlement1, output_buffer);
|
||||
|
||||
// Load the second entitlement license using the first. This should not
|
||||
// require any server roundtrip.
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->load(session_id, Cdm::kCenc, kCencEntitlementInitData2));
|
||||
|
||||
// Attempt decrypt with a key from the second license.
|
||||
input.key_id = kKeyIdEntitlement2.data();
|
||||
input.key_id_length = kKeyIdEntitlement2.size();
|
||||
input.iv = kIvEntitlement2.data();
|
||||
input.iv_length = kIvEntitlement2.size();
|
||||
ASSERT_EQ(Cdm::kSuccess, cdm_->decrypt(input, output));
|
||||
EXPECT_EQ(kOutputEntitlement2, output_buffer);
|
||||
}
|
||||
|
||||
// TODO(http://b/37286053): Fix this test.
|
||||
TEST_P(CdmTestWithDecryptParam, DecryptToClearBuffer) {
|
||||
DecryptParam param = GetParam();
|
||||
@@ -1695,7 +1904,7 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1704,7 +1913,7 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
|
||||
ASSERT_FALSE(reply.empty());
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
status = cdm_->update(session_id, reply);
|
||||
status = updateWithRetry(session_id, reply);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1715,8 +1924,8 @@ TEST_F(CdmIndividualizationTest, BasicFlow) {
|
||||
// Acquire a license and update the session.
|
||||
ASSERT_NO_FATAL_FAILURE(FetchLicense(
|
||||
g_license_server, message, &reply));
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id));
|
||||
status = cdm_->update(session_id, reply);
|
||||
EXPECT_CALL(*this, onKeyStatusesChange(session_id, true));
|
||||
status = updateWithRetry(session_id, reply);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
@@ -1738,7 +1947,7 @@ TEST_F(CdmIndividualizationTest, IsProvisioned) {
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1747,7 +1956,7 @@ TEST_F(CdmIndividualizationTest, IsProvisioned) {
|
||||
ASSERT_FALSE(reply.empty());
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
status = cdm_->update(session_id, reply);
|
||||
status = updateWithRetry(session_id, reply);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1772,7 +1981,7 @@ TEST_F(CdmIndividualizationTest, RemoveProvisioning) {
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
status = cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData);
|
||||
status = generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData);
|
||||
EXPECT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1781,7 +1990,7 @@ TEST_F(CdmIndividualizationTest, RemoveProvisioning) {
|
||||
ASSERT_FALSE(reply.empty());
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
status = cdm_->update(session_id, reply);
|
||||
status = updateWithRetry(session_id, reply);
|
||||
ASSERT_EQ(Cdm::kSuccess, status);
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
@@ -1807,7 +2016,7 @@ TEST_F(CdmIndividualizationTest, WillNotSendRequestTwice) {
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Create a second session.
|
||||
@@ -1817,7 +2026,7 @@ TEST_F(CdmIndividualizationTest, WillNotSendRequestTwice) {
|
||||
// Should not get another individualization request.
|
||||
EXPECT_CALL(*this, onMessage(_, _, _)).Times(0);
|
||||
ASSERT_EQ(Cdm::kDeferred,
|
||||
cdm_->generateRequest(session_id2, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id2, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Complete the provisioning request, should generate requests for both
|
||||
@@ -1827,7 +2036,7 @@ TEST_F(CdmIndividualizationTest, WillNotSendRequestTwice) {
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onMessage(session_id2, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onDeferredComplete(session_id2, Cdm::kSuccess)).Times(1);
|
||||
EXPECT_EQ(Cdm::kSuccess, cdm_->update(session_id, reply));
|
||||
EXPECT_EQ(Cdm::kSuccess, updateWithRetry(session_id, reply));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
@@ -1847,7 +2056,7 @@ TEST_F(CdmIndividualizationTest,
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Create a second session, don't call generateRequest for it.
|
||||
@@ -1861,13 +2070,13 @@ TEST_F(CdmIndividualizationTest,
|
||||
EXPECT_CALL(*this, onMessage(session_id, Cdm::kLicenseRequest, _)).Times(1);
|
||||
EXPECT_CALL(*this, onMessage(session_id2, Cdm::kLicenseRequest, _)).Times(0);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
EXPECT_EQ(Cdm::kSuccess, cdm_->update(session_id, reply));
|
||||
EXPECT_EQ(Cdm::kSuccess, updateWithRetry(session_id, reply));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// We should get a license message for the second session.
|
||||
EXPECT_CALL(*this, onMessage(session_id2, Cdm::kLicenseRequest, _)).Times(1);
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id2, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id2, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
@@ -1885,8 +2094,8 @@ TEST_F(CdmIndividualizationTest, PropagatesErrorsInUpdate) {
|
||||
std::string message;
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
ASSERT_EQ(Cdm::kSuccess, cdm_->generateRequest(session_id, Cdm::kCenc,
|
||||
kInvalidCencInitData));
|
||||
ASSERT_EQ(Cdm::kSuccess, generateRequestWithRetry(session_id, Cdm::kCenc,
|
||||
kInvalidCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Complete the provisioning request, should get an error call.
|
||||
@@ -1894,7 +2103,7 @@ TEST_F(CdmIndividualizationTest, PropagatesErrorsInUpdate) {
|
||||
ASSERT_FALSE(reply.empty());
|
||||
EXPECT_CALL(*this, onMessage(_, _, _)).Times(0);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
EXPECT_EQ(Cdm::kNotSupported, cdm_->update(session_id, reply));
|
||||
EXPECT_EQ(Cdm::kNotSupported, updateWithRetry(session_id, reply));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
@@ -1913,15 +2122,14 @@ TEST_F(CdmIndividualizationTest, OnlyPropagatesErrorsForThisSession) {
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Create another session that will cause an error.
|
||||
std::string session_id_2;
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->createSession(Cdm::kTemporary, &session_id_2));
|
||||
ASSERT_EQ(Cdm::kDeferred, cdm_->generateRequest(session_id_2, Cdm::kCenc,
|
||||
kInvalidCencInitData));
|
||||
ASSERT_EQ(Cdm::kSuccess, cdm_->createSession(Cdm::kTemporary, &session_id_2));
|
||||
ASSERT_EQ(Cdm::kDeferred, generateRequestWithRetry(session_id_2, Cdm::kCenc,
|
||||
kInvalidCencInitData));
|
||||
|
||||
// Complete the provisioning request, should succeed, but get an error
|
||||
// callback.
|
||||
@@ -1931,7 +2139,7 @@ TEST_F(CdmIndividualizationTest, OnlyPropagatesErrorsForThisSession) {
|
||||
EXPECT_CALL(*this, onMessage(session_id_2, _, _)).Times(0);
|
||||
EXPECT_CALL(*this, onDeferredComplete(session_id_2, Cdm::kNotSupported))
|
||||
.Times(1);
|
||||
EXPECT_EQ(Cdm::kSuccess, cdm_->update(session_id, reply));
|
||||
EXPECT_EQ(Cdm::kSuccess, updateWithRetry(session_id, reply));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
@@ -1962,7 +2170,7 @@ TEST_F(CdmIndividualizationTest, DISABLED_WorksWithLoad) {
|
||||
// Because we are now provisioned with a new key, we can't load the session,
|
||||
// but we will still be provisioned.
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
EXPECT_EQ(Cdm::kUnexpectedError, cdm_->update(session_id, reply));
|
||||
EXPECT_EQ(Cdm::kUnexpectedError, updateWithRetry(session_id, reply));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Create a second session, we should be previsioned at this point.
|
||||
@@ -1970,7 +2178,7 @@ TEST_F(CdmIndividualizationTest, DISABLED_WorksWithLoad) {
|
||||
ASSERT_EQ(Cdm::kSuccess, cdm_->createSession(Cdm::kTemporary, &session_id2));
|
||||
EXPECT_CALL(*this, onMessage(session_id2, Cdm::kLicenseRequest, _)).Times(1);
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id2, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id2, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
@@ -1989,13 +2197,13 @@ TEST_F(CdmIndividualizationTest, WillResendOnProvisioningError) {
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Fail to provision the device.
|
||||
EXPECT_CALL(*this, onMessage(_, _, _)).Times(0);
|
||||
EXPECT_CALL(*this, onDeferredComplete(_, _)).Times(0);
|
||||
EXPECT_EQ(Cdm::kUnexpectedError, cdm_->update(session_id, ""));
|
||||
EXPECT_EQ(Cdm::kUnexpectedError, updateWithRetry(session_id, ""));
|
||||
Mock::VerifyAndClear(this);
|
||||
|
||||
// Should get another individualization request.
|
||||
@@ -2005,7 +2213,7 @@ TEST_F(CdmIndividualizationTest, WillResendOnProvisioningError) {
|
||||
EXPECT_CALL(*this, onDirectIndividualizationRequest(session_id_2, _))
|
||||
.WillOnce(SaveArg<1>(&message));
|
||||
ASSERT_EQ(Cdm::kSuccess,
|
||||
cdm_->generateRequest(session_id_2, Cdm::kCenc, kCencInitData));
|
||||
generateRequestWithRetry(session_id_2, Cdm::kCenc, kCencInitData));
|
||||
Mock::VerifyAndClear(this);
|
||||
}
|
||||
|
||||
|
||||
@@ -51,13 +51,13 @@ int main(int argc, char** argv) {
|
||||
FILE* outfile;
|
||||
outfile = fopen("danger_do_not_use.bin", "w");
|
||||
if (outfile == NULL) { return 0; }
|
||||
if (fwrite(wvcdm_test_auth::kKeybox, 1,
|
||||
wvcdm_test_auth::kKeyboxSize, outfile) != 128) {
|
||||
if (fwrite(&wvcdm_test_auth::kValidKeybox01, 1,
|
||||
sizeof(wvcdm_test_auth::kValidKeybox01), outfile) != 128) {
|
||||
fclose(outfile);
|
||||
return 0;
|
||||
}
|
||||
if (fwrite(wvcdm_test_auth::kKeyboxValid02, 1,
|
||||
wvcdm_test_auth::kKeyboxSize, outfile) != 128) {
|
||||
if (fwrite(&wvcdm_test_auth::kTestKeybox, 1,
|
||||
sizeof(wvcdm_test_auth::kTestKeybox), outfile) != 128) {
|
||||
fclose(outfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,18 +12,19 @@
|
||||
#include "cdm.h"
|
||||
#include "file_store.h"
|
||||
#include "level3_file_system.h"
|
||||
#include "override.h"
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
class OEMCrypto_Level3CETestFileSystem : public OEMCrypto_Level3FileSystem {
|
||||
public:
|
||||
OEMCrypto_Level3CETestFileSystem() {};
|
||||
~OEMCrypto_Level3CETestFileSystem() override {};
|
||||
ssize_t Read(const char *filename, void *buffer, size_t size) override;
|
||||
ssize_t Write(const char *filename, const void *buffer, size_t size) override;
|
||||
bool Exists(const char *filename) override;
|
||||
ssize_t FileSize(const char *filename) override;
|
||||
bool Remove(const char *filename) override;
|
||||
~OEMCrypto_Level3CETestFileSystem() OVERRIDE {};
|
||||
ssize_t Read(const char *filename, void *buffer, size_t size) OVERRIDE;
|
||||
ssize_t Write(const char *filename, const void *buffer, size_t size) OVERRIDE;
|
||||
bool Exists(const char *filename) OVERRIDE;
|
||||
ssize_t FileSize(const char *filename) OVERRIDE;
|
||||
bool Remove(const char *filename) OVERRIDE;
|
||||
|
||||
private:
|
||||
static std::map<std::string, std::string> files_;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "level3.h"
|
||||
|
||||
#include "level3_file_system_ce_test.h"
|
||||
#include "level3_file_system_factory.h"
|
||||
|
||||
namespace wvoec3 {
|
||||
|
||||
Reference in New Issue
Block a user