Combined Decrypt Calls
(This is a merge of http://go/wvgerrit/93829, http://go/wvgerrit/93830, http://go/wvgerrit/93832, http://go/wvgerrit/93833, and http://go/wvgerrit/93834 from the Widevine repo.) This implements the CDM code changes necessary to take advantage of Combined Decrypt Calls on OEMCrypto v16. The result of this is that WVCryptoPlugin is much lighter now because it can pass the full sample down to the core in one call, but CryptoSession is heavier, as it now has to handle more complex fallback logic when devices can't handle multiple subsamples at once. This patch also removes support for the 'cens' and 'cbc1' schema, which are being dropped in OEMCrypto v16. This fixes an overflow in the code for handling those schemas by removing it entirely. This patch also fixes the "in chunks" legacy decrypt path to use larger chunk sizes on devices with higher resource rating tiers. Bug: 135285640 Bug: 123435824 Bug: 138584971 Bug: 139257871 Bug: 78289910 Bug: 149361893 Test: no new CE CDM Unit Test failures Test: Google Play plays Test: Netflix plays Test: no new GTS failures Change-Id: Ic4952c9fa3bc7fd5ed08698e88254380a7a18514
This commit is contained in:
@@ -258,8 +258,9 @@ class CdmEngine {
|
||||
|
||||
// Decryption and key related methods
|
||||
// Accept encrypted buffer and return decrypted data.
|
||||
virtual CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters);
|
||||
virtual CdmResponseType DecryptV16(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmDecryptionParametersV16& parameters);
|
||||
|
||||
// Generic crypto operations - provides basic crypto operations that an
|
||||
// application can use outside of content stream processing
|
||||
|
||||
@@ -251,12 +251,17 @@ class CdmEngineMetricsImpl : public T {
|
||||
return status;
|
||||
}
|
||||
|
||||
CdmResponseType Decrypt(const CdmSessionId& session_id,
|
||||
const CdmDecryptionParameters& parameters) override {
|
||||
CdmResponseType DecryptV16(
|
||||
const CdmSessionId& session_id,
|
||||
const CdmDecryptionParametersV16& parameters) override {
|
||||
size_t total_size = 0;
|
||||
for (const CdmDecryptionSample& sample : parameters.samples) {
|
||||
total_size += sample.encrypt_buffer_length;
|
||||
}
|
||||
|
||||
CdmResponseType sts;
|
||||
M_TIME(sts = T::Decrypt(session_id, parameters), metrics_,
|
||||
cdm_engine_decrypt_, sts,
|
||||
metrics::Pow2Bucket(parameters.encrypt_length));
|
||||
M_TIME(sts = T::DecryptV16(session_id, parameters), metrics_,
|
||||
cdm_engine_decrypt_, sts, metrics::Pow2Bucket(total_size));
|
||||
return sts;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ class CdmSession {
|
||||
virtual CdmResponseType QueryOemCryptoSessionId(CdmQueryMap* query_response);
|
||||
|
||||
// Decrypt() - Accept encrypted buffer and return decrypted data.
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& parameters);
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParametersV16& parameters);
|
||||
|
||||
// License renewal
|
||||
// GenerateRenewalRequest() - Construct valid renewal request for the current
|
||||
|
||||
@@ -36,7 +36,6 @@ class ContentKeySession : public KeySession {
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) override;
|
||||
|
||||
OEMCryptoResult LoadEntitledContentKeys(
|
||||
@@ -50,16 +49,15 @@ class ContentKeySession : public KeySession {
|
||||
|
||||
// Decrypt for ContentKeySession
|
||||
OEMCryptoResult Decrypt(
|
||||
const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc& buffer_descriptor, size_t additional_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) override;
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) override;
|
||||
|
||||
protected:
|
||||
virtual OEMCryptoResult LoadKeysAsLicenseType(
|
||||
const std::string& message, const std::string& signature,
|
||||
const std::string& mac_key_iv, const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token, CdmCipherMode* cipher_mode,
|
||||
const std::string& provider_session_token,
|
||||
const std::string& srm_requirement, OEMCrypto_LicenseType license_type);
|
||||
|
||||
CryptoSessionId oec_session_id_;
|
||||
|
||||
@@ -156,7 +156,7 @@ class CryptoSession {
|
||||
const std::string& wrapped_key);
|
||||
|
||||
// Media data path
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParameters& params);
|
||||
virtual CdmResponseType Decrypt(const CdmDecryptionParametersV16& params);
|
||||
|
||||
virtual bool IsAntiRollbackHwPresent();
|
||||
|
||||
@@ -300,6 +300,7 @@ class CryptoSession {
|
||||
CdmResponseType GetSystemIdInternal(uint32_t* system_id);
|
||||
CdmResponseType GenerateRsaSignature(const std::string& message,
|
||||
std::string* signature);
|
||||
bool GetMaxSubsampleRegionSize(size_t* max);
|
||||
|
||||
bool SetDestinationBufferType();
|
||||
|
||||
@@ -314,17 +315,24 @@ class CryptoSession {
|
||||
CdmEncryptionAlgorithm algorithm);
|
||||
size_t GenericEncryptionBlockSize(CdmEncryptionAlgorithm algorithm);
|
||||
|
||||
// These methods are used when a subsample exceeds the maximum buffer size
|
||||
// that the device can handle.
|
||||
OEMCryptoResult CopyBufferInChunks(
|
||||
const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc buffer_descriptor);
|
||||
OEMCryptoResult DecryptInChunks(
|
||||
const CdmDecryptionParameters& params,
|
||||
const OEMCrypto_DestBufferDesc& full_buffer_descriptor,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor,
|
||||
size_t max_chunk_size);
|
||||
static void IncrementIV(uint64_t increase_by, std::vector<uint8_t>* iv_out);
|
||||
// These methods fall back into each other in the order given, depending on
|
||||
// how much data they were given and how much data OEMCrypto can accept in one
|
||||
// call.
|
||||
OEMCryptoResult DecryptMultipleSamples(
|
||||
const std::vector<OEMCrypto_SampleDescription>& samples,
|
||||
CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern);
|
||||
OEMCryptoResult DecryptSample(
|
||||
const OEMCrypto_SampleDescription& sample, CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern);
|
||||
OEMCryptoResult LegacyDecrypt(
|
||||
const OEMCrypto_SampleDescription& sample, CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern);
|
||||
OEMCryptoResult LegacyCopyBufferInChunks(
|
||||
const OEMCrypto_SampleDescription& sample, size_t max_chunk_size);
|
||||
OEMCryptoResult LegacyDecryptInChunks(
|
||||
const OEMCrypto_SampleDescription& sample, CdmCipherMode cipher_mode,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern, size_t max_chunk_size);
|
||||
|
||||
// These methods should be used to take the various CryptoSession mutexes in
|
||||
// preference to taking the mutexes directly.
|
||||
@@ -420,7 +428,6 @@ class CryptoSession {
|
||||
std::string request_id_;
|
||||
static std::atomic<uint64_t> request_id_index_source_;
|
||||
|
||||
CdmCipherMode cipher_mode_;
|
||||
uint32_t api_version_;
|
||||
|
||||
// In order to avoid creating a deadlock if instantiation needs to take any
|
||||
|
||||
@@ -30,7 +30,6 @@ class EntitlementKeySession : public ContentKeySession {
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) override;
|
||||
OEMCryptoResult LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& keys) override;
|
||||
|
||||
@@ -32,16 +32,14 @@ class KeySession {
|
||||
const std::string& mac_key,
|
||||
const std::vector<CryptoKey>& keys,
|
||||
const std::string& provider_session_token,
|
||||
CdmCipherMode* cipher_mode,
|
||||
const std::string& srm_requirement) = 0;
|
||||
virtual OEMCryptoResult LoadEntitledContentKeys(
|
||||
const std::vector<CryptoKey>& keys) = 0;
|
||||
virtual OEMCryptoResult SelectKey(const std::string& key_id,
|
||||
CdmCipherMode cipher_mode) = 0;
|
||||
virtual OEMCryptoResult Decrypt(
|
||||
const CdmDecryptionParameters& params,
|
||||
OEMCrypto_DestBufferDesc& buffer_descriptor, size_t additional_offset,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern_descriptor) = 0;
|
||||
const OEMCrypto_SampleDescription* samples, size_t samples_length,
|
||||
const OEMCrypto_CENCEncryptPatternDesc& pattern) = 0;
|
||||
|
||||
protected:
|
||||
metrics::CryptoMetrics* metrics_;
|
||||
|
||||
@@ -404,6 +404,10 @@ enum CdmResponseType {
|
||||
CORE_MESSAGE_NOT_FOUND = 350,
|
||||
LOAD_LICENSE_ERROR = 351,
|
||||
LOAD_RENEWAL_ERROR = 352,
|
||||
CANNOT_DECRYPT_ZERO_SAMPLES = 353,
|
||||
CANNOT_DECRYPT_ZERO_SUBSAMPLES = 354,
|
||||
SAMPLE_AND_SUBSAMPLE_SIZE_MISMATCH = 355,
|
||||
INVALID_IV_SIZE = 356,
|
||||
// Don't forget to add new values to
|
||||
// * core/test/test_printers.cpp.
|
||||
// * android/include/mapErrors-inl.h
|
||||
@@ -581,11 +585,13 @@ class CdmKeyAllowedUsage {
|
||||
bool valid_;
|
||||
};
|
||||
|
||||
// For schemes that do not use pattern encryption (cenc and cbc1), encrypt
|
||||
// and skip should be set to 0. For those that do (cens and cbcs), it is
|
||||
// recommended that encrypt+skip bytes sum to 10 and for cbcs that a 1:9
|
||||
// encrypt:skip ratio be used. See ISO/IEC DIS 23001-7, section 10.4.2 for
|
||||
// more information.
|
||||
// For schemes that do not use pattern encryption (cenc), encrypt and skip
|
||||
// must be set to 0. For those that do (cbcs), it is recommended that
|
||||
// encrypt+skip bytes sum to 10. See ISO/IEC DIS 23001-7, section 10.4.2 for
|
||||
// more information. For Widevine, we often use the pattern (1,0) to represent
|
||||
// "encrypt all blocks," but in content, the patterns (0,0) and (10,0) are more
|
||||
// common. Since we are constrained to use (0,0) for "do not use pattern
|
||||
// encryption" — as noted above — we commonly use (1,0) for this case instead.
|
||||
struct CdmCencPatternEncryptionDescriptor {
|
||||
size_t encrypt_blocks; // number of 16 byte blocks to decrypt
|
||||
size_t skip_blocks; // number of 16 byte blocks to leave in clear
|
||||
@@ -640,6 +646,119 @@ struct CdmDecryptionParameters {
|
||||
is_video(true) {}
|
||||
};
|
||||
|
||||
struct CdmDecryptionSubsample {
|
||||
size_t clear_bytes;
|
||||
size_t protected_bytes;
|
||||
// TODO(b/149524614): These fields are not necessary except for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
uint8_t flags;
|
||||
size_t block_offset;
|
||||
CdmDecryptionSubsample()
|
||||
: clear_bytes(0), protected_bytes(0), flags(0), block_offset(0) {}
|
||||
CdmDecryptionSubsample(size_t clear_param, size_t protected_param)
|
||||
: clear_bytes(clear_param),
|
||||
protected_bytes(protected_param),
|
||||
flags(0),
|
||||
block_offset(0) {}
|
||||
};
|
||||
|
||||
struct CdmDecryptionSample {
|
||||
const uint8_t* encrypt_buffer;
|
||||
size_t encrypt_buffer_length;
|
||||
void* decrypt_buffer;
|
||||
size_t decrypt_buffer_size;
|
||||
size_t decrypt_buffer_offset;
|
||||
std::vector<CdmDecryptionSubsample> subsamples;
|
||||
std::vector<uint8_t> iv;
|
||||
CdmDecryptionSample()
|
||||
: encrypt_buffer(nullptr),
|
||||
encrypt_buffer_length(0),
|
||||
decrypt_buffer(nullptr),
|
||||
decrypt_buffer_size(0),
|
||||
decrypt_buffer_offset(0),
|
||||
subsamples(),
|
||||
iv() {}
|
||||
CdmDecryptionSample(const uint8_t* encrypt_buffer_param,
|
||||
void* decrypt_buffer_param,
|
||||
size_t decrypt_buffer_offset_param, size_t length,
|
||||
const std::vector<uint8_t>& iv_param)
|
||||
: encrypt_buffer(encrypt_buffer_param),
|
||||
encrypt_buffer_length(length),
|
||||
decrypt_buffer(decrypt_buffer_param),
|
||||
decrypt_buffer_size(length),
|
||||
decrypt_buffer_offset(decrypt_buffer_offset_param),
|
||||
subsamples(),
|
||||
iv(iv_param) {}
|
||||
};
|
||||
|
||||
// TODO(b/149524614): This name is a temporary measure for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
struct CdmDecryptionParametersV16 {
|
||||
KeyId key_id;
|
||||
std::vector<CdmDecryptionSample> samples;
|
||||
bool is_secure;
|
||||
CdmCipherMode cipher_mode;
|
||||
bool is_video;
|
||||
CdmCencPatternEncryptionDescriptor pattern;
|
||||
// TODO(b/149524614): These field is not necessary except for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
bool observe_legacy_fields;
|
||||
CdmDecryptionParametersV16()
|
||||
: key_id(),
|
||||
samples(),
|
||||
is_secure(true),
|
||||
cipher_mode(kCipherModeCtr),
|
||||
is_video(true),
|
||||
pattern(),
|
||||
observe_legacy_fields(false) {}
|
||||
CdmDecryptionParametersV16(const KeyId& key_id_param)
|
||||
: key_id(key_id_param),
|
||||
samples(),
|
||||
is_secure(true),
|
||||
cipher_mode(kCipherModeCtr),
|
||||
is_video(true),
|
||||
pattern(),
|
||||
observe_legacy_fields(false) {}
|
||||
|
||||
// TODO(b/149524614): This method is a temporary measure for
|
||||
// backwards-compatibility while we are transitioning from the v15 API to the
|
||||
// v16 API.
|
||||
static CdmDecryptionParametersV16 from_v15(
|
||||
const CdmDecryptionParameters& v15_params) {
|
||||
CdmDecryptionParametersV16 new_params;
|
||||
new_params.key_id = *(v15_params.key_id);
|
||||
new_params.is_secure = v15_params.is_secure;
|
||||
new_params.cipher_mode = v15_params.cipher_mode;
|
||||
new_params.is_video = v15_params.is_video;
|
||||
new_params.pattern = v15_params.pattern_descriptor;
|
||||
new_params.observe_legacy_fields = true;
|
||||
|
||||
new_params.samples.emplace_back();
|
||||
CdmDecryptionSample& sample = new_params.samples.back();
|
||||
sample.encrypt_buffer = v15_params.encrypt_buffer;
|
||||
sample.encrypt_buffer_length = v15_params.encrypt_length;
|
||||
sample.decrypt_buffer = v15_params.decrypt_buffer;
|
||||
sample.decrypt_buffer_size = v15_params.decrypt_buffer_length;
|
||||
sample.decrypt_buffer_offset = v15_params.decrypt_buffer_offset;
|
||||
sample.iv = *(v15_params.iv);
|
||||
|
||||
sample.subsamples.emplace_back();
|
||||
CdmDecryptionSubsample& subsample = sample.subsamples.back();
|
||||
if (v15_params.is_encrypted) {
|
||||
subsample.protected_bytes = v15_params.encrypt_length;
|
||||
} else {
|
||||
subsample.clear_bytes = v15_params.encrypt_length;
|
||||
}
|
||||
subsample.flags = v15_params.subsample_flags;
|
||||
subsample.block_offset = v15_params.block_offset;
|
||||
|
||||
return new_params;
|
||||
}
|
||||
};
|
||||
|
||||
struct CdmKeyRequest {
|
||||
CdmKeyMessage message;
|
||||
CdmKeyRequestType type;
|
||||
|
||||
Reference in New Issue
Block a user