// Copyright 2014 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/child/blink_platform_impl.h" #include <math.h> #include <memory> #include <string_view> #include <vector> #include "base/command_line.h" #include "base/files/file_path.h" #include "base/functional/bind.h" #include "base/location.h" #include "base/memory/raw_ptr.h" #include "base/memory/singleton.h" #include "base/metrics/user_metrics_action.h" #include "base/rand_util.h" #include "base/run_loop.h" #include "base/sequence_checker.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" #include "base/synchronization/lock.h" #include "base/system/sys_info.h" #include "base/task/sequenced_task_runner.h" #include "base/task/single_thread_task_runner.h" #include "base/task/thread_pool.h" #include "base/time/time.h" #include "base/trace_event/memory_allocator_dump_guid.h" #include "base/trace_event/memory_dump_manager.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" #include "content/child/child_thread_impl.h" #include "content/common/child_process.mojom.h" #include "content/public/common/content_client.h" #include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_utils.h" #include "mojo/public/cpp/bindings/shared_remote.h" #include "net/base/net_errors.h" #include "services/network/public/cpp/features.h" #include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h" #include "third_party/blink/public/platform/user_metrics_action.h" #include "third_party/blink/public/platform/web_data.h" #include "third_party/blink/public/platform/web_security_origin.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/public/platform/web_url.h" #include "third_party/blink/public/resources/grit/blink_image_resources.h" #include "third_party/blink/public/resources/grit/blink_resources.h" #include "third_party/blink/public/strings/grit/blink_strings.h" #include "ui/base/resource/resource_scale_factor.h" #include "ui/base/ui_base_features.h" #include "ui/events/gestures/blink/web_gesture_curve_impl.h" using blink::WebData; using blink::WebString; using blink::WebURL; using blink::WebURLError; namespace content { namespace { // This must match third_party/WebKit/public/blink_resources.grd. struct DataResource { const char* name; int id; ui::ResourceScaleFactor scale_factor; }; class NestedMessageLoopRunnerImpl : public blink::Platform::NestedMessageLoopRunner { public: NestedMessageLoopRunnerImpl() = default; ~NestedMessageLoopRunnerImpl() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); } void Run() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); base::RunLoop* const previous_run_loop = run_loop_; base::RunLoop run_loop(base::RunLoop::Type::kNestableTasksAllowed); run_loop_ = &run_loop; run_loop.Run(); run_loop_ = previous_run_loop; } void QuitNow() override { DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK(run_loop_); run_loop_->Quit(); } private: raw_ptr<base::RunLoop> run_loop_ = nullptr; SEQUENCE_CHECKER(sequence_checker_); }; mojo::SharedRemote<mojom::ChildProcessHost> GetChildProcessHost() { auto* thread = ChildThreadImpl::current(); if (thread) return thread->child_process_host(); return {}; } // An implementation of BrowserInterfaceBroker which forwards to the // ChildProcessHost interface. This lives on the IO thread. class ThreadSafeBrowserInterfaceBrokerProxyImpl : public blink::ThreadSafeBrowserInterfaceBrokerProxy { public: ThreadSafeBrowserInterfaceBrokerProxyImpl() : process_host_(GetChildProcessHost()) {} ThreadSafeBrowserInterfaceBrokerProxyImpl( const ThreadSafeBrowserInterfaceBrokerProxyImpl&) = delete; ThreadSafeBrowserInterfaceBrokerProxyImpl& operator=( const ThreadSafeBrowserInterfaceBrokerProxyImpl&) = delete; // blink::ThreadSafeBrowserInterfaceBrokerProxy implementation: void GetInterfaceImpl(mojo::GenericPendingReceiver receiver) override { if (process_host_) process_host_->BindHostReceiver(std::move(receiver)); } private: ~ThreadSafeBrowserInterfaceBrokerProxyImpl() override = default; const mojo::SharedRemote<mojom::ChildProcessHost> process_host_; }; } // namespace // TODO(skyostil): Ensure that we always have an active task runner when // constructing the platform. BlinkPlatformImpl::BlinkPlatformImpl() : BlinkPlatformImpl(nullptr) {} BlinkPlatformImpl::BlinkPlatformImpl( scoped_refptr<base::SingleThreadTaskRunner> io_thread_task_runner) : io_thread_task_runner_(std::move(io_thread_task_runner)), media_stream_video_source_video_task_runner_( base::FeatureList::IsEnabled( blink::features::kUseThreadPoolForMediaStreamVideoTaskRunner) ? base::ThreadPool::CreateSequencedTaskRunner(base::TaskTraits{}) : io_thread_task_runner_), browser_interface_broker_proxy_( base::MakeRefCounted<ThreadSafeBrowserInterfaceBrokerProxyImpl>()) {} BlinkPlatformImpl::~BlinkPlatformImpl() = default; void BlinkPlatformImpl::RecordAction(const blink::UserMetricsAction& name) { if (ChildThread* child_thread = ChildThread::Get()) child_thread->RecordComputedAction(name.Action()); } bool BlinkPlatformImpl::HasDataResource(int resource_id) const { return GetContentClient()->HasDataResource(resource_id); } WebData BlinkPlatformImpl::GetDataResource( int resource_id, ui::ResourceScaleFactor scale_factor) { std::string_view resource = GetContentClient()->GetDataResource(resource_id, scale_factor); return WebData(base::as_byte_span(resource)); } std::string BlinkPlatformImpl::GetDataResourceString(int resource_id) { return GetContentClient()->GetDataResourceString(resource_id); } base::RefCountedMemory* BlinkPlatformImpl::GetDataResourceBytes( int resource_id) { return GetContentClient()->GetDataResourceBytes(resource_id); } WebString BlinkPlatformImpl::QueryLocalizedString(int resource_id) { if (resource_id < 0) return WebString(); return WebString::FromUTF16( GetContentClient()->GetLocalizedString(resource_id)); } WebString BlinkPlatformImpl::QueryLocalizedString(int resource_id, const WebString& value) { if (resource_id < 0) return WebString(); std::u16string format_string = GetContentClient()->GetLocalizedString(resource_id); // If the ContentClient returned an empty string, e.g. because it's using the // default implementation of ContentClient::GetLocalizedString, return an // empty string instead of crashing with a failed DCHECK in // base::ReplaceStringPlaceholders below. This is useful for tests that don't // specialize a full ContentClient, since this way they can behave as though // there isn't a defined |resource_id| for the |name| instead of crashing // outright. if (format_string.empty()) return WebString(); return WebString::FromUTF16( base::ReplaceStringPlaceholders(format_string, value.Utf16(), nullptr)); } WebString BlinkPlatformImpl::QueryLocalizedString(int resource_id, const WebString& value1, const WebString& value2) { if (resource_id < 0) return WebString(); std::vector<std::u16string> values; values.reserve(2); values.push_back(value1.Utf16()); values.push_back(value2.Utf16()); return WebString::FromUTF16(base::ReplaceStringPlaceholders( GetContentClient()->GetLocalizedString(resource_id), values, nullptr)); } blink::WebCrypto* BlinkPlatformImpl::Crypto() { return &web_crypto_; } blink::ThreadSafeBrowserInterfaceBrokerProxy* BlinkPlatformImpl::GetBrowserInterfaceBroker() { return browser_interface_broker_proxy_.get(); } bool BlinkPlatformImpl::IsURLSavableForSavableResource( const blink::WebURL& url) { return IsSavableURL(url); } size_t BlinkPlatformImpl::MaxDecodedImageBytes() { const int kMB = 1024 * 1024; const int kMaxNumberOfBytesPerPixel = 4; #if BUILDFLAG(IS_ANDROID) if (base::SysInfo::IsLowEndDevice()) { // Limit image decoded size to 3M pixels on low end devices. // 4 is maximum number of bytes per pixel. return 3 * kMB * kMaxNumberOfBytesPerPixel; } // For other devices, limit decoded image size based on the amount of physical // memory. // In some cases all physical memory is not accessible by Chromium, as it can // be reserved for direct use by certain hardware. Thus, we set the limit so // that 1.6GB of reported physical memory on a 2GB device is enough to set the // limit at 16M pixels, which is a desirable value since 4K*4K is a relatively // common texture size. return base::SysInfo::AmountOfPhysicalMemory() / 25; #else size_t max_decoded_image_byte_limit = kNoDecodedImageByteLimit; base::CommandLine& command_line = *base::CommandLine::ForCurrentProcess(); if (command_line.HasSwitch(switches::kMaxDecodedImageSizeMb)) { if (base::StringToSizeT( command_line.GetSwitchValueASCII(switches::kMaxDecodedImageSizeMb), &max_decoded_image_byte_limit)) { max_decoded_image_byte_limit *= kMB * kMaxNumberOfBytesPerPixel; } } return max_decoded_image_byte_limit; #endif } bool BlinkPlatformImpl::IsLowEndDevice() { // This value is static for performance because calculating it is non-trivial. static bool is_low_end_device = base::SysInfo::IsLowEndDevice(); return is_low_end_device; } scoped_refptr<base::SingleThreadTaskRunner> BlinkPlatformImpl::GetIOTaskRunner() const { return io_thread_task_runner_; } scoped_refptr<base::SequencedTaskRunner> BlinkPlatformImpl::GetMediaStreamVideoSourceVideoTaskRunner() const { return media_stream_video_source_video_task_runner_; } std::unique_ptr<blink::Platform::NestedMessageLoopRunner> BlinkPlatformImpl::CreateNestedMessageLoopRunner() const { return std::make_unique<NestedMessageLoopRunnerImpl>(); } } // namespace content