| // Copyright 2016 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| |
| #include "content/browser/media/cdm_registry_impl.h" |
| |
| #include <algorithm> |
| #include <string> |
| #include <vector> |
| |
| #include "base/base_paths.h" |
| #include "base/command_line.h" |
| #include "base/containers/contains.h" |
| #include "base/containers/flat_set.h" |
| #include "base/files/file_path.h" |
| #include "base/functional/callback_helpers.h" |
| #include "base/strings/string_split.h" |
| #include "base/strings/string_util.h" |
| #include "base/strings/utf_string_conversions.h" |
| #include "base/test/gmock_callback_support.h" |
| #include "base/test/gmock_move_support.h" |
| #include "base/test/mock_callback.h" |
| #include "base/test/scoped_feature_list.h" |
| #include "base/types/expected.h" |
| #include "base/version.h" |
| #include "content/browser/gpu/gpu_data_manager_impl.h" |
| #include "content/public/common/cdm_info.h" |
| #include "content/public/test/browser_task_environment.h" |
| #include "gpu/config/gpu_feature_info.h" |
| #include "media/base/cdm_capability.h" |
| #include "media/base/media_switches.h" |
| #include "media/base/video_codecs.h" |
| #include "media/cdm/cdm_type.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace content { |
| |
| namespace { |
| |
| using AudioCodec = media::AudioCodec; |
| using VideoCodec = media::VideoCodec; |
| using EncryptionScheme = media::EncryptionScheme; |
| using CdmSessionType = media::CdmSessionType; |
| using Robustness = CdmInfo::Robustness; |
| using base::test::RunOnceCallback; |
| using testing::_; |
| |
| const char kTestCdmName[] = "Test CDM"; |
| const char kAlternateCdmName[] = "Alternate CDM"; |
| const media::CdmType kTestCdmType{1234, 5678}; |
| const char kTestPath[] = "/aa/bb"; |
| const char kVersion1[] = "1.1.1.1"; |
| const char kVersion2[] = "1.1.1.2"; |
| const char kTestKeySystem[] = "com.example.somesystem"; |
| const char kOtherKeySystem[] = "com.example.othersystem"; |
| const int kObserver1 = 1; |
| const int kObserver2 = 2; |
| |
| #if BUILDFLAG(IS_WIN) |
| // 0x1234 is randomly picked as a non-software emulated vendor ID. |
| constexpr uint32_t kNonSoftwareEmulatedVendorId = 0x1234; |
| // 0x0000 is one of the software emulated vendor IDs. |
| constexpr uint32_t kSoftwareEmulatedVendorId = 0x0000; |
| #endif // BUILDFLAG(IS_WIN) |
| |
| // Helper function to convert a VideoCodecMap to a list of VideoCodec values |
| // so that they can be compared. VideoCodecProfiles are ignored. |
| std::vector<media::VideoCodec> VideoCodecMapToList( |
| const media::CdmCapability::VideoCodecMap& map) { |
| std::vector<media::VideoCodec> list; |
| for (const auto& [video_codec, ignore] : map) { |
| list.push_back(video_codec); |
| } |
| return list; |
| } |
| |
| #define EXPECT_STL_EQ(container, ...) \ |
| do { \ |
| EXPECT_THAT(container, ::testing::ElementsAre(__VA_ARGS__)); \ |
| } while (false) |
| |
| #define EXPECT_AUDIO_CODECS(...) \ |
| EXPECT_STL_EQ(cdm.capability->audio_codecs, __VA_ARGS__) |
| |
| #define EXPECT_VIDEO_CODECS(...) \ |
| EXPECT_STL_EQ(VideoCodecMapToList(cdm.capability->video_codecs), __VA_ARGS__) |
| |
| #define EXPECT_ENCRYPTION_SCHEMES(...) \ |
| EXPECT_STL_EQ(cdm.capability->encryption_schemes, __VA_ARGS__) |
| |
| #define EXPECT_SESSION_TYPES(...) \ |
| EXPECT_STL_EQ(cdm.capability->session_types, __VA_ARGS__) |
| |
| } // namespace |
| |
| // TODO(crbug.com/347991515): Add browser tests to test protected content id |
| // settings. |
| // For simplicity and to make failures easier to diagnose, this test uses |
| // std::string instead of base::FilePath and std::vector<std::string>. |
| class CdmRegistryImplTest : public testing::Test { |
| public: |
| CdmRegistryImplTest() = default; |
| ~CdmRegistryImplTest() override = default; |
| |
| void SetUp() final { |
| DVLOG(1) << __func__; |
| |
| auto* gpu_data_manager = GpuDataManagerImpl::GetInstance(); |
| |
| // Simulate GPU process initialization completing with GL unavailable. |
| gpu::GpuFeatureInfo gpu_feature_info = GetGpuFeatureInfoWithOneDisabled( |
| gpu::GpuFeatureType::GPU_FEATURE_TYPE_ACCELERATED_GL); |
| gpu_data_manager->UpdateGpuFeatureInfo(gpu_feature_info, std::nullopt); |
| |
| #if BUILDFLAG(IS_WIN) |
| // Simulate enabling direct composition. |
| gpu::GPUInfo gpu_info; |
| gpu_info.overlay_info.direct_composition = true; |
| |
| // Simulate non-software emulated GPU. Check out `gpu/config/gpu_info.cc` to |
| // see which vendor IDs are for the software emulated GPU. |
| gpu_info.gpu.vendor_id = kNonSoftwareEmulatedVendorId; |
| gpu_data_manager->UpdateGpuInfo(gpu_info, std::nullopt); |
| #endif // BUILDFLAG(IS_WIN) |
| |
| cdm_registry_.SetCapabilityCBForTesting(capability_cb_.Get()); |
| } |
| |
| void OnKeySystemCapabilitiesUpdated( |
| int observer_id, |
| base::OnceClosure done_cb, |
| KeySystemCapabilities key_system_capabilities) { |
| DVLOG(1) << __func__; |
| results_[observer_id].push_back(std::move(key_system_capabilities)); |
| std::move(done_cb).Run(); |
| } |
| |
| protected: |
| media::CdmCapability GetTestCdmCapability() { |
| return media::CdmCapability( |
| {media::AudioCodec::kVorbis}, |
| {{media::VideoCodec::kVP8, {}}, {media::VideoCodec::kVP9, {}}}, |
| {EncryptionScheme::kCenc}, |
| {CdmSessionType::kTemporary, CdmSessionType::kPersistentLicense}, |
| base::Version(kVersion1)); |
| } |
| |
| media::CdmCapability GetOtherCdmCapability() { |
| return media::CdmCapability( |
| {media::AudioCodec::kVorbis}, {{media::VideoCodec::kVP9, {}}}, |
| {EncryptionScheme::kCbcs}, {CdmSessionType::kTemporary}, |
| base::Version(kVersion1)); |
| } |
| |
| CdmInfo GetTestCdmInfo() { |
| return CdmInfo(kTestKeySystem, CdmInfo::Robustness::kSoftwareSecure, |
| GetTestCdmCapability(), |
| /*supports_sub_key_systems=*/true, kTestCdmName, |
| kTestCdmType, base::FilePath::FromUTF8Unsafe(kTestPath)); |
| } |
| |
| void Register(CdmInfo cdm_info) { |
| cdm_registry_.RegisterCdm(std::move(cdm_info)); |
| } |
| |
| void Register(const std::string& key_system, |
| std::optional<media::CdmCapability> capability, |
| Robustness robustness = Robustness::kSoftwareSecure) { |
| Register(CdmInfo(key_system, robustness, std::move(capability), |
| /*supports_sub_key_systems=*/true, kTestCdmName, |
| kTestCdmType, base::FilePath::FromUTF8Unsafe(kTestPath))); |
| } |
| |
| void RegisterForLazySoftwareSecureInitialization() { |
| // Register a CdmInfo without CdmCapability to allow lazy initialization. |
| Register(CdmInfo(kTestKeySystem, CdmInfo::Robustness::kSoftwareSecure, |
| std::nullopt, kTestCdmType)); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kSoftwareSecure); |
| ASSERT_TRUE(cdm_info); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| |
| void RegisterForLazyHardwareSecureInitialization() { |
| // Register a CdmInfo without CdmCapability to allow lazy initialization. |
| Register(CdmInfo(kTestKeySystem, CdmInfo::Robustness::kHardwareSecure, |
| std::nullopt, kTestCdmType)); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| ASSERT_TRUE(cdm_info); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| |
| bool IsRegistered(const std::string& name, const std::string& version) { |
| for (const auto& cdm : cdm_registry_.GetRegisteredCdms()) { |
| if (cdm.name == name && cdm.capability->version.GetString() == version) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| std::vector<std::string> GetVersions(const media::CdmType& cdm_type) { |
| std::vector<std::string> versions; |
| for (const auto& cdm : cdm_registry_.GetRegisteredCdms()) { |
| if (cdm.type == cdm_type) { |
| versions.push_back(cdm.capability->version.GetString()); |
| } |
| } |
| return versions; |
| } |
| |
| void GetKeySystemCapabilities(bool allow_hw_secure_capability_check = true) { |
| DVLOG(1) << __func__; |
| base::RunLoop run_loop; |
| capabilities_cb_sub_ = cdm_registry_.ObserveKeySystemCapabilities( |
| allow_hw_secure_capability_check, |
| base::BindRepeating( |
| &CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, run_loop.QuitClosure())); |
| run_loop.Run(); |
| } |
| |
| [[maybe_unused]] gpu::GpuFeatureInfo GetGpuFeatureInfoWithOneDisabled( |
| gpu::GpuFeatureType disabled_feature) { |
| gpu::GpuFeatureInfo gpu_feature_info; |
| for (auto& status : gpu_feature_info.status_values) { |
| status = gpu::GpuFeatureStatus::kGpuFeatureStatusEnabled; |
| } |
| gpu_feature_info.status_values[disabled_feature] = |
| gpu::GpuFeatureStatus::kGpuFeatureStatusDisabled; |
| return gpu_feature_info; |
| } |
| |
| void SelectHardwareSecureDecryption(bool enabled) { |
| const std::vector<base::test::FeatureRef> kHardwareSecureFeatures = { |
| media::kHardwareSecureDecryption, |
| media::kHardwareSecureDecryptionExperiment}; |
| const std::vector<base::test::FeatureRef> kNoFeatures = {}; |
| |
| auto enabled_features = enabled ? kHardwareSecureFeatures : kNoFeatures; |
| auto disabled_features = enabled ? kNoFeatures : kHardwareSecureFeatures; |
| scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features); |
| } |
| |
| #if BUILDFLAG(IS_ANDROID) |
| // On Android checking for key system support can be run on a separate |
| // thread. Disable this for testing. |
| void DisableMediaDrmQueryInSeparateProcess() { |
| scoped_feature_list_.InitAndDisableFeature( |
| media::kMediaDrmQueryInSeparateProcess); |
| } |
| #endif |
| |
| void ClearCapabilityTestOverride() { |
| cdm_registry_.SetCapabilityCBForTesting(base::NullCallback()); |
| } |
| |
| base::test::ScopedFeatureList scoped_feature_list_; |
| BrowserTaskEnvironment task_environment_; |
| |
| CdmRegistryImpl cdm_registry_; |
| base::MockCallback<CdmRegistryImpl::CapabilityCB> capability_cb_; |
| base::CallbackListSubscription capabilities_cb_sub_; |
| |
| // Map of "observer ID" to the list of updated KeySystemCapabilities. |
| std::map<int, std::vector<KeySystemCapabilities>> results_; |
| }; |
| |
| TEST_F(CdmRegistryImplTest, Register) { |
| Register(GetTestCdmInfo()); |
| |
| auto cdms = cdm_registry_.GetRegisteredCdms(); |
| ASSERT_EQ(1u, cdms.size()); |
| CdmInfo cdm = cdms[0]; |
| EXPECT_EQ(kTestCdmName, cdm.name); |
| EXPECT_EQ(kVersion1, cdm.capability->version.GetString()); |
| EXPECT_EQ(kTestPath, cdm.path.MaybeAsASCII()); |
| EXPECT_EQ(kTestCdmType, cdm.type); |
| EXPECT_AUDIO_CODECS(AudioCodec::kVorbis); |
| EXPECT_VIDEO_CODECS(VideoCodec::kVP8, VideoCodec::kVP9); |
| EXPECT_ENCRYPTION_SCHEMES(EncryptionScheme::kCenc); |
| EXPECT_SESSION_TYPES(CdmSessionType::kTemporary, |
| CdmSessionType::kPersistentLicense); |
| EXPECT_EQ(kTestKeySystem, cdm.key_system); |
| EXPECT_TRUE(cdm.supports_sub_key_systems); |
| EXPECT_EQ(cdm.robustness, CdmInfo::Robustness::kSoftwareSecure); |
| } |
| |
| TEST_F(CdmRegistryImplTest, ReRegister) { |
| auto cdm_info = GetTestCdmInfo(); |
| Register(cdm_info); |
| EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1)); |
| |
| // Now register same key system with different values. |
| cdm_info.supports_sub_key_systems = false; |
| Register(cdm_info); |
| |
| EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1)); |
| } |
| |
| TEST_F(CdmRegistryImplTest, MultipleVersions) { |
| auto cdm_info = GetTestCdmInfo(); |
| Register(cdm_info); |
| cdm_info.capability->version = base::Version(kVersion2); |
| Register(cdm_info); |
| |
| EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1)); |
| EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion2)); |
| |
| // The first inserted CdmInfo takes effect. |
| auto result = cdm_registry_.GetCdmInfo(kTestKeySystem, |
| CdmInfo::Robustness::kSoftwareSecure); |
| ASSERT_EQ(result->capability->version, base::Version(kVersion1)); |
| } |
| |
| TEST_F(CdmRegistryImplTest, NewVersionInsertedLast) { |
| auto cdm_info = GetTestCdmInfo(); |
| Register(cdm_info); |
| cdm_info.capability->version = base::Version(kVersion2); |
| Register(cdm_info); |
| |
| const std::vector<std::string> versions = GetVersions(kTestCdmType); |
| EXPECT_EQ(2u, versions.size()); |
| EXPECT_EQ(kVersion1, versions[0]); |
| EXPECT_EQ(kVersion2, versions[1]); |
| } |
| |
| TEST_F(CdmRegistryImplTest, DifferentNames) { |
| auto cdm_info = GetTestCdmInfo(); |
| Register(cdm_info); |
| cdm_info.name = kAlternateCdmName; |
| Register(cdm_info); |
| |
| EXPECT_TRUE(IsRegistered(kTestCdmName, kVersion1)); |
| EXPECT_TRUE(IsRegistered(kAlternateCdmName, kVersion1)); |
| } |
| |
| TEST_F(CdmRegistryImplTest, Profiles) { |
| Register(kTestKeySystem, |
| media::CdmCapability( |
| {AudioCodec::kVorbis}, |
| {{VideoCodec::kVP9, |
| media::VideoCodecInfo({media::VP9PROFILE_PROFILE0, |
| media::VP9PROFILE_PROFILE2})}}, |
| {EncryptionScheme::kCenc}, {CdmSessionType::kTemporary}, |
| base::Version(kVersion1))); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kSoftwareSecure); |
| CdmInfo& cdm = *cdm_info; |
| EXPECT_VIDEO_CODECS(VideoCodec::kVP9); |
| EXPECT_TRUE(base::Contains( |
| cdm.capability->video_codecs[VideoCodec::kVP9].supported_profiles, |
| media::VP9PROFILE_PROFILE0)); |
| EXPECT_TRUE(base::Contains( |
| cdm.capability->video_codecs[VideoCodec::kVP9].supported_profiles, |
| media::VP9PROFILE_PROFILE2)); |
| EXPECT_TRUE( |
| cdm.capability->video_codecs[VideoCodec::kVP9].supports_clear_lead); |
| } |
| |
| TEST_F(CdmRegistryImplTest, SupportedEncryptionSchemes) { |
| auto cdm_info = GetTestCdmInfo(); |
| cdm_info.capability->encryption_schemes = {EncryptionScheme::kCenc, |
| EncryptionScheme::kCbcs}; |
| Register(cdm_info); |
| |
| std::vector<CdmInfo> cdms = cdm_registry_.GetRegisteredCdms(); |
| ASSERT_EQ(1u, cdms.size()); |
| const CdmInfo& cdm = cdms[0]; |
| EXPECT_ENCRYPTION_SCHEMES(EncryptionScheme::kCenc, EncryptionScheme::kCbcs); |
| } |
| |
| TEST_F(CdmRegistryImplTest, GetCdmInfo_Success) { |
| Register(GetTestCdmInfo()); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kSoftwareSecure); |
| ASSERT_TRUE(cdm_info); |
| |
| const CdmInfo& cdm = *cdm_info; |
| |
| EXPECT_EQ(kTestCdmName, cdm.name); |
| EXPECT_EQ(kVersion1, cdm.capability->version.GetString()); |
| EXPECT_EQ(kTestPath, cdm.path.MaybeAsASCII()); |
| EXPECT_EQ(kTestCdmType, cdm.type); |
| EXPECT_VIDEO_CODECS(VideoCodec::kVP8, VideoCodec::kVP9); |
| EXPECT_ENCRYPTION_SCHEMES(EncryptionScheme::kCenc); |
| EXPECT_SESSION_TYPES(CdmSessionType::kTemporary, |
| CdmSessionType::kPersistentLicense); |
| EXPECT_EQ(kTestKeySystem, cdm.key_system); |
| EXPECT_TRUE(cdm.supports_sub_key_systems); |
| EXPECT_EQ(cdm.robustness, CdmInfo::Robustness::kSoftwareSecure); |
| } |
| |
| TEST_F(CdmRegistryImplTest, GetCdmInfo_Fail) { |
| Register(GetTestCdmInfo()); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| ASSERT_FALSE(cdm_info); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_SoftwareSecure) { |
| Register(GetTestCdmInfo()); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_FALSE(support.hw_cdm_capability_or_status.has_value()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_HardwareSecure) { |
| Register(kTestKeySystem, GetTestCdmCapability(), Robustness::kHardwareSecure); |
| SelectHardwareSecureDecryption(true); |
| |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_FALSE(support.sw_cdm_capability_or_status.has_value()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_LazySoftwareSecureInitialize_Supported) { |
| RegisterForLazySoftwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kSoftwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_FALSE(support.hw_cdm_capability_or_status.has_value()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_LazyHardwareSecureInitialize_Supported) { |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_FALSE(support.sw_cdm_capability_or_status.has_value()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_LazySoftwareSecureInitialize_NotSupported) { |
| RegisterForLazySoftwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kSoftwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>( |
| base::unexpected(media::CdmCapabilityQueryStatus::kUnknown))); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kSoftwareSecure); |
| ASSERT_EQ(cdm_info->status, CdmInfo::Status::kEnabled); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_LazyHardwareSecureInitialize_NotSupported) { |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>( |
| base::unexpected(media::CdmCapabilityQueryStatus::kUnknown))); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| ASSERT_EQ(cdm_info->status, CdmInfo::Status::kEnabled); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_HardwareSecureDisabled) { |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(false); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| ASSERT_EQ(cdm_info->status, |
| CdmInfo::Status::kHardwareSecureDecryptionDisabled); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_SoftwareAndHardwareSecure) { |
| RegisterForLazySoftwareSecureInitialization(); |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kSoftwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetOtherCdmCapability())); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetOtherCdmCapability()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_MultipleObservers) { |
| Register(GetTestCdmInfo()); |
| |
| base::RunLoop run_loop; |
| auto subscription1 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, |
| base::DoNothing())); |
| auto subscription2 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver2, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| |
| ASSERT_TRUE(results_.count(kObserver2)); |
| ASSERT_EQ(results_[kObserver2].size(), 1u); |
| ASSERT_EQ(key_system_capabilities, results_[kObserver2][0]); |
| } |
| |
| TEST_F( |
| CdmRegistryImplTest, |
| KeySystemCapabilities_MultipleObservers_PendingLazySoftwareSecureInitialize) { |
| RegisterForLazySoftwareSecureInitialization(); |
| SelectHardwareSecureDecryption(false); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kSoftwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| |
| base::RunLoop run_loop; |
| auto subscription1 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, |
| base::DoNothing())); |
| auto subscription2 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver2, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_FALSE(support.hw_cdm_capability_or_status.has_value()); |
| |
| ASSERT_TRUE(results_.count(kObserver2)); |
| ASSERT_EQ(results_[kObserver2].size(), 1u); |
| ASSERT_EQ(key_system_capabilities, results_[kObserver2][0]); |
| } |
| |
| TEST_F( |
| CdmRegistryImplTest, |
| KeySystemCapabilities_MultipleObservers_PendingLazyHardwareSecureInitialize) { |
| Register(GetTestCdmInfo()); |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| |
| base::RunLoop run_loop; |
| auto subscription1 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, |
| base::DoNothing())); |
| auto subscription2 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver2, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| |
| ASSERT_TRUE(results_.count(kObserver2)); |
| ASSERT_EQ(results_[kObserver2].size(), 1u); |
| ASSERT_EQ(key_system_capabilities, results_[kObserver2][0]); |
| } |
| |
| TEST_F( |
| CdmRegistryImplTest, |
| KeySystemCapabilities_MultipleObservers_AfterLazyHardwareSecureInitialize) { |
| Register(GetTestCdmInfo()); |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| |
| base::CallbackListSubscription subscription1; |
| { |
| base::RunLoop run_loop; |
| subscription1 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating( |
| &CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, run_loop.QuitClosure())); |
| run_loop.Run(); |
| } |
| base::CallbackListSubscription subscription2; |
| { |
| base::RunLoop run_loop; |
| subscription2 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating( |
| &CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver2, run_loop.QuitClosure())); |
| run_loop.Run(); |
| } |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| |
| ASSERT_TRUE(results_.count(kObserver2)); |
| ASSERT_EQ(results_[kObserver2].size(), 1u); |
| ASSERT_EQ(key_system_capabilities, results_[kObserver2][0]); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_RegisterCdmAfterObserving) { |
| Register(GetTestCdmInfo()); |
| SelectHardwareSecureDecryption(true); |
| |
| base::CallbackListSubscription subscription; |
| { |
| base::RunLoop run_loop; |
| subscription = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating( |
| &CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, run_loop.QuitClosure())); |
| run_loop.Run(); |
| } |
| |
| // Hardware security not supported for `kTestKeySystem`. |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities_1 = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities_1.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities_1.count(kTestKeySystem)); |
| const auto& support_1 = key_system_capabilities_1[kTestKeySystem]; |
| ASSERT_EQ(support_1.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_FALSE(support_1.hw_cdm_capability_or_status.has_value()); |
| |
| { |
| base::RunLoop run_loop; |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetOtherCdmCapability())); |
| RegisterForLazyHardwareSecureInitialization(); |
| run_loop.RunUntilIdle(); |
| } |
| |
| // Now hardware security is supported for `kTestKeySystem`. |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 2u); |
| auto& key_system_capabilities_2 = results_[kObserver1][1]; |
| ASSERT_EQ(key_system_capabilities_2.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities_2.count(kTestKeySystem)); |
| const auto& support_2 = key_system_capabilities_2[kTestKeySystem]; |
| ASSERT_EQ(support_2.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_EQ(support_2.hw_cdm_capability_or_status.value(), |
| GetOtherCdmCapability()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_RegisterCdmPendingLazyInitialize) { |
| SelectHardwareSecureDecryption(true); |
| |
| // Save the callbacks so we can control when and how they are fired. |
| base::OnceCallback<void(media::CdmCapabilityOrStatus)> callback_1, callback_2, |
| callback_3; |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(MoveArg<2>(&callback_1)) |
| .WillOnce(MoveArg<2>(&callback_2)); |
| EXPECT_CALL(capability_cb_, |
| Run(kOtherKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(MoveArg<2>(&callback_3)); |
| |
| // Register CdmInfo for lazy initialization. |
| base::CallbackListSubscription subscription; |
| { |
| base::RunLoop run_loop; |
| Register(CdmInfo(kTestKeySystem, CdmInfo::Robustness::kHardwareSecure, |
| std::nullopt, kTestCdmType)); |
| subscription = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating( |
| &CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, base::DoNothing())); |
| run_loop.RunUntilIdle(); |
| } |
| |
| // No results since we are still pending lazy initialization. |
| ASSERT_TRUE(results_.empty()); |
| |
| // Register CdmInfo for the same key system with a CdmCapability. |
| { |
| base::RunLoop run_loop; |
| // Register a CdmInfo without CdmCapability to allow lazy initialization. |
| Register(CdmInfo(kOtherKeySystem, CdmInfo::Robustness::kHardwareSecure, |
| std::nullopt, kTestCdmType)); |
| std::move(callback_1).Run(GetTestCdmCapability()); |
| std::move(callback_2).Run(GetTestCdmCapability()); |
| std::move(callback_3).Run(GetOtherCdmCapability()); |
| run_loop.RunUntilIdle(); |
| } |
| |
| // The observer should only be updated once with both key systems. |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 2u); |
| |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_FALSE(support.sw_cdm_capability_or_status.has_value()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| |
| ASSERT_TRUE(key_system_capabilities.count(kOtherKeySystem)); |
| const auto& other_support = key_system_capabilities[kOtherKeySystem]; |
| ASSERT_FALSE(other_support.sw_cdm_capability_or_status.has_value()); |
| ASSERT_EQ(other_support.hw_cdm_capability_or_status.value(), |
| GetOtherCdmCapability()); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_DisableHardwareSecureCdms) { |
| Register(GetTestCdmInfo()); |
| Register(kTestKeySystem, GetTestCdmCapability(), Robustness::kHardwareSecure); |
| SelectHardwareSecureDecryption(true); |
| |
| GetKeySystemCapabilities(); |
| |
| // Both software and hardware security are supported for `kTestKeySystem`. |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities_1 = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities_1.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities_1.count(kTestKeySystem)); |
| const auto& support_1 = key_system_capabilities_1[kTestKeySystem]; |
| ASSERT_EQ(support_1.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_EQ(support_1.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| |
| { |
| base::RunLoop run_loop; |
| cdm_registry_.SetHardwareSecureCdmStatus(CdmInfo::Status::kDisabledOnError); |
| run_loop.RunUntilIdle(); |
| } |
| |
| // Now hardware security is NOT supported for `kTestKeySystem`. Software |
| // security is not affected. |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 2u); |
| auto& key_system_capabilities_2 = results_[kObserver1][1]; |
| ASSERT_EQ(key_system_capabilities_2.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities_2.count(kTestKeySystem)); |
| const auto& support_2 = key_system_capabilities_2[kTestKeySystem]; |
| ASSERT_EQ(support_2.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_FALSE(support_2.hw_cdm_capability_or_status.has_value()); |
| } |
| |
| #if BUILDFLAG(IS_WIN) |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_DirectCompositionDisabled) { |
| // Simulate disabling direct composition. |
| gpu::GPUInfo gpu_info; |
| gpu_info.overlay_info.direct_composition = false; |
| GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info, std::nullopt); |
| |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| ASSERT_EQ(cdm_info->status, CdmInfo::Status::kGpuCompositionDisabled); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_DisabledBySoftwareEmulatedGpu) { |
| // Simulate enabling direct composition and software emulated GPU. |
| gpu::GPUInfo gpu_info; |
| gpu_info.overlay_info.direct_composition = true; |
| gpu_info.gpu.vendor_id = kSoftwareEmulatedVendorId; |
| GpuDataManagerImpl::GetInstance()->UpdateGpuInfo(gpu_info, std::nullopt); |
| |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| ASSERT_EQ(cdm_info->status, CdmInfo::Status::kDisabledBySoftwareEmulatedGpu); |
| ASSERT_FALSE(cdm_info->capability); |
| } |
| #endif // BUILDFLAG(IS_WIN) |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_HwCapabilityNotAllowedToAllowed) { |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| // Start with hw capability check not allowed and observe that we don't get |
| // capability. |
| GetKeySystemCapabilities(/*allow_hw_secure_capability_check=*/false); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| EXPECT_EQ(cdm_info->status, CdmInfo::Status::kUninitialized); |
| EXPECT_FALSE(cdm_info->capability); |
| |
| // Now we allow hw capability check and expect that we get capability. |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| GetKeySystemCapabilities(/*allow_hw_secure_capability_check=*/true); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 2u); |
| auto& key_system_capabilities2 = results_[kObserver1][1]; |
| ASSERT_FALSE(key_system_capabilities2.empty()); |
| auto cdm_info2 = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| |
| EXPECT_EQ(cdm_info2->status, CdmInfo::Status::kEnabled); |
| EXPECT_TRUE(cdm_info2->capability); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_HwCapabilityAllowedToNotAllowed) { |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| // Start with hw capability check allowed and observe that we get capability. |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| GetKeySystemCapabilities(/*allow_hw_secure_capability_check=*/true); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_FALSE(key_system_capabilities.empty()); |
| auto cdm_info = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| |
| EXPECT_EQ(cdm_info->status, CdmInfo::Status::kEnabled); |
| EXPECT_EQ(cdm_info->capability, GetTestCdmCapability()); |
| |
| // Now we don't allow hw capability check, but still expect that we get |
| // capability. Note that we don't EXPECT_CALL to capability since the |
| // CdmRegistry just returns the cached capability. |
| GetKeySystemCapabilities(/*allow_hw_secure_capability_check=*/false); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 2u); |
| auto& key_system_capabilities2 = results_[kObserver1][1]; |
| ASSERT_FALSE(key_system_capabilities2.empty()); |
| auto cdm_info2 = cdm_registry_.GetCdmInfo( |
| kTestKeySystem, CdmInfo::Robustness::kHardwareSecure); |
| |
| EXPECT_EQ(cdm_info2->status, CdmInfo::Status::kEnabled); |
| EXPECT_TRUE(cdm_info2->capability); |
| } |
| |
| TEST_F(CdmRegistryImplTest, |
| KeySystemCapabilities_HwCapabilityTwoObserverNotAllowedAndAllowed) { |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| |
| base::RunLoop run_loop; |
| auto subscription1 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/false, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_TRUE(key_system_capabilities.empty()); |
| |
| base::RunLoop run_loop2; |
| auto subscription2 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver2, |
| run_loop2.QuitClosure())); |
| run_loop2.Run(); |
| |
| ASSERT_TRUE(results_.count(kObserver2)); |
| ASSERT_EQ(results_[kObserver2].size(), 1u); |
| auto& key_system_capabilities2 = results_[kObserver2][0]; |
| const auto& support = key_system_capabilities2[kTestKeySystem]; |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| } |
| |
| TEST_F( |
| CdmRegistryImplTest, |
| KeySystemCapabilities_MultipleObservers_NotAllowedAndAllowedHwCapabilityCheck) { |
| RegisterForLazySoftwareSecureInitialization(); |
| RegisterForLazyHardwareSecureInitialization(); |
| SelectHardwareSecureDecryption(true); |
| |
| // Expect the lazy software capability to be triggered twice because the |
| // second observer will invalidate pending initializations and retrigger them. |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kSoftwareSecure, _)) |
| .Times(2) |
| .WillRepeatedly( |
| base::test::RunOnceCallbackRepeatedly<2>(GetTestCdmCapability())); |
| |
| EXPECT_CALL(capability_cb_, |
| Run(kTestKeySystem, Robustness::kHardwareSecure, _)) |
| .WillOnce(RunOnceCallback<2>(GetTestCdmCapability())); |
| |
| base::RunLoop run_loop; |
| auto subscription1 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/false, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver1, |
| base::DoNothing())); |
| auto subscription2 = cdm_registry_.ObserveKeySystemCapabilities( |
| /*allow_hw_secure_capability_check=*/true, |
| base::BindRepeating(&CdmRegistryImplTest::OnKeySystemCapabilitiesUpdated, |
| base::Unretained(this), kObserver2, |
| run_loop.QuitClosure())); |
| run_loop.Run(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 1u); |
| ASSERT_TRUE(key_system_capabilities.count(kTestKeySystem)); |
| const auto& support = key_system_capabilities[kTestKeySystem]; |
| ASSERT_EQ(support.sw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| ASSERT_EQ(support.hw_cdm_capability_or_status.value(), |
| GetTestCdmCapability()); |
| |
| ASSERT_TRUE(results_.count(kObserver2)); |
| ASSERT_EQ(results_[kObserver2].size(), 1u); |
| ASSERT_EQ(key_system_capabilities, results_[kObserver2][0]); |
| } |
| |
| TEST_F(CdmRegistryImplTest, KeySystemCapabilities_NoOverride) { |
| #if BUILDFLAG(IS_ANDROID) |
| DisableMediaDrmQueryInSeparateProcess(); |
| #endif |
| |
| // kTestKeySystem doesn't exist on any platform, but this should at least |
| // exercise a bit more of the code (and leave the capabilities as nullptr). |
| RegisterForLazySoftwareSecureInitialization(); |
| |
| // Don't use the testing callback. |
| ClearCapabilityTestOverride(); |
| EXPECT_CALL(capability_cb_, Run(_, _, _)).Times(0); |
| |
| GetKeySystemCapabilities(); |
| |
| ASSERT_TRUE(results_.count(kObserver1)); |
| ASSERT_EQ(results_[kObserver1].size(), 1u); |
| auto& key_system_capabilities = results_[kObserver1][0]; |
| ASSERT_EQ(key_system_capabilities.size(), 0u); |
| } |
| |
| } // namespace content |