Skip to content

Commit

Permalink
Creates a utility process that houses video encoding.
Browse files Browse the repository at this point in the history
This CL changes where accelerated video encoding is done by decoupling
it from the GPU process and putting it in an isolated utility process.
The purpose for this is to ensure that malicious renderers cannot gain
access to different parts of the GPU process that are unrelated to video
encoding.

For each renderer that needs accelerated video encoding, there should
only be one utility process. Due to this, a new mojo interface was
created that stores a UniqueReceiverSet of
mojom::VideoEncodeAcceleratorProviders. This is required since the
utility process can only have one mojom interface bound to it, but each
renderer can have multiple video encoder providers. This interface is
given to the utility process when it is launched. Each video encoder
provider created on the renderer corresponding to it are added to the
UniqueReceiverSet so that when calls are made to it, they are called
from the utility process.

For more information, refer to go/oop-vea

Change-Id: I59979d58da93a52614922659e46a32ab5916e75b
Bug: b:248540499
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3953577
Commit-Queue: Grayson LaFleur <graysonlafleur@google.com>
Reviewed-by: Alex Gough <ajgo@chromium.org>
Reviewed-by: Andres Calderon Jaramillo <andrescj@chromium.org>
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
Reviewed-by: Pilar Molina Lopez <pmolinalopez@chromium.org>
Reviewed-by: Dan Sanders <sandersd@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1075405}
  • Loading branch information
Grayson LaFleur authored and Chromium LUCI CQ committed Nov 24, 2022
1 parent d11d6a5 commit d349535
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 6 deletions.
2 changes: 2 additions & 0 deletions content/browser/BUILD.gn
Expand Up @@ -2321,6 +2321,8 @@ source_set("browser") {
"font_service.cc",
"font_service.h",
"media/stable_video_decoder_factory.cc",
"media/video_encode_accelerator_provider_launcher.cc",
"media/video_encode_accelerator_provider_launcher.h",
"memory/swap_metrics_driver_impl_linux.cc",
"memory/swap_metrics_driver_impl_linux.h",
"sandbox_host_linux.cc",
Expand Down
@@ -0,0 +1,18 @@
// Copyright 2022 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/video_encode_accelerator_provider_launcher.h"
#include "content/public/browser/service_process_host.h"

namespace content {

void LaunchVideoEncodeAcceleratorProviderFactory(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProviderFactory>
receiver) {
ServiceProcessHost::Launch(
std::move(receiver),
ServiceProcessHost::Options().WithDisplayName("Video Encoder").Pass());
}

} // namespace content
22 changes: 22 additions & 0 deletions content/browser/media/video_encode_accelerator_provider_launcher.h
@@ -0,0 +1,22 @@
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_MEDIA_VIDEO_ENCODE_ACCELERATOR_PROVIDER_LAUNCHER_H_
#define CONTENT_BROWSER_MEDIA_VIDEO_ENCODE_ACCELERATOR_PROVIDER_LAUNCHER_H_

#include "media/mojo/mojom/video_encode_accelerator.mojom.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"

namespace content {

// This method is used to create a utility process that hosts a
// VideoEncodeAcceleratorProviderFactory implementation so that video
// encode acceleration can be done outside of the GPU process.
void LaunchVideoEncodeAcceleratorProviderFactory(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProviderFactory>
receiver);

} // namespace content

#endif // CONTENT_BROWSER_MEDIA_VIDEO_ENCODE_ACCELERATOR_PROVIDER_LAUNCHER_H_
28 changes: 27 additions & 1 deletion content/browser/renderer_host/render_process_host_impl.cc
Expand Up @@ -221,7 +221,9 @@
#include "content/browser/font_service.h" // nogncheck
#include "third_party/blink/public/mojom/memory_usage_monitor_linux.mojom.h" // nogncheck

#include "content/browser/media/video_encode_accelerator_provider_launcher.h"
#include "content/public/browser/stable_video_decoder_factory.h"
#include "media/mojo/mojom/video_encode_accelerator.mojom.h"
#endif

#if BUILDFLAG(IS_MAC)
Expand Down Expand Up @@ -1230,7 +1232,26 @@ class RenderProcessHostImpl::IOThreadHostImpl : public mojom::ChildProcessHost {
ConnectToFontService(std::move(font_receiver));
return;
}
#endif

if (base::FeatureList::IsEnabled(media::kUseOutOfProcessVideoEncoding)) {
if (auto r =
receiver.As<media::mojom::VideoEncodeAcceleratorProvider>()) {
if (!video_encode_accelerator_factory_remote_.is_bound()) {
LaunchVideoEncodeAcceleratorProviderFactory(
video_encode_accelerator_factory_remote_
.BindNewPipeAndPassReceiver());
video_encode_accelerator_factory_remote_.reset_on_disconnect();
}

if (!video_encode_accelerator_factory_remote_.is_bound())
return;

video_encode_accelerator_factory_remote_
->CreateVideoEncodeAcceleratorProvider(std::move(r));
return;
}
}
#endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS))

#if BUILDFLAG(IS_WIN)
if (auto r = receiver.As<mojom::FontCacheWin>()) {
Expand Down Expand Up @@ -1294,6 +1315,11 @@ class RenderProcessHostImpl::IOThreadHostImpl : public mojom::ChildProcessHost {
const base::WeakPtr<RenderProcessHostImpl> weak_host_;
std::unique_ptr<service_manager::BinderRegistry> binders_;
mojo::Receiver<mojom::ChildProcessHost> receiver_{this};

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
mojo::Remote<media::mojom::VideoEncodeAcceleratorProviderFactory>
video_encode_accelerator_factory_remote_;
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
};

// static
Expand Down
10 changes: 10 additions & 0 deletions content/renderer/render_thread_impl.cc
Expand Up @@ -1091,8 +1091,18 @@ media::GpuVideoAcceleratorFactories* RenderThreadImpl::GetGpuFactories() {

mojo::PendingRemote<media::mojom::VideoEncodeAcceleratorProvider>
vea_provider;

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
if (base::FeatureList::IsEnabled(media::kUseOutOfProcessVideoEncoding)) {
BindHostReceiver(vea_provider.InitWithNewPipeAndPassReceiver());
} else {
gpu_->CreateVideoEncodeAcceleratorProvider(
vea_provider.InitWithNewPipeAndPassReceiver());
}
#else
gpu_->CreateVideoEncodeAcceleratorProvider(
vea_provider.InitWithNewPipeAndPassReceiver());
#endif

gpu_factories_.push_back(GpuVideoAcceleratorFactoriesImpl::Create(
std::move(gpu_channel_host),
Expand Down
6 changes: 1 addition & 5 deletions content/utility/BUILD.gn
Expand Up @@ -99,13 +99,9 @@ source_set("utility") {
deps += [
"//gpu/config",
"//media/gpu/sandbox",
"//media/mojo/services",
"//third_party/angle:angle_gpu_info_util",
]

if ((is_linux || is_chromeos_ash) && (use_vaapi || use_v4l2_codec)) {
# To allow creating media::StableVideoDecoderFactoryService objects.
deps += [ "//media/mojo/services" ]
}
}

if (is_chromeos_ash && is_chrome_branded) {
Expand Down
16 changes: 16 additions & 0 deletions content/utility/services.cc
Expand Up @@ -65,6 +65,7 @@ extern sandbox::TargetServices* g_utility_target_services;
#endif // BUILDFLAG(IS_WIN)

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "media/mojo/services/mojo_video_encode_accelerator_provider_factory.h"
#include "sandbox/linux/services/libc_interceptor.h"
#include "sandbox/policy/mojom/sandbox.mojom.h"
#include "sandbox/policy/sandbox_type.h"
Expand Down Expand Up @@ -323,6 +324,17 @@ auto RunStableVideoDecoderFactoryService(
#endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)) &&
// (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
auto RunVideoEncodeAcceleratorProviderFactory(
mojo::PendingReceiver<media::mojom::VideoEncodeAcceleratorProviderFactory>
receiver) {
auto factory =
std::make_unique<media::MojoVideoEncodeAcceleratorProviderFactory>();
factory->BindReceiver(std::move(receiver));
return factory;
}
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

} // namespace

void RegisterIOThreadServices(mojo::ServiceFactory& services) {
Expand Down Expand Up @@ -371,6 +383,10 @@ void RegisterMainThreadServices(mojo::ServiceFactory& services) {
#endif // (BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS_ASH)) &&
// (BUILDFLAG(USE_VAAPI) || BUILDFLAG(USE_V4L2_CODEC))

#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
services.Add(RunVideoEncodeAcceleratorProviderFactory);
#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)

#if BUILDFLAG(ENABLE_ACCESSIBILITY_SERVICE)
if (::features::IsAccessibilityServiceEnabled())
services.Add(RunAccessibilityService);
Expand Down
3 changes: 3 additions & 0 deletions media/mojo/mojom/BUILD.gn
Expand Up @@ -104,6 +104,9 @@ mojom("mojom") {
}

enabled_features = []
if (is_linux || is_chromeos) {
enabled_features += [ "is_linux_or_chromeos" ]
}

# Help select ServiceSandbox for media_service.mojom.
if (mojo_media_host == "browser") {
Expand Down
26 changes: 26 additions & 0 deletions media/mojo/mojom/video_encode_accelerator.mojom
Expand Up @@ -10,6 +10,7 @@ import "mojo/public/mojom/base/shared_memory.mojom";
import "mojo/public/mojom/base/time.mojom";
import "ui/gfx/geometry/mojom/geometry.mojom";
import "media/mojo/mojom/video_encoder_info.mojom";
import "sandbox/policy/mojom/sandbox.mojom";

// This file is the Mojo version of the media::VideoEncodeAccelerator interface
// and describes the communication between a Client and a remote "service"
Expand Down Expand Up @@ -64,6 +65,31 @@ interface VideoEncodeAcceleratorProvider {
=> (array<VideoEncodeAcceleratorSupportedProfile> profiles);
};

// This interface allows the browser process to broker
// VideoEncodeAcceleratorProvider connection requests on behalf of a renderer.
// The browser creates the mojo pipe and gives the receiver to a utility
// process. The expected usage is as follows:
//
// 1) The browser process receives a request from a renderer process to bind a
// pending_receiver<VideoEncodeAcceleratorProvider>.
//
// 2) To satisfy that request, the browser process first starts a utility
// process that hosts a VideoEncodeAcceleratorProviderFactory if it hasn't
// already done so -- note that each renderer process should get its own
// corresponding utility process.
//
// 3) The browser process calls CreateVideoEncodeAcceleratorProvider() passing
// the pending_receiver<VideoEncodeAcceleratorProvider> received from the
// renderer process.
[EnableIf=is_linux_or_chromeos,
ServiceSandbox=sandbox.mojom.Sandbox.kHardwareVideoEncoding]
interface VideoEncodeAcceleratorProviderFactory {
// Creates a VideoEncodeAcceleratorProvider and should be called by the
// browser process.
CreateVideoEncodeAcceleratorProvider(
pending_receiver<VideoEncodeAcceleratorProvider> receiver);
};

// This defines a mojo transport format used in the
// mojo::VideoBitrateAllocation that corresponds to media::Bitrate::peak_bps_
struct VariableBitratePeak {
Expand Down
7 changes: 7 additions & 0 deletions media/mojo/services/BUILD.gn
Expand Up @@ -128,6 +128,13 @@ component("services") {
[ "//chromeos/components/cdm_factory_daemon:cdm_factory_daemon_gpu" ]
}

if (is_linux || is_chromeos) {
sources += [
"mojo_video_encode_accelerator_provider_factory.cc",
"mojo_video_encode_accelerator_provider_factory.h",
]
}

if (is_android) {
sources += [
"android_mojo_media_client.cc",
Expand Down
@@ -0,0 +1,49 @@
// Copyright 2022 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/mojo_video_encode_accelerator_provider_factory.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_info.h"
#include "gpu/config/gpu_preferences.h"
#include "media/base/media_log.h"
#include "media/gpu/gpu_video_encode_accelerator_factory.h"
#include "media/mojo/services/mojo_video_encode_accelerator_provider.h"

namespace media {

MojoVideoEncodeAcceleratorProviderFactory::
MojoVideoEncodeAcceleratorProviderFactory()
: receiver_(this) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

MojoVideoEncodeAcceleratorProviderFactory::
~MojoVideoEncodeAcceleratorProviderFactory() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}

void MojoVideoEncodeAcceleratorProviderFactory::BindReceiver(
mojo::PendingReceiver<mojom::VideoEncodeAcceleratorProviderFactory>
receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(!receiver_.is_bound());
receiver_.Bind(std::move(receiver));
}

void MojoVideoEncodeAcceleratorProviderFactory::
CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<mojom::VideoEncodeAcceleratorProvider> receiver) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// TODO(b/248540499): pass useful gpu::GpuPreferences,
// gpu::GpuDriverBugWorkarounds, and gpu::GPUInfo::GPUDevice instances.
std::unique_ptr<mojom::VideoEncodeAcceleratorProvider> provider =
std::make_unique<MojoVideoEncodeAcceleratorProvider>(
base::BindRepeating(&GpuVideoEncodeAcceleratorFactory::CreateVEA),
gpu::GpuPreferences(), gpu::GpuDriverBugWorkarounds(),
gpu::GPUInfo::GPUDevice());

video_encoder_providers_.Add(std::move(provider), std::move(receiver));
}

} // namespace media
@@ -0,0 +1,51 @@
// Copyright 2022 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_MOJO_VIDEO_ENCODE_ACCELERATOR_PROVIDER_FACTORY_H_
#define MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_PROVIDER_FACTORY_H_

#include "base/sequence_checker.h"
#include "media/mojo/mojom/video_encode_accelerator.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"
#include "mojo/public/cpp/bindings/unique_receiver_set.h"

namespace media {

// This class implements mojom::VideoEncodeAcceleratorProviderFactory and lives
// in a utility process. This class houses a UniqueReceiverSet of
// mojom::VideoEncodeAcceleratorProviders so that each utility process can have
// multiple encoder providers.
class MEDIA_MOJO_EXPORT MojoVideoEncodeAcceleratorProviderFactory
: public mojom::VideoEncodeAcceleratorProviderFactory {
public:
MojoVideoEncodeAcceleratorProviderFactory();
MojoVideoEncodeAcceleratorProviderFactory(
const MojoVideoEncodeAcceleratorProviderFactory&) = delete;
MojoVideoEncodeAcceleratorProviderFactory& operator=(
const MojoVideoEncodeAcceleratorProviderFactory&) = delete;
~MojoVideoEncodeAcceleratorProviderFactory() override;

void BindReceiver(
mojo::PendingReceiver<mojom::VideoEncodeAcceleratorProviderFactory>
receiver);

// mojom::VideoEncodeAcceleratorProviderFactory implementation.
void CreateVideoEncodeAcceleratorProvider(
mojo::PendingReceiver<mojom::VideoEncodeAcceleratorProvider> receiver)
override;

private:
mojo::Receiver<mojom::VideoEncodeAcceleratorProviderFactory> receiver_
GUARDED_BY_CONTEXT(sequence_checker_);
mojo::UniqueReceiverSet<mojom::VideoEncodeAcceleratorProvider>
video_encoder_providers_ GUARDED_BY_CONTEXT(sequence_checker_);

SEQUENCE_CHECKER(sequence_checker_);
};

} // namespace media

#endif // MEDIA_MOJO_SERVICES_MOJO_VIDEO_ENCODE_ACCELERATOR_PROVIDER_FACTORY_H_

0 comments on commit d349535

Please sign in to comment.