// 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. #ifdef UNSAFE_BUFFERS_BUILD // TODO(crbug.com/342213636): Remove this and spanify to fix the errors. #pragma allow_unsafe_buffers #endif #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/content_settings/core/common/content_settings_pattern.h" #include "components/input/input_constants.h" #include "components/url_formatter/url_formatter.h" #include "components/viz/common/features.h" #include "content/child/child_process.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/40837434) 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/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 "net/base/schemeful_site.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/peerconnection/webrtc_ip_handling_policy.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/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_WIN) #include "content/child/child_process_sandbox_support_impl_win.h" #include "content/renderer/font_data/font_data_manager.h" #include "skia/ext/font_utils.h" #include "third_party/blink/public/web/win/web_font_rendering.h" #endif #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; namespace content { namespace { // TODO(crbug.com/40550966): 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(); } } // 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_WIN) // Create a FontDataManager if it's enabled, and if we're not in a // single-process environment. In single process, the SkFontMgr is already // installed by browser process code at this point. if (base::FeatureList::IsEnabled( features::kFontDataServiceAllWebContents) && sandboxEnabled()) { sk_sp<font_data_service::FontDataManager> font_data_manager = sk_make_sp<font_data_service::FontDataManager>(); blink::WebFontRendering::SetSkiaFontManager(font_data_manager); skia::OverrideDefaultSkFontMgr(font_data_manager); } #endif } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_MAC) || \ BUILDFLAG(IS_WIN) if (sandboxEnabled()) { #if BUILDFLAG(IS_MAC) sandbox_support_ = std::make_unique<WebSandboxSupportMac>(); #elif BUILDFLAG(IS_WIN) sandbox_support_ = std::make_unique<WebSandboxSupportWin>(); #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) || \ BUILDFLAG(IS_WIN) 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); } uint64_t RendererBlinkPlatformImpl::PartitionedVisitedLinkFingerprint( std::string_view canonical_link_url, const net::SchemefulSite& top_level_site, const blink::WebSecurityOrigin& frame_origin) { return GetContentClient()->renderer()->PartitionedVisitedLinkFingerprint( canonical_link_url, top_level_site, frame_origin); } bool RendererBlinkPlatformImpl::IsLinkVisited(uint64_t link_hash) { return GetContentClient()->renderer()->IsLinkVisited(link_hash); } void RendererBlinkPlatformImpl::AddOrUpdateVisitedLinkSalt( const url::Origin& origin, uint64_t salt) { GetContentClient()->renderer()->AddOrUpdateVisitedLinkSalt(origin, salt); } 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::ShouldUseCodeCacheWithHashing( const blink::WebURL& request_url) const { return GetContentClient()->renderer()->ShouldUseCodeCacheWithHashing( request_url); } 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 input::kHungRendererDelay; } std::unique_ptr<WebAudioDevice> RendererBlinkPlatformImpl::CreateAudioDevice( const WebAudioSinkDescriptor& sink_descriptor, unsigned number_of_output_channels, const blink::WebAudioLatencyHint& latency_hint, media::AudioRendererSink::RenderCallback* callback) { return RendererWebAudioDeviceImpl::Create( sink_descriptor, number_of_output_channels, latency_hint, 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); } bool RendererBlinkPlatformImpl::IsGpuRemoteDisconnected() { return RenderThreadImpl::current()->IsGpuRemoteDisconnected(); } 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::mojom::WebRtcIpHandlingPolicy* 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; GURL gurl = url::Origin(web_frame->Top()->GetSecurityOrigin()).GetURL(); *ip_handling_policy = render_frame->GetRendererPreferences().webrtc_ip_handling_policy; std::vector<blink::WebRtcIpHandlingUrlEntry> ip_handling_urls = render_frame->GetRendererPreferences().webrtc_ip_handling_urls; for (const auto& per_url_entry : ip_handling_urls) { if (per_url_entry.url_pattern.Matches(gurl)) { *ip_handling_policy = per_url_entry.handling; break; } } *udp_min_port = render_frame->GetRendererPreferences().webrtc_udp_min_port; *udp_max_port = render_frame->GetRendererPreferences().webrtc_udp_max_port; const std::string url(web_frame->GetSecurityOrigin().ToString().Utf8()); const std::vector<std::string>& allowed_urls = render_frame->GetRendererPreferences().webrtc_local_ips_allowed_urls; 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::FeatureList::IsEnabled(::features::kWebRtcHWEncoding); } bool RendererBlinkPlatformImpl::IsWebRtcHWDecodingEnabled() { return base::FeatureList::IsEnabled(::features::kWebRtcHWDecoding); } 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, 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/40837434) 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, 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/41464325): 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/40241479): 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(); CHECK(web_frame); 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>(); } bool RendererBlinkPlatformImpl::DisallowV8FeatureFlagOverrides() const { return base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kDisallowV8FeatureFlagOverrides); } void RendererBlinkPlatformImpl::AppendContentSecurityPolicy( const blink::WebURL& url, std::vector<blink::WebContentSecurityPolicyHeader>* csp) { GetContentClient()->renderer()->AppendContentSecurityPolicy(url, csp); } bool RendererBlinkPlatformImpl::IsFilePickerAllowedForCrossOriginSubframe( const blink::WebSecurityOrigin& origin) { return GetContentClient()->IsFilePickerAllowedForCrossOriginSubframe(origin); } 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::kDisplayCritical)); } 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