Run MediaDrm queries in utility process on Android
Calls to determine Widevine key system support (using MediaDrm.isCryptoSchemeSupported) crash on some Android devices. To avoid crashing the browser, run these queries in a separate unsandboxed process (if possible). This avoids crashing the browser and will result in the key system not getting registered, which means that protected content will not play on the device. Tested on a Pixel 7 with both clank and WebView. Also tested on an Android emulator (clank only). Verified that the information shown with chrome://media-internals#cdms matches current Chrome results (clank only) and playback of protected content works. Bug: 40280540 Bug: 40948139 Test: see above Change-Id: Ieb509ce38b29a3fcaa77f6fae668b75d97868191 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5704248 Reviewed-by: Vikram Pasupathy <vpasupathy@chromium.org> Reviewed-by: Richard (Torne) Coles <torne@chromium.org> Reviewed-by: Matthew Denton <mpdenton@chromium.org> Reviewed-by: Jorge Lucangeli Obes <jorgelo@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org> Commit-Queue: John Rummell <jrummell@chromium.org> Cr-Commit-Position: refs/heads/main@{#1336847}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
fcc48d82a9
commit
a70b0c9730
android_webview/browser
content
browser
media
test
utility
media
@ -165,6 +165,11 @@ void AwFieldTrials::RegisterFeatureOverrides(base::FeatureList* feature_list) {
|
||||
// clear on how user can remove persistent media licenses from UI.
|
||||
aw_feature_overrides.DisableFeature(media::kMediaDrmPersistentLicense);
|
||||
|
||||
// WebView does not support multiple processes, so don't try to call some
|
||||
// MediaDrm APIs in a separate process.
|
||||
aw_feature_overrides.DisableFeature(
|
||||
media::kAllowMediaCodecCallsInSeparateProcess);
|
||||
|
||||
aw_feature_overrides.DisableFeature(::features::kBackgroundFetch);
|
||||
|
||||
// SurfaceControl is controlled by kWebViewSurfaceControl flag.
|
||||
|
@ -259,6 +259,15 @@ class CdmRegistryImplTest : public testing::Test {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
// On Android checking for key system support can be run on a separate
|
||||
// thread. Disable this for testing.
|
||||
void DisableMediaCodecCallsInSeparateThread() {
|
||||
scoped_feature_list_.InitAndDisableFeature(
|
||||
media::kAllowMediaCodecCallsInSeparateProcess);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ClearCapabilityTestOverride() {
|
||||
cdm_registry_.SetCapabilityCBForTesting(base::NullCallback());
|
||||
}
|
||||
@ -1051,6 +1060,10 @@ TEST_F(
|
||||
}
|
||||
|
||||
TEST_F(CdmRegistryImplTest, KeySystemCapabilities_NoOverride) {
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
DisableMediaCodecCallsInSeparateThread();
|
||||
#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();
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "base/android/build_info.h"
|
||||
#include "base/feature_list.h"
|
||||
#include "content/public/browser/android/android_overlay_provider.h"
|
||||
#include "content/public/browser/service_process_host.h"
|
||||
#include "media/audio/android/audio_manager_android.h"
|
||||
#include "media/base/android/media_codec_util.h"
|
||||
#include "media/base/android/media_drm_bridge.h"
|
||||
@ -21,6 +22,8 @@
|
||||
#include "media/base/media_util.h"
|
||||
#include "media/base/video_codecs.h"
|
||||
#include "media/media_buildflags.h"
|
||||
#include "media/mojo/mojom/mediadrm_support.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
|
||||
using media::MediaCodecUtil;
|
||||
using media::MediaDrmBridge;
|
||||
@ -72,36 +75,21 @@ static bool CanPassthrough(media::AudioCodec codec) {
|
||||
media::ConvertAudioCodecToBitstreamFormat(codec)) != 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void GetAndroidCdmCapability(const std::string& key_system,
|
||||
CdmInfo::Robustness robustness,
|
||||
media::CdmCapabilityCB cdm_capability_cb) {
|
||||
const bool is_secure = robustness == CdmInfo::Robustness::kHardwareSecure;
|
||||
if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
|
||||
DVLOG(1) << "Key system " << key_system << " not supported.";
|
||||
std::move(cdm_capability_cb).Run(std::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
// Rendering of hardware secure codecs is only supported when AndroidOverlay
|
||||
// is enabled.
|
||||
if (is_secure) {
|
||||
bool are_overlay_supported =
|
||||
content::AndroidOverlayProvider::GetInstance()->AreOverlaysSupported();
|
||||
bool overlay_fullscreen_video =
|
||||
base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo);
|
||||
if (!are_overlay_supported || !overlay_fullscreen_video) {
|
||||
DVLOG(1) << "Hardware secure codecs not supported for key system"
|
||||
<< key_system << ".";
|
||||
std::move(cdm_capability_cb).Run(std::nullopt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the capabilities for `key_system` based on `webm_supported` and
|
||||
// `mp4_supported`, and call `cdm_capability_cb` with the resulting capability.
|
||||
// This class assumes that MediaDrm does support `key_system`.
|
||||
void DetermineKeySystemSupport(const std::string& key_system,
|
||||
bool is_secure,
|
||||
media::CdmCapabilityCB cdm_capability_cb,
|
||||
bool webm_supported,
|
||||
bool mp4_supported) {
|
||||
const std::vector<media::VideoCodecProfile> kAllProfiles = {};
|
||||
media::CdmCapability capability;
|
||||
if (MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "video/webm")) {
|
||||
|
||||
DVLOG(1) << __func__ << " mp4_supported: " << mp4_supported
|
||||
<< ", webm_supported: " << webm_supported;
|
||||
|
||||
if (webm_supported) {
|
||||
for (const auto& codec : kWebMAudioCodecsToQuery) {
|
||||
if (MediaCodecUtil::CanDecode(codec)) {
|
||||
capability.audio_codecs.insert(codec);
|
||||
@ -117,7 +105,7 @@ void GetAndroidCdmCapability(const std::string& key_system,
|
||||
// |audio_codecs| and |video_codecs| should not have multiple entries with
|
||||
// the same codec, so if the loop above added them, no need to test the same
|
||||
// codec again.
|
||||
if (MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "video/mp4")) {
|
||||
if (mp4_supported) {
|
||||
// It is possible that a device that is not able to decode the audio stream
|
||||
// is connected to an audiosink device that can. In this case, CanDecode()
|
||||
// returns false but CanPassthrough() will return true. CanPassthrough()
|
||||
@ -199,4 +187,120 @@ void GetAndroidCdmCapability(const std::string& key_system,
|
||||
std::move(cdm_capability_cb).Run(capability);
|
||||
}
|
||||
|
||||
// Used to determine if `key_system` is supported, and if it is whether WebM and
|
||||
// MP4 mime types are also supported. Done via a separate process so that
|
||||
// crashes in MediaDrm do not crash the browser. This class destructs itself
|
||||
// when complete.
|
||||
class CheckCdmCompatibility {
|
||||
public:
|
||||
CheckCdmCompatibility(const std::string& key_system,
|
||||
bool is_secure,
|
||||
media::CdmCapabilityCB cdm_capability_cb)
|
||||
: key_system_(key_system),
|
||||
is_secure_(is_secure),
|
||||
cdm_capability_cb_(std::move(cdm_capability_cb)) {}
|
||||
|
||||
~CheckCdmCompatibility() = default;
|
||||
|
||||
// Creates the remote process and calls it.
|
||||
void CheckKeySystemSupport() {
|
||||
media_drm_service_ =
|
||||
content::ServiceProcessHost::Launch<media::mojom::MediaDrmSupport>(
|
||||
content::ServiceProcessHost::Options()
|
||||
.WithDisplayName("MediaDrmSupport")
|
||||
.Pass());
|
||||
|
||||
// As the calls to MediaDrm can crash and take out the utility process,
|
||||
// set up a handler for when this happens.
|
||||
media_drm_service_.set_disconnect_handler(base::BindOnce(
|
||||
&CheckCdmCompatibility::OnServiceClosed, base::Unretained(this)));
|
||||
|
||||
DVLOG(1) << __func__ << " calling IsKeySystemSupported for " << key_system_;
|
||||
media_drm_service_->IsKeySystemSupported(
|
||||
key_system_,
|
||||
base::BindOnce(&CheckCdmCompatibility::VerifyKeySystemSupport,
|
||||
base::Unretained(this)));
|
||||
}
|
||||
|
||||
// Called when the remote process has determined if `key_system` and WebM/MP4
|
||||
// are supported.
|
||||
void VerifyKeySystemSupport(
|
||||
media::mojom::MediaDrmSupportResultPtr key_system_support_result) {
|
||||
if (key_system_support_result.is_null()) {
|
||||
DVLOG(1) << "Key system " << key_system_ << " not supported.";
|
||||
std::move(cdm_capability_cb_).Run(std::nullopt);
|
||||
delete this;
|
||||
return;
|
||||
}
|
||||
|
||||
DetermineKeySystemSupport(
|
||||
key_system_, is_secure_, std::move(cdm_capability_cb_),
|
||||
key_system_support_result->key_system_supports_video_webm,
|
||||
key_system_support_result->key_system_supports_video_mp4);
|
||||
delete this;
|
||||
}
|
||||
|
||||
// If the remote service fails, assume it has crashed and thus `key_system`
|
||||
// is not supported.
|
||||
void OnServiceClosed() {
|
||||
DVLOG(1) << "IsKeySystemSupported failed for " << key_system_;
|
||||
std::move(cdm_capability_cb_).Run(std::nullopt);
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string key_system_;
|
||||
const bool is_secure_;
|
||||
media::CdmCapabilityCB cdm_capability_cb_;
|
||||
mojo::Remote<media::mojom::MediaDrmSupport> media_drm_service_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void GetAndroidCdmCapability(const std::string& key_system,
|
||||
CdmInfo::Robustness robustness,
|
||||
media::CdmCapabilityCB cdm_capability_cb) {
|
||||
// Rendering of hardware secure codecs is only supported when AndroidOverlay
|
||||
// is enabled.
|
||||
const bool is_secure = robustness == CdmInfo::Robustness::kHardwareSecure;
|
||||
if (is_secure) {
|
||||
bool are_overlay_supported =
|
||||
content::AndroidOverlayProvider::GetInstance()->AreOverlaysSupported();
|
||||
bool overlay_fullscreen_video =
|
||||
base::FeatureList::IsEnabled(media::kOverlayFullscreenVideo);
|
||||
if (!are_overlay_supported || !overlay_fullscreen_video) {
|
||||
DVLOG(1) << "Hardware secure codecs not supported for key system"
|
||||
<< key_system << ".";
|
||||
std::move(cdm_capability_cb).Run(std::nullopt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Calls to MediaDrm.isCryptoSchemeSupported() are known to crash
|
||||
// (see b/308692917), so calling them via a utility process to avoid
|
||||
// crashing the browser if allowed.
|
||||
if (base::FeatureList::IsEnabled(
|
||||
media::kAllowMediaCodecCallsInSeparateProcess)) {
|
||||
// The class CheckCdmCompatibility will manage it's own lifetime
|
||||
// (destruct after calling `cdm_capability_cb`).
|
||||
auto* check_cdm_compatibility = new CheckCdmCompatibility(
|
||||
key_system, is_secure, std::move(cdm_capability_cb));
|
||||
check_cdm_compatibility->CheckKeySystemSupport();
|
||||
return;
|
||||
}
|
||||
|
||||
// Multiple processes are not allowed, so call MediaDrmBridge directly.
|
||||
if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
|
||||
std::move(cdm_capability_cb).Run(std::nullopt);
|
||||
return;
|
||||
}
|
||||
|
||||
bool webm_supported =
|
||||
MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "video/webm");
|
||||
bool mp4_supported =
|
||||
MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "video/mp4");
|
||||
DetermineKeySystemSupport(key_system, is_secure, std::move(cdm_capability_cb),
|
||||
webm_supported, mp4_supported);
|
||||
}
|
||||
|
||||
} // namespace content
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "base/functional/callback.h"
|
||||
#include "content/common/content_export.h"
|
||||
#include "content/public/common/cdm_info.h"
|
||||
#include "media/base/cdm_capability.h"
|
||||
|
||||
@ -16,9 +16,10 @@ namespace content {
|
||||
// Calls `cdm_capability_cb` with the CdmCapability supported on Android for
|
||||
// `key_system` with robustness `robustness`. Capability will be base::nullopt
|
||||
// if the device does not support `key_system` and `robustness`.
|
||||
void GetAndroidCdmCapability(const std::string& key_system,
|
||||
CdmInfo::Robustness robustness,
|
||||
media::CdmCapabilityCB cdm_capability_cb);
|
||||
void CONTENT_EXPORT
|
||||
GetAndroidCdmCapability(const std::string& key_system,
|
||||
CdmInfo::Robustness robustness,
|
||||
media::CdmCapabilityCB cdm_capability_cb);
|
||||
|
||||
} // namespace content
|
||||
|
||||
|
72
content/browser/media/key_system_support_android_unittest.cc
Normal file
72
content/browser/media/key_system_support_android_unittest.cc
Normal file
@ -0,0 +1,72 @@
|
||||
// Copyright 2024 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/key_system_support_android.h"
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "base/test/scoped_feature_list.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "content/public/common/cdm_info.h"
|
||||
#include "media/base/cdm_capability.h"
|
||||
#include "media/base/media_switches.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
namespace content {
|
||||
|
||||
namespace {
|
||||
const char kWidevineKeySystem[] = "com.widevine.alpha";
|
||||
const char kUnsupportedKeySystem[] = "keysystem.test.unsupported";
|
||||
} // namespace
|
||||
|
||||
// These tests disable the mojo remote process as it uses a sandbox which does
|
||||
// not appear to be available during testing.
|
||||
|
||||
TEST(KeySystemSupportAndroidTest, SoftwareSecureWidevine) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndDisableFeature(
|
||||
media::kAllowMediaCodecCallsInSeparateProcess);
|
||||
|
||||
base::test::TestFuture<std::optional<media::CdmCapability>> capability;
|
||||
GetAndroidCdmCapability(kWidevineKeySystem,
|
||||
CdmInfo::Robustness::kSoftwareSecure,
|
||||
capability.GetCallback());
|
||||
|
||||
// As the capabilities depend on the device this is running on, just check
|
||||
// that we get something back. All Android devices should support some
|
||||
// form of Widevine for software secure operation.
|
||||
ASSERT_TRUE(capability.Get().has_value());
|
||||
}
|
||||
|
||||
TEST(KeySystemSupportAndroidTest, HardwareSecureWidevine) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndDisableFeature(
|
||||
media::kAllowMediaCodecCallsInSeparateProcess);
|
||||
|
||||
base::test::TestFuture<std::optional<media::CdmCapability>> capability;
|
||||
GetAndroidCdmCapability(kWidevineKeySystem,
|
||||
CdmInfo::Robustness::kHardwareSecure,
|
||||
capability.GetCallback());
|
||||
|
||||
// As the capabilities depend on the device this is running on, just check
|
||||
// that we get something back. Some devices (e.g. emulators) will not have
|
||||
// any hardware secure capabilities.
|
||||
ASSERT_TRUE(capability.Wait());
|
||||
}
|
||||
|
||||
TEST(KeySystemSupportAndroidTest, UnknownKeySystem) {
|
||||
base::test::ScopedFeatureList scoped_feature_list;
|
||||
scoped_feature_list.InitAndDisableFeature(
|
||||
media::kAllowMediaCodecCallsInSeparateProcess);
|
||||
|
||||
base::test::TestFuture<std::optional<media::CdmCapability>> capability;
|
||||
GetAndroidCdmCapability(kUnsupportedKeySystem,
|
||||
CdmInfo::Robustness::kSoftwareSecure,
|
||||
capability.GetCallback());
|
||||
|
||||
// Keysystem should not exist, so no capabilities should be found.
|
||||
ASSERT_FALSE(capability.Get().has_value());
|
||||
}
|
||||
|
||||
} // namespace content
|
@ -3329,6 +3329,7 @@ test("content_unittests") {
|
||||
"../browser/android/overscroll_controller_android_unittest.cc",
|
||||
"../browser/android/scoped_surface_request_manager_unittest.cc",
|
||||
"../browser/font_unique_name_lookup/font_unique_name_lookup_unittest.cc",
|
||||
"../browser/media/key_system_support_android_unittest.cc",
|
||||
"../browser/renderer_host/render_widget_host_view_android_unittest.cc",
|
||||
"../browser/sms/sms_provider_gms_unittest.cc",
|
||||
"../renderer/java/gin_java_bridge_value_converter_unittest.cc",
|
||||
|
@ -91,6 +91,11 @@ extern sandbox::TargetServices* g_utility_target_services;
|
||||
#include "media/mojo/services/media_foundation_service_broker.h" // nogncheck
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
#include "media/mojo/mojom/mediadrm_support.mojom.h" // nogncheck
|
||||
#include "media/mojo/services/mediadrm_support_service.h" // nogncheck
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS_ASH) && \
|
||||
(BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))
|
||||
#include "ash/components/arc/video_accelerator/oop_arc_video_accelerator_factory.h"
|
||||
@ -306,6 +311,13 @@ RunMediaFoundationServiceBroker(
|
||||
}
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
auto RunMediaDrmSupportService(
|
||||
mojo::PendingReceiver<media::mojom::MediaDrmSupport> receiver) {
|
||||
return std::make_unique<media::MediaDrmSupportService>(std::move(receiver));
|
||||
}
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
|
||||
auto RunStorageService(
|
||||
mojo::PendingReceiver<storage::mojom::StorageService> receiver) {
|
||||
return std::make_unique<storage::StorageServiceImpl>(
|
||||
@ -460,6 +472,10 @@ void RegisterMainThreadServices(mojo::ServiceFactory& services) {
|
||||
services.Add(RunMediaFoundationServiceBroker);
|
||||
#endif // BUILDFLAG(IS_WIN)
|
||||
|
||||
#if BUILDFLAG(IS_ANDROID)
|
||||
services.Add(RunMediaDrmSupportService);
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
|
||||
#if BUILDFLAG(ENABLE_VR) && !BUILDFLAG(IS_ANDROID)
|
||||
services.Add(RunXrDeviceService);
|
||||
#endif
|
||||
|
@ -1205,6 +1205,13 @@ BASE_FEATURE(kAllowMediaCodecSoftwareDecoder,
|
||||
"AllowMediaCodecSoftwareDecoder",
|
||||
base::FEATURE_DISABLED_BY_DEFAULT);
|
||||
|
||||
// This feature allows for some MediaDrm functions to be executed in a separate
|
||||
// process so that crashes do not bring down the browser. Flag is available so
|
||||
// that it can be disabled for WebView as separate processes are not allowed.
|
||||
BASE_FEATURE(kAllowMediaCodecCallsInSeparateProcess,
|
||||
"AllowMediaCodecCallsInSeparateProcess",
|
||||
base::FEATURE_ENABLED_BY_DEFAULT);
|
||||
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
|
||||
#if BUILDFLAG(ENABLE_HLS_DEMUXER)
|
||||
|
@ -396,6 +396,7 @@ MEDIA_EXPORT BASE_DECLARE_FEATURE(kRequestSystemAudioFocus);
|
||||
MEDIA_EXPORT BASE_DECLARE_FEATURE(kUseAudioLatencyFromHAL);
|
||||
MEDIA_EXPORT BASE_DECLARE_FEATURE(kUsePooledSharedImageVideoProvider);
|
||||
MEDIA_EXPORT BASE_DECLARE_FEATURE(kAllowMediaCodecSoftwareDecoder);
|
||||
MEDIA_EXPORT BASE_DECLARE_FEATURE(kAllowMediaCodecCallsInSeparateProcess);
|
||||
#endif // BUILDFLAG(IS_ANDROID)
|
||||
|
||||
#if BUILDFLAG(ENABLE_HLS_DEMUXER)
|
||||
|
@ -56,7 +56,10 @@ mojom("mojom") {
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
sources += [ "android_overlay.mojom" ]
|
||||
sources += [
|
||||
"android_overlay.mojom",
|
||||
"mediadrm_support.mojom",
|
||||
]
|
||||
} else {
|
||||
sources += [ "speech_recognition_service.mojom" ]
|
||||
}
|
||||
|
23
media/mojo/mojom/mediadrm_support.mojom
Normal file
23
media/mojo/mojom/mediadrm_support.mojom
Normal file
@ -0,0 +1,23 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
module media.mojom;
|
||||
|
||||
import "sandbox/policy/mojom/sandbox.mojom";
|
||||
|
||||
struct MediaDrmSupportResult {
|
||||
bool key_system_supports_video_mp4;
|
||||
bool key_system_supports_video_webm;
|
||||
};
|
||||
|
||||
// A service to execute some MediaDrm functions on Android due to the OS
|
||||
// occasionally running into problems and crashing.
|
||||
[ServiceSandbox=sandbox.mojom.Sandbox.kNoSandbox]
|
||||
interface MediaDrmSupport {
|
||||
// Checks whether key system `key_system` is supported. If it is, returns
|
||||
// `key_system_supports` with whether `key_system` supports MP4 and/or
|
||||
// WebM. If `key_system` is not supported, nothing is returned.
|
||||
IsKeySystemSupported(string key_system)
|
||||
=> (MediaDrmSupportResult? key_system_supports);
|
||||
};
|
@ -147,6 +147,8 @@ component("services") {
|
||||
"android_mojo_media_client.h",
|
||||
"android_mojo_util.cc",
|
||||
"android_mojo_util.h",
|
||||
"mediadrm_support_service.cc",
|
||||
"mediadrm_support_service.h",
|
||||
]
|
||||
}
|
||||
|
||||
@ -313,6 +315,11 @@ source_set("unit_tests") {
|
||||
]
|
||||
}
|
||||
|
||||
if (is_android) {
|
||||
sources += [ "mediadrm_support_service_unittest.cc" ]
|
||||
deps += [ "//third_party/widevine/cdm:headers" ]
|
||||
}
|
||||
|
||||
if (is_chromeos_ash) {
|
||||
deps += [
|
||||
"//components/chromeos_camera:mjpeg_decode_accelerator_service_unittest",
|
||||
|
40
media/mojo/services/mediadrm_support_service.cc
Normal file
40
media/mojo/services/mediadrm_support_service.cc
Normal file
@ -0,0 +1,40 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "media/mojo/services/mediadrm_support_service.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/functional/callback.h"
|
||||
#include "media/base/android/media_drm_bridge.h"
|
||||
|
||||
namespace media {
|
||||
|
||||
MediaDrmSupportService::MediaDrmSupportService(
|
||||
mojo::PendingReceiver<mojom::MediaDrmSupport> receiver)
|
||||
: receiver_(this, std::move(receiver)) {}
|
||||
|
||||
MediaDrmSupportService::~MediaDrmSupportService() = default;
|
||||
|
||||
void MediaDrmSupportService::IsKeySystemSupported(
|
||||
const std::string& key_system,
|
||||
IsKeySystemSupportedCallback callback) {
|
||||
DCHECK(!key_system.empty());
|
||||
DVLOG(1) << __func__ << " key_system: " << key_system;
|
||||
|
||||
if (!MediaDrmBridge::IsKeySystemSupported(key_system)) {
|
||||
std::move(callback).Run(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = mojom::MediaDrmSupportResult::New();
|
||||
result->key_system_supports_video_webm =
|
||||
MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "video/webm");
|
||||
result->key_system_supports_video_mp4 =
|
||||
MediaDrmBridge::IsKeySystemSupportedWithType(key_system, "video/mp4");
|
||||
std::move(callback).Run(std::move(result));
|
||||
}
|
||||
|
||||
} // namespace media
|
38
media/mojo/services/mediadrm_support_service.h
Normal file
38
media/mojo/services/mediadrm_support_service.h
Normal file
@ -0,0 +1,38 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef MEDIA_MOJO_SERVICES_MEDIADRM_SUPPORT_SERVICE_H_
|
||||
#define MEDIA_MOJO_SERVICES_MEDIADRM_SUPPORT_SERVICE_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "media/mojo/mojom/mediadrm_support.mojom.h"
|
||||
#include "media/mojo/services/media_mojo_export.h"
|
||||
#include "mojo/public/cpp/bindings/pending_receiver.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
|
||||
namespace media {
|
||||
|
||||
class MEDIA_MOJO_EXPORT MediaDrmSupportService final
|
||||
: public mojom::MediaDrmSupport {
|
||||
public:
|
||||
explicit MediaDrmSupportService(
|
||||
mojo::PendingReceiver<mojom::MediaDrmSupport> receiver);
|
||||
|
||||
MediaDrmSupportService(const MediaDrmSupportService&) = delete;
|
||||
MediaDrmSupportService& operator=(const MediaDrmSupportService&) = delete;
|
||||
|
||||
~MediaDrmSupportService() final;
|
||||
|
||||
// mojom::MediaDrmSupport interface
|
||||
void IsKeySystemSupported(const std::string& key_system,
|
||||
IsKeySystemSupportedCallback callback) override;
|
||||
|
||||
private:
|
||||
mojo::Receiver<mojom::MediaDrmSupport> receiver_;
|
||||
};
|
||||
|
||||
} // namespace media
|
||||
|
||||
#endif // MEDIA_MOJO_SERVICES_MEDIADRM_SUPPORT_SERVICE_H_
|
59
media/mojo/services/mediadrm_support_service_unittest.cc
Normal file
59
media/mojo/services/mediadrm_support_service_unittest.cc
Normal file
@ -0,0 +1,59 @@
|
||||
// Copyright 2024 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "media/mojo/services/mediadrm_support_service.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/test/task_environment.h"
|
||||
#include "base/test/test_future.h"
|
||||
#include "media/mojo/mojom/mediadrm_support.mojom.h"
|
||||
#include "mojo/public/cpp/bindings/remote.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
#include "third_party/widevine/cdm/widevine_cdm_common.h"
|
||||
|
||||
namespace media {
|
||||
|
||||
namespace {
|
||||
|
||||
class MediaDrmSupportServiceTest : public testing::Test {
|
||||
public:
|
||||
void Initialize() {
|
||||
service_ = std::make_unique<MediaDrmSupportService>(
|
||||
remote_.BindNewPipeAndPassReceiver());
|
||||
}
|
||||
|
||||
protected:
|
||||
base::test::TaskEnvironment task_environment_;
|
||||
std::unique_ptr<MediaDrmSupportService> service_;
|
||||
mojo::Remote<mojom::MediaDrmSupport> remote_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST_F(MediaDrmSupportServiceTest, WidevineKeySystem) {
|
||||
Initialize();
|
||||
|
||||
base::test::TestFuture<mojom::MediaDrmSupportResultPtr> support;
|
||||
service_->IsKeySystemSupported(kWidevineKeySystem, support.GetCallback());
|
||||
|
||||
// All Android devices should support some form of Widevine support.
|
||||
// However, support for WebM and MP4 formats may vary between devices,
|
||||
// so we cannot check the other parameters.
|
||||
ASSERT_TRUE(support.Get());
|
||||
}
|
||||
|
||||
TEST_F(MediaDrmSupportServiceTest, UnknownKeySystem) {
|
||||
const char kUnsupportedKeySystem[] = "keysystem.test.unsupported";
|
||||
|
||||
Initialize();
|
||||
|
||||
base::test::TestFuture<mojom::MediaDrmSupportResultPtr> support;
|
||||
service_->IsKeySystemSupported(kUnsupportedKeySystem, support.GetCallback());
|
||||
|
||||
// Unknown key system should not be supported.
|
||||
ASSERT_FALSE(support.Get());
|
||||
}
|
||||
|
||||
} // namespace media
|
Reference in New Issue
Block a user