Skip to content

Commit

Permalink
(merge) media: Fix EME session type support rules
Browse files Browse the repository at this point in the history
Currently there's no way to differentiate the persistent session support
between software and hardware secure robustness for the same key system.
This is causing issues on platforms where software and hardware secure
pipeline uses totally different code paths.

This CL fixes this issue with the following changes:
- Remove EmeSessionTypeSupport and uses EmeConfigRule for consistency,
  simplicity and flexibility.
- Update all key system properties to use the new type.
- Fix WidevineKeySystemProperties::GetPersistentLicenseSessionSupport()
  to support returning the right rule based on different persistent
  session support.
- Add a new browser test to cover persistent session support for
  hardware secure Widevine.

(cherry picked from commit 1c3543f)

Bug: 1325152, b/186035558
Test: Added new browser test
Change-Id: Icd96da36db27e09878c5adea306dd8d48ce2aea6
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3638694
Commit-Queue: Kevin Marshall <kmarshall@chromium.org>
Auto-Submit: Xiaohan Wang <xhwang@chromium.org>
Reviewed-by: Kevin Marshall <kmarshall@chromium.org>
Reviewed-by: John Rummell <jrummell@chromium.org>
Reviewed-by: Yuchen Liu <yucliu@chromium.org>
Cr-Original-Commit-Position: refs/heads/main@{#1003926}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3655010
Commit-Queue: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/branch-heads/5060@{#192}
Cr-Branched-From: b83393d-refs/heads/main@{#1002911}
  • Loading branch information
xhwang-chromium authored and Chromium LUCI CQ committed May 23, 2022
1 parent d1d4e7a commit 069e507
Show file tree
Hide file tree
Showing 16 changed files with 240 additions and 198 deletions.
65 changes: 51 additions & 14 deletions chrome/browser/media/encrypted_media_supported_types_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,26 @@ const char16_t kUnexpectedResult16[] = u"unexpected result";
#define EXPECT_WV_PROPRIETARY EXPECT_UNSUPPORTED
#endif // BUILDFLAG(BUNDLE_WIDEVINE_CDM)

// For Widevine key system with software secure robustness, persistent license
// session is supported on Windows and Mac. On ChromeOS, it is supported when
// the protected media identifier permission is allowed. See
// kUnsafelyAllowProtectedMediaIdentifierForDomain used below.
#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
#define EXPECT_WV_SW_SECURE_PERSISTENT_SESSION EXPECT_WV
#else
#define EXPECT_WV_SW_SECURE_PERSISTENT_SESSION EXPECT_UNSUPPORTED
#endif

// For Widevine key system with hardware secure robustness, persistent license
// session is only supported on ChromeOS when the protected media identifier
// permission is allowed. See kUnsafelyAllowProtectedMediaIdentifierForDomain
// used below.
#if BUILDFLAG(IS_CHROMEOS_ASH)
#define EXPECT_WV_HW_SECURE_PERSISTENT_SESSION EXPECT_WV
#else
#define EXPECT_WV_HW_SECURE_PERSISTENT_SESSION EXPECT_UNSUPPORTED
#endif

} // namespace

class EncryptedMediaSupportedTypesTest : public InProcessBrowserTest {
Expand Down Expand Up @@ -348,9 +368,11 @@ class EncryptedMediaSupportedTypesTest : public InProcessBrowserTest {
}

std::string IsSessionTypeSupported(const std::string& key_system,
SessionType session_type) {
SessionType session_type,
const char* robustness = nullptr) {
return IsSupportedByKeySystem(key_system, kVideoWebMMimeType,
video_webm_codecs(), session_type);
video_webm_codecs(), session_type,
robustness);
}

std::string IsAudioRobustnessSupported(const std::string& key_system,
Expand Down Expand Up @@ -1218,18 +1240,8 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineTest, SessionType) {
EXPECT_WV(IsSessionTypeSupported(kWidevine, SessionType::kTemporary));

// Persistent license session support varies by platform.
auto result =
IsSessionTypeSupported(kWidevine, SessionType::kPersistentLicense);

#if BUILDFLAG(IS_CHROMEOS_ASH) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
// Persistent license session supported by Widevine key system on Windows and
// Mac. On ChromeOS, it is supported when the protected media identifier
// permission is allowed. See kUnsafelyAllowProtectedMediaIdentifierForDomain
// used above.
EXPECT_WV(result);
#else
EXPECT_UNSUPPORTED(result);
#endif
EXPECT_WV_SW_SECURE_PERSISTENT_SESSION(
IsSessionTypeSupported(kWidevine, SessionType::kPersistentLicense));
}

IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineTest, Robustness) {
Expand Down Expand Up @@ -1435,6 +1447,31 @@ IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineHwSecureTest,
#endif
}

IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineHwSecureTest,
SessionType) {
// Temporary session always supported.
EXPECT_WV(IsSessionTypeSupported(kWidevine, SessionType::kTemporary,
"SW_SECURE_CRYPTO"));
EXPECT_WV(IsSessionTypeSupported(kWidevine, SessionType::kTemporary,
"SW_SECURE_DECODE"));
EXPECT_WV(IsSessionTypeSupported(kWidevine, SessionType::kTemporary,
"HW_SECURE_CRYPTO"));
EXPECT_WV(IsSessionTypeSupported(kWidevine, SessionType::kTemporary,
"HW_SECURE_ALL"));

// Persistent session for software secure Widevine is platform specific.
EXPECT_WV_SW_SECURE_PERSISTENT_SESSION(IsSessionTypeSupported(
kWidevine, SessionType::kPersistentLicense, "SW_SECURE_CRYPTO"));
EXPECT_WV_SW_SECURE_PERSISTENT_SESSION(IsSessionTypeSupported(
kWidevine, SessionType::kPersistentLicense, "SW_SECURE_DECODE"));

// Persistent session for hardware secure Widevine is platform specific.
EXPECT_WV_HW_SECURE_PERSISTENT_SESSION(IsSessionTypeSupported(
kWidevine, SessionType::kPersistentLicense, "HW_SECURE_CRYPTO"));
EXPECT_WV_HW_SECURE_PERSISTENT_SESSION(IsSessionTypeSupported(
kWidevine, SessionType::kPersistentLicense, "HW_SECURE_ALL"));
}

IN_PROC_BROWSER_TEST_F(EncryptedMediaSupportedTypesWidevineHwSecureTest,
WidevineExperiment) {
EXPECT_UNSUPPORTED(
Expand Down
66 changes: 30 additions & 36 deletions chrome/renderer/media/chrome_key_systems.cc
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
#endif // BUILDFLAG(ENABLE_WIDEVINE)
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS) || BUILDFLAG(IS_WIN)

using media::CdmSessionType;
using media::EmeConfigRule;
using media::EmeFeatureSupport;
using media::EmeSessionTypeSupport;
using media::KeySystemProperties;
using media::KeySystemPropertiesVector;
using media::SupportedCodecs;
Expand Down Expand Up @@ -181,18 +182,13 @@ SupportedCodecs GetSupportedCodecs(const media::CdmCapability& capability) {
return supported_codecs;
}

// Returns persistent-license session support.
EmeSessionTypeSupport GetPersistentLicenseSupport(bool supported_by_the_cdm) {
// Returns whether persistent-license session can be supported.
bool CanSupportPersistentLicense() {
// Do not support persistent-license if the process cannot persist data.
// TODO(crbug.com/457487): Have a better plan on this. See bug for details.
if (ChromeRenderThreadObserver::is_incognito_process()) {
DVLOG(2) << __func__ << ": Not supported in incognito process.";
return EmeSessionTypeSupport::NOT_SUPPORTED;
}

if (!supported_by_the_cdm) {
DVLOG(2) << __func__ << ": Not supported by the CDM.";
return EmeSessionTypeSupport::NOT_SUPPORTED;
return false;
}

// On ChromeOS, platform verification is similar to CDM host verification.
Expand All @@ -206,48 +202,52 @@ EmeSessionTypeSupport GetPersistentLicenseSupport(bool supported_by_the_cdm) {
// support persistent-license.
if (!cdm_host_verification_potentially_supported) {
DVLOG(2) << __func__ << ": Not supported without CDM host verification.";
return EmeSessionTypeSupport::NOT_SUPPORTED;
return false;
}

#if BUILDFLAG(IS_CHROMEOS)
// On ChromeOS, platform verification (similar to CDM host verification)
// requires identifier to be allowed.
// TODO(jrummell): Currently the ChromeOS CDM does not require storage ID
// to support persistent license. Update this logic when the new CDM requires
// storage ID.
return EmeSessionTypeSupport::SUPPORTED_WITH_IDENTIFIER;
return true;
#elif BUILDFLAG(ENABLE_CDM_STORAGE_ID)
// On other platforms, we require storage ID to support persistent license.
return EmeSessionTypeSupport::SUPPORTED;
return true;
#else
// Storage ID not implemented, so no support for persistent license.
DVLOG(2) << __func__ << ": Not supported without CDM storage ID.";
return EmeSessionTypeSupport::NOT_SUPPORTED;
return false;
#endif // BUILDFLAG(IS_CHROMEOS)
}

// Remove `kPersistentLicense` support if it's not supported by the platform.
base::flat_set<CdmSessionType> UpdatePersistentLicenseSupport(
const base::flat_set<CdmSessionType> session_types) {
auto updated_session_types = session_types;
if (!CanSupportPersistentLicense())
updated_session_types.erase(CdmSessionType::kPersistentLicense);
return updated_session_types;
}

bool AddWidevine(const media::mojom::KeySystemCapabilityPtr& capability,
KeySystemPropertiesVector* key_systems) {
// Codecs and encryption schemes.
SupportedCodecs codecs = media::EME_CODEC_NONE;
SupportedCodecs hw_secure_codecs = media::EME_CODEC_NONE;
base::flat_set<::media::EncryptionScheme> encryption_schemes;
base::flat_set<::media::EncryptionScheme> hw_secure_encryption_schemes;
bool cdm_supports_persistent_license = false;
base::flat_set<CdmSessionType> session_types;
base::flat_set<CdmSessionType> hw_secure_session_types;

if (capability->sw_secure_capability) {
codecs = GetSupportedCodecs(capability->sw_secure_capability.value());
encryption_schemes = capability->sw_secure_capability->encryption_schemes;
if (!base::Contains(capability->sw_secure_capability->session_types,
media::CdmSessionType::kTemporary)) {
session_types = UpdatePersistentLicenseSupport(
capability->sw_secure_capability->session_types);
if (!base::Contains(session_types, CdmSessionType::kTemporary)) {
DVLOG(1) << "Temporary sessions must be supported.";
return false;
}

cdm_supports_persistent_license =
base::Contains(capability->sw_secure_capability->session_types,
media::CdmSessionType::kPersistentLicense);

DVLOG(2) << "Software secure Widevine supported";
}

Expand All @@ -256,16 +256,12 @@ bool AddWidevine(const media::mojom::KeySystemCapabilityPtr& capability,
GetSupportedCodecs(capability->hw_secure_capability.value());
hw_secure_encryption_schemes =
capability->hw_secure_capability->encryption_schemes;
if (!base::Contains(capability->hw_secure_capability->session_types,
media::CdmSessionType::kTemporary)) {
hw_secure_session_types = UpdatePersistentLicenseSupport(
capability->hw_secure_capability->session_types);
if (!base::Contains(hw_secure_session_types, CdmSessionType::kTemporary)) {
DVLOG(1) << "Temporary sessions must be supported.";
return false;
}

// TODO(b/186035558): With a single flag we can't distinguish persistent
// session support between software and hardware CDMs. This should be
// fixed so that if there is both a software and a hardware CDM, persistent
// session support can be different between the versions.
DVLOG(2) << "Hardware secure Widevine supported";
}

Expand All @@ -286,9 +282,6 @@ bool AddWidevine(const media::mojom::KeySystemCapabilityPtr& capability,
}
#endif

auto persistent_license_support =
GetPersistentLicenseSupport(cdm_supports_persistent_license);

// Others.
auto persistent_state_support = EmeFeatureSupport::REQUESTABLE;
auto distinctive_identifier_support = EmeFeatureSupport::NOT_SUPPORTED;
Expand All @@ -297,9 +290,10 @@ bool AddWidevine(const media::mojom::KeySystemCapabilityPtr& capability,
#endif

key_systems->emplace_back(new cdm::WidevineKeySystemProperties(
codecs, encryption_schemes, hw_secure_codecs,
hw_secure_encryption_schemes, max_audio_robustness, max_video_robustness,
persistent_license_support, persistent_state_support,
codecs, std::move(encryption_schemes), std::move(session_types),
hw_secure_codecs, std::move(hw_secure_encryption_schemes),
std::move(hw_secure_session_types), max_audio_robustness,
max_video_robustness, persistent_state_support,
distinctive_identifier_support));
return true;
}
Expand Down
36 changes: 21 additions & 15 deletions chromecast/renderer/media/key_systems_cast.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "chromecast/chromecast_buildflags.h"
#include "chromecast/media/base/key_systems_common.h"
#include "components/cdm/renderer/android_key_systems.h"
#include "media/base/content_decryption_module.h"
#include "media/base/eme_constants.h"
#include "media/base/key_system_properties.h"
#include "media/media_buildflags.h"
Expand All @@ -21,11 +22,12 @@
#include "components/cdm/renderer/widevine_key_system_properties.h"
#endif

using ::media::CdmSessionType;
using ::media::EmeConfigRule;
using ::media::EmeFeatureSupport;
using ::media::EmeInitDataType;
using ::media::EmeMediaType;
using ::media::EmeSessionTypeSupport;
using ::media::EncryptionScheme;
using ::media::SupportedCodecs;

namespace chromecast {
Expand Down Expand Up @@ -86,9 +88,9 @@ class PlayReadyKeySystemProperties : public ::media::KeySystemProperties {
return EmeConfigRule::NOT_SUPPORTED;
}

EmeSessionTypeSupport GetPersistentLicenseSessionSupport() const override {
return persistent_license_support_ ? EmeSessionTypeSupport::SUPPORTED
: EmeSessionTypeSupport::NOT_SUPPORTED;
EmeConfigRule GetPersistentLicenseSessionSupport() const override {
return persistent_license_support_ ? EmeConfigRule::SUPPORTED
: EmeConfigRule::NOT_SUPPORTED;
}

EmeFeatureSupport GetPersistentStateSupport() const override {
Expand All @@ -99,8 +101,8 @@ class PlayReadyKeySystemProperties : public ::media::KeySystemProperties {
}

EmeConfigRule GetEncryptionSchemeConfigRule(
::media::EncryptionScheme encryption_scheme) const override {
if (encryption_scheme == ::media::EncryptionScheme::kCenc)
EncryptionScheme encryption_scheme) const override {
if (encryption_scheme == EncryptionScheme::kCenc)
return EmeConfigRule::SUPPORTED;
return EmeConfigRule::NOT_SUPPORTED;
}
Expand Down Expand Up @@ -170,17 +172,21 @@ void AddCmaKeySystems(
#if BUILDFLAG(ENABLE_WIDEVINE)
using Robustness = cdm::WidevineKeySystemProperties::Robustness;

base::flat_set<::media::EncryptionScheme> encryption_schemes = {
::media::EncryptionScheme::kCenc, ::media::EncryptionScheme::kCbcs};
const base::flat_set<EncryptionScheme> kEncryptionSchemes = {
EncryptionScheme::kCenc, EncryptionScheme::kCbcs};

const base::flat_set<CdmSessionType> kSessionTypes = {
CdmSessionType::kTemporary, CdmSessionType::kPersistentLicense};

key_systems_properties->emplace_back(new cdm::WidevineKeySystemProperties(
codecs, // Regular codecs.
encryption_schemes, // Encryption schemes.
codecs, // Hardware secure codecs.
encryption_schemes, // Hardware secure encryption schemes.
Robustness::HW_SECURE_CRYPTO, // Max audio robustness.
Robustness::HW_SECURE_ALL, // Max video robustness.
EmeSessionTypeSupport::SUPPORTED, // persistent-license.
codecs, // Regular codecs.
kEncryptionSchemes, // Encryption schemes.
kSessionTypes, // Session types.
codecs, // Hardware secure codecs.
kEncryptionSchemes, // Hardware secure encryption schemes.
kSessionTypes, // Hardware secure session types.
Robustness::HW_SECURE_CRYPTO, // Max audio robustness.
Robustness::HW_SECURE_ALL, // Max video robustness.
// Note: On Chromecast, all CDMs may have persistent state.
EmeFeatureSupport::ALWAYS_ENABLED, // Persistent state.
EmeFeatureSupport::ALWAYS_ENABLED)); // Distinctive identifier.
Expand Down

0 comments on commit 069e507

Please sign in to comment.