[go: nahoru, domu]

blob: 132aca6cb29e9968816e45cc567818818d555ad9 [file] [log] [blame]
// Copyright 2012 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/renderer/renderer_blink_platform_impl.h"
#include <algorithm>
#include <memory>
#include <string_view>
#include <utility>
#include <vector>
#include "base/check_is_test.h"
#include "base/command_line.h"
#include "base/feature_list.h"
#include "base/files/file_path.h"
#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/histogram_macros.h"
#include "base/numerics/safe_conversions.h"
#include "base/strings/pattern.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/single_thread_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "base/time/time_delta_from_string.h"
#include "build/build_config.h"
#include "cc/trees/raster_context_provider_wrapper.h"
#include "components/url_formatter/url_formatter.h"
#include "components/viz/common/features.h"
#include "content/child/child_process.h"
#include "content/common/content_constants_internal.h"
#include "content/common/features.h"
#include "content/common/user_level_memory_pressure_signal_features.h"
#include "content/public/common/content_features.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/gpu_stream_constants.h"
#include "content/public/common/origin_util.h"
#include "content/public/common/url_utils.h"
#include "content/public/common/webplugininfo.h"
#include "content/public/renderer/content_renderer_client.h"
#include "content/public/renderer/render_frame.h"
#include "content/renderer/media/audio_decoder.h"
#include "content/renderer/media/batching_media_log.h"
#include "content/renderer/media/inspector_media_event_handler.h"
#include "content/renderer/media/render_media_event_handler.h"
#include "content/renderer/media/renderer_webaudiodevice_impl.h"
#include "content/renderer/render_frame_impl.h"
#include "content/renderer/render_thread_impl.h"
#include "content/renderer/service_worker/controller_service_worker_connector.h"
#include "content/renderer/service_worker/service_worker_subresource_loader.h"
#include "content/renderer/v8_value_converter_impl.h"
#include "content/renderer/variations_render_thread_observer.h"
#include "content/renderer/webgraphicscontext3d_provider_impl.h"
#include "content/renderer/worker/dedicated_worker_host_factory_client.h"
#include "content/renderer/worker/worker_thread_registry.h"
#include "device/gamepad/public/cpp/gamepads.h"
#include "gin/array_buffer.h" // TODO(crbug.com/1321521) remove import once resolved.
#include "gpu/command_buffer/client/gles2_interface.h"
#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "gpu/config/gpu_finch_features.h"
#include "gpu/config/gpu_info.h"
#include "gpu/ipc/client/gpu_channel_host.h"
#include "media/audio/audio_output_device.h"
#include "media/base/limits.h"
#include "media/base/media_permission.h"
#include "media/base/media_switches.h"
#include "media/filters/stream_parser_factory.h"
#include "media/video/gpu_video_accelerator_factories.h"
#include "media/webrtc/webrtc_features.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "ppapi/buildflags/buildflags.h"
#include "services/network/public/cpp/features.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/cpp/wrapper_shared_url_loader_factory.h"
#include "services/service_manager/public/cpp/interface_provider.h"
#include "services/viz/public/cpp/gpu/context_provider_command_buffer.h"
#include "storage/common/database/database_identifier.h"
#include "third_party/blink/public/common/features.h"
#include "third_party/blink/public/common/origin_trials/trial_token_validator.h"
#include "third_party/blink/public/common/security/protocol_handler_security_level.h"
#include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
#include "third_party/blink/public/mojom/indexeddb/indexeddb.mojom.h"
#include "third_party/blink/public/mojom/service_worker/service_worker_provider.mojom.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/modules/video_capture/web_video_capture_impl_manager.h"
#include "third_party/blink/public/platform/scheduler/web_thread_scheduler.h"
#include "third_party/blink/public/platform/url_conversion.h"
#include "third_party/blink/public/platform/web_audio_latency_hint.h"
#include "third_party/blink/public/platform/web_audio_sink_descriptor.h"
#include "third_party/blink/public/platform/web_security_origin.h"
#include "third_party/blink/public/platform/web_theme_engine.h"
#include "third_party/blink/public/platform/web_url.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/public/platform/web_v8_value_converter.h"
#include "third_party/blink/public/platform/web_vector.h"
#include "third_party/blink/public/web/modules/media/audio/audio_device_factory.h"
#include "third_party/blink/public/web/web_local_frame.h"
#include "third_party/blink/public/web/web_media_inspector.h"
#include "third_party/blink/public/web/web_user_level_memory_pressure_signal_generator.h"
#include "third_party/sqlite/sqlite3.h"
#include "ui/base/ui_base_switches.h"
#include "ui/gl/buildflags.h"
#include "url/gurl.h"
#include "url/origin.h"
#if BUILDFLAG(IS_MAC)
#include "content/child/child_process_sandbox_support_impl_mac.h"
#elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
#include "content/child/child_process_sandbox_support_impl_linux.h"
#include "content/child/sandboxed_process_thread_type_handler.h"
#endif
#if BUILDFLAG(IS_POSIX)
#include "base/file_descriptor_posix.h"
#endif
#if BUILDFLAG(IS_ANDROID)
#include "content/common/android/sync_compositor_statics.h"
#endif
using blink::Platform;
using blink::WebAudioDevice;
using blink::WebAudioLatencyHint;
using blink::WebAudioSinkDescriptor;
using blink::WebMediaStreamTrack;
using blink::WebString;
using blink::WebURL;
using blink::WebVector;
namespace content {
namespace {
// TODO(https://crbug.com/787252): Move this method and its callers to Blink.
media::AudioParameters GetAudioHardwareParams() {
blink::WebLocalFrame* const web_frame =
blink::WebLocalFrame::FrameForCurrentContext();
RenderFrame* const render_frame = RenderFrame::FromWebFrame(web_frame);
if (!render_frame)
return media::AudioParameters::UnavailableDeviceParams();
return blink::AudioDeviceFactory::GetInstance()
->GetOutputDeviceInfo(render_frame->GetWebFrame()->GetLocalFrameToken(),
std::string())
.output_params();
}
gpu::ContextType ToGpuContextType(blink::Platform::ContextType type) {
switch (type) {
case blink::Platform::kWebGL1ContextType:
return gpu::CONTEXT_TYPE_WEBGL1;
case blink::Platform::kWebGL2ContextType:
return gpu::CONTEXT_TYPE_WEBGL2;
case blink::Platform::kGLES2ContextType:
return gpu::CONTEXT_TYPE_OPENGLES2;
case blink::Platform::kGLES3ContextType:
return gpu::CONTEXT_TYPE_OPENGLES3;
case blink::Platform::kWebGPUContextType:
return gpu::CONTEXT_TYPE_WEBGPU;
}
NOTREACHED();
return gpu::CONTEXT_TYPE_OPENGLES2;
}
} // namespace
//------------------------------------------------------------------------------
RendererBlinkPlatformImpl::RendererBlinkPlatformImpl(
blink::scheduler::WebThreadScheduler* main_thread_scheduler)
: BlinkPlatformImpl(RenderThreadImpl::current()
? RenderThreadImpl::current()->GetIOTaskRunner()
: nullptr),
sudden_termination_disables_(0),
is_locked_to_site_(false),
main_thread_scheduler_(main_thread_scheduler),
next_frame_sink_id_(uint32_t{std::numeric_limits<int32_t>::max()} + 1) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
sk_sp<font_service::FontLoader> font_loader;
#endif
// RenderThread may not exist in some tests.
if (RenderThreadImpl::current()) {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
mojo::PendingRemote<font_service::mojom::FontService> font_service;
RenderThreadImpl::current()->BindHostReceiver(
font_service.InitWithNewPipeAndPassReceiver());
font_loader = sk_make_sp<font_service::FontLoader>(std::move(font_service));
SkFontConfigInterface::SetGlobal(font_loader);
#endif
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
if (sandboxEnabled()) {
#if BUILDFLAG(IS_MAC)
sandbox_support_ = std::make_unique<WebSandboxSupportMac>();
#else
sandbox_support_ = std::make_unique<WebSandboxSupportLinux>(font_loader);
#endif
} else {
DVLOG(1) << "Disabling sandbox support for testing.";
}
#endif
auto io_task_runner = GetIOTaskRunner();
if (io_task_runner) {
io_task_runner->PostTask(
FROM_HERE, base::BindOnce(
[](base::PlatformThreadId* id,
base::WaitableEvent* io_thread_id_ready_event) {
*id = base::PlatformThread::CurrentId();
io_thread_id_ready_event->Signal();
},
&io_thread_id_, &io_thread_id_ready_event_));
} else {
// Match the `Wait` in destructor even if there is no IO runner.
io_thread_id_ready_event_.Signal();
}
}
RendererBlinkPlatformImpl::~RendererBlinkPlatformImpl() {
base::ScopedAllowBaseSyncPrimitives allow;
// Ensure task posted to IO thread is finished because it contains
// pointers to fields of `this`.
io_thread_id_ready_event_.Wait();
}
void RendererBlinkPlatformImpl::Shutdown() {}
//------------------------------------------------------------------------------
std::string RendererBlinkPlatformImpl::GetNameForHistogram(const char* name) {
RenderThreadImpl* render_thread_impl = RenderThreadImpl::current();
// render_thread_impl can be null in tests.
return render_thread_impl ? render_thread_impl->histogram_customizer()
->ConvertToCustomHistogramName(name)
: std::string{name};
}
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
void RendererBlinkPlatformImpl::SetThreadType(base::PlatformThreadId thread_id,
base::ThreadType thread_type) {
// TODO: both of the usages of this method could just be switched to use
// base::PlatformThread::SetCurrentThreadType().
if (SandboxedProcessThreadTypeHandler* sandboxed_process_thread_type_handler =
SandboxedProcessThreadTypeHandler::Get()) {
sandboxed_process_thread_type_handler->HandleThreadTypeChange(thread_id,
thread_type);
}
}
#endif
blink::WebSandboxSupport* RendererBlinkPlatformImpl::GetSandboxSupport() {
#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC)
return sandbox_support_.get();
#else
// These platforms do not require sandbox support.
return nullptr;
#endif
}
bool RendererBlinkPlatformImpl::sandboxEnabled() {
// As explained in Platform.h, this function is used to decide
// whether to allow file system operations to come out of WebKit or not.
// Even if the sandbox is disabled, there's no reason why the code should
// act any differently...unless we're in single process mode. In which
// case, we have no other choice. Platform.h discourages using
// this switch unless absolutely necessary, so hopefully we won't end up
// with too many code paths being different in single-process mode.
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess);
}
uint64_t RendererBlinkPlatformImpl::VisitedLinkHash(
std::string_view canonical_url) {
return GetContentClient()->renderer()->VisitedLinkHash(canonical_url);
}
bool RendererBlinkPlatformImpl::IsLinkVisited(uint64_t link_hash) {
return GetContentClient()->renderer()->IsLinkVisited(link_hash);
}
blink::WebString RendererBlinkPlatformImpl::UserAgent() {
auto* render_thread = RenderThreadImpl::current();
// RenderThreadImpl is null in some tests.
if (!render_thread)
return WebString();
return render_thread->GetUserAgent();
}
blink::UserAgentMetadata RendererBlinkPlatformImpl::UserAgentMetadata() {
auto* render_thread = RenderThreadImpl::current();
// RenderThreadImpl is null in some tests.
if (!render_thread)
return blink::UserAgentMetadata();
return render_thread->GetUserAgentMetadata();
}
bool RendererBlinkPlatformImpl::IsRedirectSafe(const GURL& from_url,
const GURL& to_url) {
return IsSafeRedirectTarget(from_url, to_url) &&
(!GetContentClient()->renderer() || // null in unit tests.
GetContentClient()->renderer()->IsSafeRedirectTarget(from_url,
to_url));
}
void RendererBlinkPlatformImpl::AppendVariationsThrottles(
const url::Origin& top_origin,
std::vector<std::unique_ptr<blink::URLLoaderThrottle>>* throttles) {
VariationsRenderThreadObserver::AppendThrottleIfNeeded(top_origin, throttles);
}
std::unique_ptr<blink::URLLoaderThrottleProvider>
RendererBlinkPlatformImpl::CreateURLLoaderThrottleProviderForWorker(
blink::URLLoaderThrottleProviderType provider_type) {
return GetContentClient()->renderer()->CreateURLLoaderThrottleProvider(
blink::URLLoaderThrottleProviderType::kWorker);
}
std::unique_ptr<blink::WebSocketHandshakeThrottleProvider>
RendererBlinkPlatformImpl::CreateWebSocketHandshakeThrottleProvider() {
return GetContentClient()
->renderer()
->CreateWebSocketHandshakeThrottleProvider();
}
bool RendererBlinkPlatformImpl::IsolateStartsInBackground() {
if (auto* renderer = GetContentClient()->renderer()) {
// Isolates start in the background if we do not handle hidden/visibility
// changes for this process. See `RenderThreadImpl::OnRendererHidden` and
// `RenderThreadImpl::OnRendererVisible`.
return !renderer->RunIdleHandlerWhenWidgetsHidden();
}
return BlinkPlatformImpl::IsolateStartsInBackground();
}
WebString RendererBlinkPlatformImpl::DefaultLocale() {
return WebString::FromASCII(RenderThread::Get()->GetLocale());
}
void RendererBlinkPlatformImpl::SuddenTerminationChanged(bool enabled) {
if (enabled) {
// We should not get more enables than disables, but we want it to be a
// non-fatal error if it does happen.
DCHECK_GT(sudden_termination_disables_, 0);
sudden_termination_disables_ =
std::max(sudden_termination_disables_ - 1, 0);
if (sudden_termination_disables_ != 0)
return;
} else {
sudden_termination_disables_++;
if (sudden_termination_disables_ != 1)
return;
}
RenderThreadImpl* thread = RenderThreadImpl::current();
if (!thread) {
CHECK_IS_TEST();
return;
}
thread->GetRendererHost()->SuddenTerminationChanged(enabled);
}
//------------------------------------------------------------------------------
viz::FrameSinkId RendererBlinkPlatformImpl::GenerateFrameSinkId() {
uint32_t frame_sink_id = next_frame_sink_id_++;
CHECK_LT(frame_sink_id, next_frame_sink_id_);
return viz::FrameSinkId(RenderThread::Get()->GetClientId(), frame_sink_id);
}
bool RendererBlinkPlatformImpl::IsLockedToSite() const {
return is_locked_to_site_;
}
void RendererBlinkPlatformImpl::SetIsLockedToSite() {
is_locked_to_site_ = true;
}
bool RendererBlinkPlatformImpl::IsGpuCompositingDisabled() const {
DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
RenderThreadImpl* thread = RenderThreadImpl::current();
if (!thread) {
CHECK_IS_TEST();
return true;
}
return thread->IsGpuCompositingDisabled();
}
#if BUILDFLAG(IS_ANDROID)
bool RendererBlinkPlatformImpl::
IsSynchronousCompositingEnabledForAndroidWebView() {
return GetContentClient()->UsingSynchronousCompositing();
}
bool RendererBlinkPlatformImpl::
IsZeroCopySynchronousSwDrawEnabledForAndroidWebView() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kSingleProcess);
}
SkCanvas*
RendererBlinkPlatformImpl::SynchronousCompositorGetSkCanvasForAndroidWebView() {
return content::SynchronousCompositorGetSkCanvas();
}
#endif
bool RendererBlinkPlatformImpl::IsLcdTextEnabled() {
RenderThreadImpl* thread = RenderThreadImpl::current();
return thread ? thread->IsLcdTextEnabled() : false;
}
bool RendererBlinkPlatformImpl::IsElasticOverscrollEnabled() {
RenderThreadImpl* thread = RenderThreadImpl::current();
return thread ? thread->IsElasticOverscrollEnabled() : false;
}
bool RendererBlinkPlatformImpl::IsScrollAnimatorEnabled() {
RenderThreadImpl* thread = RenderThreadImpl::current();
return thread ? thread->IsScrollAnimatorEnabled() : false;
}
bool RendererBlinkPlatformImpl::IsThreadedAnimationEnabled() {
RenderThreadImpl* thread = RenderThreadImpl::current();
return thread ? thread->IsThreadedAnimationEnabled() : true;
}
double RendererBlinkPlatformImpl::AudioHardwareSampleRate() {
return GetAudioHardwareParams().sample_rate();
}
size_t RendererBlinkPlatformImpl::AudioHardwareBufferSize() {
return GetAudioHardwareParams().frames_per_buffer();
}
unsigned RendererBlinkPlatformImpl::AudioHardwareOutputChannels() {
return GetAudioHardwareParams().channels();
}
base::TimeDelta RendererBlinkPlatformImpl::GetHungRendererDelay() {
return kHungRendererDelay;
}
std::unique_ptr<WebAudioDevice> RendererBlinkPlatformImpl::CreateAudioDevice(
const WebAudioSinkDescriptor& sink_descriptor,
unsigned number_of_output_channels,
const blink::WebAudioLatencyHint& latency_hint,
std::optional<float> sample_rate,
media::AudioRendererSink::RenderCallback* callback) {
// The `number_of_output_channels` does not manifest the actual channel
// layout of the audio output device. We use the best guess to the channel
// layout based on the number of channels.
media::ChannelLayout layout =
media::GuessChannelLayout(number_of_output_channels);
// Use "discrete" channel layout when the best guess was not successful.
if (layout == media::CHANNEL_LAYOUT_UNSUPPORTED) {
layout = media::CHANNEL_LAYOUT_DISCRETE;
}
if (sample_rate && !(media::limits::kMinSampleRate <= *sample_rate &&
*sample_rate <= media::limits::kMaxSampleRate)) {
return nullptr;
}
return RendererWebAudioDeviceImpl::Create(
sink_descriptor,
media::ChannelLayoutConfig(layout, number_of_output_channels),
latency_hint, sample_rate, callback);
}
bool RendererBlinkPlatformImpl::DecodeAudioFileData(
blink::WebAudioBus* destination_bus,
const char* audio_file_data,
size_t data_size) {
return content::DecodeAudioFileData(destination_bus, audio_file_data,
data_size);
}
//------------------------------------------------------------------------------
scoped_refptr<media::AudioCapturerSource>
RendererBlinkPlatformImpl::NewAudioCapturerSource(
blink::WebLocalFrame* web_frame,
const media::AudioSourceParameters& params) {
return blink::AudioDeviceFactory::GetInstance()->NewAudioCapturerSource(
web_frame, params);
}
scoped_refptr<viz::RasterContextProvider>
RendererBlinkPlatformImpl::SharedMainThreadContextProvider() {
return RenderThreadImpl::current()->SharedMainThreadContextProvider();
}
scoped_refptr<cc::RasterContextProviderWrapper>
RendererBlinkPlatformImpl::SharedCompositorWorkerContextProvider(
cc::RasterDarkModeFilter* dark_mode_filter) {
return RenderThreadImpl::current()->SharedCompositorWorkerContextProvider(
dark_mode_filter);
}
scoped_refptr<gpu::GpuChannelHost>
RendererBlinkPlatformImpl::EstablishGpuChannelSync() {
return RenderThreadImpl::current()->EstablishGpuChannelSync();
}
void RendererBlinkPlatformImpl::EstablishGpuChannel(
EstablishGpuChannelCallback callback) {
RenderThreadImpl::current()->EstablishGpuChannel(std::move(callback));
}
bool RendererBlinkPlatformImpl::RTCSmoothnessAlgorithmEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableRTCSmoothnessAlgorithm);
}
//------------------------------------------------------------------------------
std::optional<double>
RendererBlinkPlatformImpl::GetWebRtcMaxCaptureFrameRate() {
const std::string max_fps_str =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kWebRtcMaxCaptureFramerate);
if (!max_fps_str.empty()) {
double value;
if (base::StringToDouble(max_fps_str, &value) && value >= 0.0)
return value;
}
return std::nullopt;
}
scoped_refptr<media::AudioRendererSink>
RendererBlinkPlatformImpl::NewAudioRendererSink(
blink::WebAudioDeviceSourceType source_type,
blink::WebLocalFrame* web_frame,
const media::AudioSinkParameters& params) {
return blink::AudioDeviceFactory::GetInstance()->NewAudioRendererSink(
source_type, web_frame->GetLocalFrameToken(), params);
}
media::AudioLatency::Type RendererBlinkPlatformImpl::GetAudioSourceLatencyType(
blink::WebAudioDeviceSourceType source_type) {
return blink::AudioDeviceFactory::GetSourceLatencyType(source_type);
}
bool RendererBlinkPlatformImpl::ShouldEnforceWebRTCRoutingPreferences() {
return GetContentClient()
->renderer()
->ShouldEnforceWebRTCRoutingPreferences();
}
bool RendererBlinkPlatformImpl::UsesFakeCodecForPeerConnection() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseFakeCodecForPeerConnection);
}
bool RendererBlinkPlatformImpl::IsWebRtcEncryptionEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebRtcEncryption);
}
media::MediaPermission* RendererBlinkPlatformImpl::GetWebRTCMediaPermission(
blink::WebLocalFrame* web_frame) {
DCHECK(ShouldEnforceWebRTCRoutingPreferences());
media::MediaPermission* media_permission = nullptr;
RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(web_frame);
if (render_frame)
media_permission = render_frame->GetMediaPermission();
DCHECK(media_permission);
return media_permission;
}
void RendererBlinkPlatformImpl::GetWebRTCRendererPreferences(
blink::WebLocalFrame* web_frame,
blink::WebString* ip_handling_policy,
uint16_t* udp_min_port,
uint16_t* udp_max_port,
bool* allow_mdns_obfuscation) {
DCHECK(ip_handling_policy);
DCHECK(udp_min_port);
DCHECK(udp_max_port);
DCHECK(allow_mdns_obfuscation);
auto* render_frame = RenderFrameImpl::FromWebFrame(web_frame);
if (!render_frame)
return;
*ip_handling_policy = blink::WebString::FromUTF8(
render_frame->GetRendererPreferences().webrtc_ip_handling_policy);
*udp_min_port = render_frame->GetRendererPreferences().webrtc_udp_min_port;
*udp_max_port = render_frame->GetRendererPreferences().webrtc_udp_max_port;
const std::vector<std::string>& allowed_urls =
render_frame->GetRendererPreferences().webrtc_local_ips_allowed_urls;
const std::string url(web_frame->GetSecurityOrigin().ToString().Utf8());
for (const auto& allowed_url : allowed_urls) {
if (base::MatchPattern(url, allowed_url)) {
*allow_mdns_obfuscation = false;
return;
}
}
*allow_mdns_obfuscation = true;
}
bool RendererBlinkPlatformImpl::IsWebRtcHWEncodingEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebRtcHWEncoding);
}
bool RendererBlinkPlatformImpl::IsWebRtcHWDecodingEnabled() {
return !base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableWebRtcHWDecoding);
}
bool RendererBlinkPlatformImpl::IsWebRtcSrtpEncryptedHeadersEnabled() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableWebRtcSrtpEncryptedHeaders);
}
bool RendererBlinkPlatformImpl::AllowsLoopbackInPeerConnection() {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kAllowLoopbackInPeerConnection);
}
blink::WebVideoCaptureImplManager*
RendererBlinkPlatformImpl::GetVideoCaptureImplManager() {
RenderThreadImpl* thread = RenderThreadImpl::current();
return thread ? thread->video_capture_impl_manager() : nullptr;
}
//------------------------------------------------------------------------------
void RendererBlinkPlatformImpl::Collect3DContextInformation(
blink::Platform::GraphicsInfo* gl_info,
const gpu::GPUInfo& gpu_info) const {
DCHECK(gl_info);
const gpu::GPUInfo::GPUDevice& active_gpu = gpu_info.active_gpu();
gl_info->vendor_id = active_gpu.vendor_id;
gl_info->device_id = active_gpu.device_id;
gl_info->renderer_info = WebString::FromUTF8(gpu_info.gl_renderer);
gl_info->vendor_info = WebString::FromUTF8(gpu_info.gl_vendor);
gl_info->driver_version = WebString::FromUTF8(active_gpu.driver_version);
gl_info->reset_notification_strategy =
gpu_info.gl_reset_notification_strategy;
gl_info->sandboxed = gpu_info.sandboxed;
gl_info->amd_switchable = gpu_info.amd_switchable;
gl_info->optimus = gpu_info.optimus;
gl_info->using_gpu_compositing = !IsGpuCompositingDisabled();
gl_info->using_passthrough_command_decoder = gpu_info.passthrough_cmd_decoder;
gl_info->angle_implementation = gpu_info.gl_implementation_parts.angle;
}
std::unique_ptr<blink::WebGraphicsContext3DProvider>
RendererBlinkPlatformImpl::CreateOffscreenGraphicsContext3DProvider(
const blink::Platform::ContextAttributes& web_attributes,
const blink::WebURL& document_url,
blink::Platform::GraphicsInfo* gl_info) {
DCHECK(gl_info);
if (!RenderThreadImpl::current()) {
std::string error_message("Failed to run in Current RenderThreadImpl");
gl_info->error_message = WebString::FromUTF8(error_message);
return nullptr;
}
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
RenderThreadImpl::current()->EstablishGpuChannelSync());
if (!gpu_channel_host) {
std::string error_message(
"OffscreenContext Creation failed, GpuChannelHost creation failed");
gl_info->error_message = WebString::FromUTF8(error_message);
return nullptr;
}
Collect3DContextInformation(gl_info, gpu_channel_host->gpu_info());
gpu::ContextCreationAttribs attributes;
attributes.bind_generates_resource = false;
attributes.enable_raster_interface = web_attributes.enable_raster_interface;
attributes.enable_oop_rasterization =
attributes.enable_raster_interface &&
gpu_channel_host->gpu_feature_info()
.status_values[gpu::GPU_FEATURE_TYPE_CANVAS_OOP_RASTERIZATION] ==
gpu::kGpuFeatureStatusEnabled;
attributes.enable_gles2_interface = !attributes.enable_oop_rasterization;
attributes.enable_grcontext =
!attributes.enable_oop_rasterization && web_attributes.support_grcontext;
attributes.gpu_preference = web_attributes.prefer_low_power_gpu
? gl::GpuPreference::kLowPower
: gl::GpuPreference::kHighPerformance;
attributes.fail_if_major_perf_caveat =
web_attributes.fail_if_major_performance_caveat;
attributes.context_type = ToGpuContextType(web_attributes.context_type);
constexpr bool automatic_flushes = true;
constexpr bool support_locking = false;
return std::make_unique<WebGraphicsContext3DProviderImpl>(
base::MakeRefCounted<viz::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), kGpuStreamIdDefault,
kGpuStreamPriorityDefault, gpu::kNullSurfaceHandle,
GURL(document_url), automatic_flushes, support_locking,
gpu::SharedMemoryLimits(), attributes,
viz::command_buffer_metrics::ContextType::WEBGL));
}
//------------------------------------------------------------------------------
std::unique_ptr<blink::WebGraphicsContext3DProvider>
RendererBlinkPlatformImpl::CreateSharedOffscreenGraphicsContext3DProvider() {
auto* thread = RenderThreadImpl::current();
scoped_refptr<viz::ContextProviderCommandBuffer> provider =
thread->SharedMainThreadContextProvider();
if (!provider)
return nullptr;
scoped_refptr<gpu::GpuChannelHost> host = thread->EstablishGpuChannelSync();
// This shouldn't normally fail because we just got |provider|. But the
// channel can become lost on the IO thread since then. It is important that
// this happens after getting |provider|. In the case that this GpuChannelHost
// is not the same one backing |provider|, the context behind the |provider|
// will be already lost/dead on arrival.
if (!host)
return nullptr;
return std::make_unique<WebGraphicsContext3DProviderImpl>(
std::move(provider));
}
//------------------------------------------------------------------------------
static std::unique_ptr<blink::WebGraphicsContext3DProvider>
CreateWebGPUGraphicsContext3DImpl(
const blink::WebURL& document_url,
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) {
gpu::ContextCreationAttribs attributes;
// TODO(kainino): It's not clear yet how GPU preferences work for WebGPU.
attributes.gpu_preference = gl::GpuPreference::kHighPerformance;
attributes.enable_gles2_interface = false;
attributes.context_type = gpu::CONTEXT_TYPE_WEBGPU;
constexpr bool automatic_flushes = true;
constexpr bool support_locking = false;
// WebGPU GPUBuffers, which are backed by shared memory transfer buffers, may
// be accessed as ArrayBuffers from JavaScript. As such, the underlying
// buffers need to be mapped using the ArrayBuffer shared memory mapper. As
// there is currently no way of specifying a custom mapper per buffer, we
// have to map all buffers created by this provider using the custom mapper.
// TODO(crbug.com/1321521) instead of mapping all buffers created by this
// provider with the array buffer mapper, only map those that will actually
// be used as ArrayBuffers and remove this per-provider mapper again.
base::SharedMemoryMapper* buffer_mapper =
gin::GetSharedMemoryMapperForArrayBuffers();
return std::make_unique<WebGraphicsContext3DProviderImpl>(
base::MakeRefCounted<viz::ContextProviderCommandBuffer>(
std::move(gpu_channel_host), kGpuStreamIdDefault,
kGpuStreamPriorityDefault, gpu::kNullSurfaceHandle,
GURL(document_url), automatic_flushes, support_locking,
gpu::SharedMemoryLimits::ForWebGPUContext(), attributes,
viz::command_buffer_metrics::ContextType::WEBGPU, buffer_mapper));
}
std::unique_ptr<blink::WebGraphicsContext3DProvider>
RendererBlinkPlatformImpl::CreateWebGPUGraphicsContext3DProvider(
const blink::WebURL& document_url) {
#if !BUILDFLAG(USE_DAWN)
return nullptr;
#else
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host(
RenderThreadImpl::current()->EstablishGpuChannelSync());
if (!gpu_channel_host) {
// TODO(crbug.com/973017): Collect GPU info and surface context creation
// error.
return nullptr;
}
return CreateWebGPUGraphicsContext3DImpl(document_url, gpu_channel_host);
#endif
}
void RendererBlinkPlatformImpl::CreateWebGPUGraphicsContext3DProviderAsync(
const blink::WebURL& document_url,
base::OnceCallback<
void(std::unique_ptr<blink::WebGraphicsContext3DProvider>)> callback) {
#if !BUILDFLAG(USE_DAWN)
std::move(callback).Run(nullptr);
#else
// Initiate the asynchronous call to establish the GPU channel
RenderThreadImpl::current()->EstablishGpuChannel(base::BindOnce(
&RendererBlinkPlatformImpl::OnGpuChannelEstablished,
weak_factory_.GetWeakPtr(), document_url, std::move(callback)));
#endif
}
void RendererBlinkPlatformImpl::OnGpuChannelEstablished(
const blink::WebURL& document_url,
base::OnceCallback<
void(std::unique_ptr<blink::WebGraphicsContext3DProvider>)> callback,
scoped_refptr<gpu::GpuChannelHost> gpu_channel_host) {
if (!gpu_channel_host) {
std::move(callback).Run(nullptr);
return;
}
std::move(callback).Run(
CreateWebGPUGraphicsContext3DImpl(document_url, gpu_channel_host));
}
//------------------------------------------------------------------------------
gpu::GpuMemoryBufferManager*
RendererBlinkPlatformImpl::GetGpuMemoryBufferManager() {
RenderThreadImpl* thread = RenderThreadImpl::current();
return thread ? thread->GetGpuMemoryBufferManager() : nullptr;
}
//------------------------------------------------------------------------------
blink::WebString RendererBlinkPlatformImpl::ConvertIDNToUnicode(
const blink::WebString& host) {
return WebString::FromUTF16(url_formatter::IDNToUnicode(host.Ascii()));
}
//------------------------------------------------------------------------------
std::unique_ptr<blink::WebDedicatedWorkerHostFactoryClient>
RendererBlinkPlatformImpl::CreateDedicatedWorkerHostFactoryClient(
blink::WebDedicatedWorker* worker,
const blink::BrowserInterfaceBrokerProxy& interface_broker) {
return std::make_unique<DedicatedWorkerHostFactoryClient>(worker,
interface_broker);
}
void RendererBlinkPlatformImpl::DidStartWorkerThread() {
WorkerThreadRegistry::Instance()->DidStartCurrentWorkerThread();
}
void RendererBlinkPlatformImpl::WillStopWorkerThread() {
WorkerThreadRegistry::Instance()->WillStopCurrentWorkerThread();
}
void RendererBlinkPlatformImpl::WorkerContextCreated(
const v8::Local<v8::Context>& worker) {
GetContentClient()->renderer()->DidInitializeWorkerContextOnWorkerThread(
worker);
}
bool RendererBlinkPlatformImpl::AllowScriptExtensionForServiceWorker(
const blink::WebSecurityOrigin& script_origin) {
return GetContentClient()->renderer()->AllowScriptExtensionForServiceWorker(
script_origin);
}
blink::ProtocolHandlerSecurityLevel
RendererBlinkPlatformImpl::GetProtocolHandlerSecurityLevel(
const blink::WebSecurityOrigin& origin) {
url::Origin url_origin(origin);
return GetContentClient()->renderer()->GetProtocolHandlerSecurityLevel(
url_origin);
}
bool RendererBlinkPlatformImpl::OriginCanAccessServiceWorkers(const GURL& url) {
return content::OriginCanAccessServiceWorkers(url);
}
std::tuple<blink::CrossVariantMojoRemote<
blink::mojom::ServiceWorkerContainerHostInterfaceBase>,
blink::CrossVariantMojoRemote<
blink::mojom::ServiceWorkerContainerHostInterfaceBase>>
RendererBlinkPlatformImpl::CloneServiceWorkerContainerHost(
blink::CrossVariantMojoRemote<
blink::mojom::ServiceWorkerContainerHostInterfaceBase>
service_worker_container_host) {
mojo::Remote<blink::mojom::ServiceWorkerContainerHost>
service_worker_container_host_remote(
std::move(service_worker_container_host));
mojo::PendingRemote<blink::mojom::ServiceWorkerContainerHost>
service_worker_container_host_pending_remote;
service_worker_container_host_remote->CloneContainerHost(
service_worker_container_host_pending_remote
.InitWithNewPipeAndPassReceiver());
return std::make_tuple(
service_worker_container_host_remote.Unbind(),
std::move(service_worker_container_host_pending_remote));
}
void RendererBlinkPlatformImpl::CreateServiceWorkerSubresourceLoaderFactory(
blink::CrossVariantMojoRemote<
blink::mojom::ServiceWorkerContainerHostInterfaceBase>
service_worker_container_host,
const blink::WebString& client_id,
std::unique_ptr<network::PendingSharedURLLoaderFactory> fallback_factory,
mojo::PendingReceiver<network::mojom::URLLoaderFactory> receiver,
scoped_refptr<base::SequencedTaskRunner> task_runner) {
// TODO(crbug.com/1371756): plumb `router_rules` with the function callers
// if there is such use case. As of 2023-06-01, only
// `DedicatedOrSharedWorkerFetchContextImpl` calls the function, and
// no need to allow it set the `router_rules`.
ServiceWorkerSubresourceLoaderFactory::Create(
base::MakeRefCounted<ControllerServiceWorkerConnector>(
std::move(service_worker_container_host),
/*remote_controller=*/mojo::NullRemote(),
/*remote_cache_storage=*/mojo::NullRemote(), client_id.Utf8(),
blink::mojom::ServiceWorkerFetchHandlerBypassOption::kDefault,
/*router_rules=*/std::nullopt, blink::EmbeddedWorkerStatus::kStopped,
/*running_status_receiver=*/mojo::NullReceiver()),
network::SharedURLLoaderFactory::Create(std::move(fallback_factory)),
std::move(receiver), std::move(task_runner));
}
//------------------------------------------------------------------------------
// The returned BatchingMediaLog can be used on any thread, but must be
// destroyed on |owner_task_runner|. The aggregated MediaLogRecords will be
// sent back to the Browser via Mojo objects bound to |owner_task_runner|.
std::unique_ptr<media::MediaLog> RendererBlinkPlatformImpl::GetMediaLog(
blink::MediaInspectorContext* inspector_context,
scoped_refptr<base::SingleThreadTaskRunner> owner_task_runner,
bool is_on_worker) {
std::vector<std::unique_ptr<BatchingMediaLog::EventHandler>> handlers;
// For chrome://media-internals.
// This should only be created in the main Window context, and not from
// a worker context.
if (!is_on_worker)
handlers.push_back(std::make_unique<RenderMediaEventHandler>(
media::GetNextMediaPlayerLoggingID()));
// For devtools' media tab.
handlers.push_back(
std::make_unique<InspectorMediaEventHandler>(inspector_context));
return std::make_unique<BatchingMediaLog>(owner_task_runner,
std::move(handlers));
}
//------------------------------------------------------------------------------
media::GpuVideoAcceleratorFactories*
RendererBlinkPlatformImpl::GetGpuFactories() {
auto* render_thread = RenderThreadImpl::current();
if (!render_thread)
return nullptr;
return render_thread->GetGpuFactories();
}
scoped_refptr<base::SequencedTaskRunner>
RendererBlinkPlatformImpl::MediaThreadTaskRunner() {
auto* render_thread = RenderThreadImpl::current();
if (!render_thread)
return nullptr;
return render_thread->GetMediaSequencedTaskRunner();
}
base::WeakPtr<media::DecoderFactory>
RendererBlinkPlatformImpl::GetMediaDecoderFactory() {
blink::WebLocalFrame* const web_frame =
blink::WebLocalFrame::FrameForCurrentContext();
RenderFrameImpl* render_frame = RenderFrameImpl::FromWebFrame(web_frame);
return render_frame->GetMediaDecoderFactory();
}
void RendererBlinkPlatformImpl::SetRenderingColorSpace(
const gfx::ColorSpace& color_space) {
auto* render_thread = RenderThreadImpl::current();
if (!render_thread)
return;
render_thread->SetRenderingColorSpace(color_space);
}
gfx::ColorSpace RendererBlinkPlatformImpl::GetRenderingColorSpace() const {
auto* render_thread = RenderThreadImpl::current();
if (!render_thread)
return {};
return render_thread->GetRenderingColorSpace();
}
//------------------------------------------------------------------------------
void RendererBlinkPlatformImpl::SetActiveURL(const blink::WebURL& url,
const blink::WebString& top_url) {
GetContentClient()->SetActiveURL(url, top_url.Utf8());
}
//------------------------------------------------------------------------------
SkBitmap* RendererBlinkPlatformImpl::GetSadPageBitmap() {
return GetContentClient()->renderer()->GetSadWebViewBitmap();
}
//------------------------------------------------------------------------------
std::unique_ptr<blink::WebV8ValueConverter>
RendererBlinkPlatformImpl::CreateWebV8ValueConverter() {
return std::make_unique<V8ValueConverterImpl>();
}
void RendererBlinkPlatformImpl::AppendContentSecurityPolicy(
const blink::WebURL& url,
blink::WebVector<blink::WebContentSecurityPolicyHeader>* csp) {
GetContentClient()->renderer()->AppendContentSecurityPolicy(url, csp);
}
base::PlatformThreadId RendererBlinkPlatformImpl::GetIOThreadId() const {
auto io_task_runner = GetIOTaskRunner();
if (!io_task_runner)
return base::kInvalidThreadId;
// Cannot be called from IO thread due to potential deadlock.
CHECK(!io_task_runner->BelongsToCurrentThread());
{
base::ScopedAllowBaseSyncPrimitives allow;
io_thread_id_ready_event_.Wait();
}
return io_thread_id_;
}
scoped_refptr<base::SingleThreadTaskRunner>
RendererBlinkPlatformImpl::VideoFrameCompositorTaskRunner() {
auto compositor_task_runner = CompositorThreadTaskRunner();
if (::features::UseSurfaceLayerForVideo() || !compositor_task_runner) {
if (!video_frame_compositor_thread_) {
// All of Chromium's GPU code must know which thread it's running on, and
// be the same thread on which the rendering context was initialized. This
// is why this must be a SingleThreadTaskRunner instead of a
// SequencedTaskRunner.
video_frame_compositor_thread_ =
std::make_unique<base::Thread>("VideoFrameCompositor");
video_frame_compositor_thread_->StartWithOptions(
base::Thread::Options(base::ThreadType::kCompositing));
}
return video_frame_compositor_thread_->task_runner();
}
return compositor_task_runner;
}
#if BUILDFLAG(IS_ANDROID)
void RendererBlinkPlatformImpl::SetPrivateMemoryFootprint(
uint64_t private_memory_footprint_bytes) {
auto* render_thread = RenderThreadImpl::current();
CHECK(render_thread);
render_thread->SetPrivateMemoryFootprint(private_memory_footprint_bytes);
}
bool RendererBlinkPlatformImpl::IsUserLevelMemoryPressureSignalEnabled() {
return features::IsUserLevelMemoryPressureSignalEnabledOn3GbDevices() ||
features::IsUserLevelMemoryPressureSignalEnabledOn4GbDevices() ||
features::IsUserLevelMemoryPressureSignalEnabledOn6GbDevices();
}
std::pair<base::TimeDelta, base::TimeDelta> RendererBlinkPlatformImpl::
InertAndMinimumIntervalOfUserLevelMemoryPressureSignal() {
if (features::IsUserLevelMemoryPressureSignalEnabledOn3GbDevices()) {
return std::make_pair(
features::InertIntervalFor3GbDevices(),
features::MinUserMemoryPressureIntervalOn3GbDevices());
}
if (features::IsUserLevelMemoryPressureSignalEnabledOn4GbDevices()) {
return std::make_pair(
features::InertIntervalFor4GbDevices(),
features::MinUserMemoryPressureIntervalOn4GbDevices());
}
if (features::IsUserLevelMemoryPressureSignalEnabledOn6GbDevices()) {
return std::make_pair(
features::InertIntervalFor6GbDevices(),
features::MinUserMemoryPressureIntervalOn6GbDevices());
}
constexpr std::pair<base::TimeDelta, base::TimeDelta>
kDefaultInertAndMinInterval =
std::make_pair(base::TimeDelta::Min(), base::Minutes(10));
return kDefaultInertAndMinInterval;
}
#endif // BUILDFLAG(IS_ANDROID)
} // namespace content