
Removes `#include "base/macros.h"` from files in content/ that do not contain `ignore_result(`. Bug: 1010217 No-Try: true Change-Id: I887403408704241047e3bd66e953ff7df195368b Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3274993 Commit-Queue: Peter Boström <pbos@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Owners-Override: Lei Zhang <thestig@chromium.org> Cr-Commit-Position: refs/heads/main@{#940781}
743 lines
26 KiB
C++
743 lines
26 KiB
C++
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "content/browser/browser_child_process_host_impl.h"
|
|
|
|
#include <memory>
|
|
|
|
#include "base/base_switches.h"
|
|
#include "base/bind.h"
|
|
#include "base/command_line.h"
|
|
#include "base/cxx17_backports.h"
|
|
#include "base/debug/dump_without_crashing.h"
|
|
#include "base/feature_list.h"
|
|
#include "base/files/file_path.h"
|
|
#include "base/lazy_instance.h"
|
|
#include "base/logging.h"
|
|
#include "base/metrics/histogram_functions.h"
|
|
#include "base/metrics/histogram_macros.h"
|
|
#include "base/metrics/persistent_histogram_allocator.h"
|
|
#include "base/metrics/persistent_memory_allocator.h"
|
|
#include "base/no_destructor.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/synchronization/waitable_event.h"
|
|
#include "base/threading/thread_task_runner_handle.h"
|
|
#include "base/token.h"
|
|
#include "base/trace_event/memory_dump_manager.h"
|
|
#include "build/build_config.h"
|
|
#include "build/chromeos_buildflags.h"
|
|
#include "components/tracing/common/trace_startup_config.h"
|
|
#include "components/tracing/common/tracing_switches.h"
|
|
#include "content/browser/browser_main_loop.h"
|
|
#include "content/browser/metrics/histogram_controller.h"
|
|
#include "content/browser/tracing/background_tracing_manager_impl.h"
|
|
#include "content/common/child_process_host_impl.h"
|
|
#include "content/public/browser/browser_child_process_host_delegate.h"
|
|
#include "content/public/browser/browser_child_process_observer.h"
|
|
#include "content/public/browser/browser_message_filter.h"
|
|
#include "content/public/browser/browser_task_traits.h"
|
|
#include "content/public/browser/browser_thread.h"
|
|
#include "content/public/browser/child_process_data.h"
|
|
#include "content/public/browser/content_browser_client.h"
|
|
#include "content/public/browser/resource_coordinator_service.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/process_type.h"
|
|
#include "content/public/common/result_codes.h"
|
|
#include "content/public/common/sandboxed_process_launcher_delegate.h"
|
|
#include "mojo/public/cpp/bindings/scoped_message_error_crash_key.h"
|
|
#include "mojo/public/cpp/system/platform_handle.h"
|
|
#include "services/tracing/public/cpp/trace_startup.h"
|
|
|
|
#if defined(OS_MAC)
|
|
#include "content/browser/child_process_task_port_provider_mac.h"
|
|
#include "content/browser/sandbox_support_mac_impl.h"
|
|
#include "content/common/sandbox_support_mac.mojom.h"
|
|
#endif
|
|
|
|
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
|
#include "services/tracing/public/cpp/system_tracing_service.h"
|
|
#endif
|
|
|
|
#if defined(OS_WIN)
|
|
#include "content/browser/renderer_host/dwrite_font_proxy_impl_win.h"
|
|
#include "content/public/common/font_cache_dispatcher_win.h"
|
|
#include "content/public/common/font_cache_win.mojom.h"
|
|
#endif
|
|
|
|
namespace content {
|
|
namespace {
|
|
|
|
static base::LazyInstance<
|
|
BrowserChildProcessHostImpl::BrowserChildProcessList>::DestructorAtExit
|
|
g_child_process_list = LAZY_INSTANCE_INITIALIZER;
|
|
|
|
base::LazyInstance<base::ObserverList<BrowserChildProcessObserver>::Unchecked>::
|
|
DestructorAtExit g_browser_child_process_observers =
|
|
LAZY_INSTANCE_INITIALIZER;
|
|
|
|
void NotifyProcessLaunchedAndConnected(const ChildProcessData& data) {
|
|
for (auto& observer : g_browser_child_process_observers.Get())
|
|
observer.BrowserChildProcessLaunchedAndConnected(data);
|
|
}
|
|
|
|
void NotifyProcessHostDisconnected(const ChildProcessData& data) {
|
|
for (auto& observer : g_browser_child_process_observers.Get())
|
|
observer.BrowserChildProcessHostDisconnected(data);
|
|
}
|
|
|
|
#if !defined(OS_ANDROID)
|
|
void NotifyProcessCrashed(const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) {
|
|
for (auto& observer : g_browser_child_process_observers.Get())
|
|
observer.BrowserChildProcessCrashed(data, info);
|
|
}
|
|
#endif
|
|
|
|
void NotifyProcessKilled(const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) {
|
|
for (auto& observer : g_browser_child_process_observers.Get())
|
|
observer.BrowserChildProcessKilled(data, info);
|
|
}
|
|
|
|
memory_instrumentation::mojom::ProcessType GetCoordinatorClientProcessType(
|
|
ProcessType process_type) {
|
|
switch (process_type) {
|
|
case PROCESS_TYPE_RENDERER:
|
|
return memory_instrumentation::mojom::ProcessType::RENDERER;
|
|
case PROCESS_TYPE_UTILITY:
|
|
return memory_instrumentation::mojom::ProcessType::UTILITY;
|
|
case PROCESS_TYPE_GPU:
|
|
return memory_instrumentation::mojom::ProcessType::GPU;
|
|
case PROCESS_TYPE_PPAPI_PLUGIN:
|
|
case PROCESS_TYPE_PPAPI_BROKER:
|
|
return memory_instrumentation::mojom::ProcessType::PLUGIN;
|
|
default:
|
|
NOTREACHED();
|
|
return memory_instrumentation::mojom::ProcessType::OTHER;
|
|
}
|
|
}
|
|
void BindTracedProcessFromUIThread(
|
|
base::WeakPtr<BrowserChildProcessHostImpl> weak_host,
|
|
mojo::PendingReceiver<tracing::mojom::TracedProcess> receiver) {
|
|
if (!weak_host)
|
|
return;
|
|
|
|
weak_host->GetHost()->BindReceiver(std::move(receiver));
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// static
|
|
std::unique_ptr<BrowserChildProcessHost> BrowserChildProcessHost::Create(
|
|
content::ProcessType process_type,
|
|
BrowserChildProcessHostDelegate* delegate,
|
|
ChildProcessHost::IpcMode ipc_mode) {
|
|
return std::make_unique<BrowserChildProcessHostImpl>(process_type, delegate,
|
|
ipc_mode);
|
|
}
|
|
|
|
BrowserChildProcessHost* BrowserChildProcessHost::FromID(int child_process_id) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
BrowserChildProcessHostImpl::BrowserChildProcessList* process_list =
|
|
g_child_process_list.Pointer();
|
|
for (BrowserChildProcessHostImpl* host : *process_list) {
|
|
if (host->GetData().id == child_process_id)
|
|
return host;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
#if defined(OS_MAC)
|
|
base::PortProvider* BrowserChildProcessHost::GetPortProvider() {
|
|
return ChildProcessTaskPortProvider::GetInstance();
|
|
}
|
|
#endif
|
|
|
|
// static
|
|
BrowserChildProcessHostImpl::BrowserChildProcessList*
|
|
BrowserChildProcessHostImpl::GetIterator() {
|
|
return g_child_process_list.Pointer();
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::AddObserver(
|
|
BrowserChildProcessObserver* observer) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
g_browser_child_process_observers.Get().AddObserver(observer);
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::RemoveObserver(
|
|
BrowserChildProcessObserver* observer) {
|
|
// TODO(phajdan.jr): Check thread after fixing http://crbug.com/167126.
|
|
g_browser_child_process_observers.Get().RemoveObserver(observer);
|
|
}
|
|
|
|
BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
|
|
content::ProcessType process_type,
|
|
BrowserChildProcessHostDelegate* delegate,
|
|
ChildProcessHost::IpcMode ipc_mode)
|
|
: data_(process_type), delegate_(delegate) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
|
|
|
|
child_process_host_ = ChildProcessHost::Create(this, ipc_mode);
|
|
|
|
g_child_process_list.Get().push_back(this);
|
|
GetContentClient()->browser()->BrowserChildProcessHostCreated(this);
|
|
|
|
// Create a persistent memory segment for subprocess histograms.
|
|
CreateMetricsAllocator();
|
|
}
|
|
|
|
BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
|
|
g_child_process_list.Get().remove(this);
|
|
|
|
if (notify_child_connection_status_) {
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&NotifyProcessHostDisconnected, data_.Duplicate()));
|
|
}
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::TerminateAll() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
// Make a copy since the BrowserChildProcessHost dtor mutates the original
|
|
// list.
|
|
BrowserChildProcessList copy = g_child_process_list.Get();
|
|
for (auto it = copy.begin(); it != copy.end(); ++it) {
|
|
delete (*it)->delegate(); // ~*HostDelegate deletes *HostImpl.
|
|
}
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::CopyTraceStartupFlags(
|
|
base::CommandLine* cmd_line) {
|
|
tracing::PropagateTracingFlagsToChildProcessCmdLine(cmd_line);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::Launch(
|
|
std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
|
|
std::unique_ptr<base::CommandLine> cmd_line,
|
|
bool terminate_on_shutdown) {
|
|
LaunchWithPreloadedFiles(std::move(delegate), std::move(cmd_line),
|
|
/*files_to_preload=*/{}, terminate_on_shutdown);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::LaunchWithPreloadedFiles(
|
|
std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
|
|
std::unique_ptr<base::CommandLine> cmd_line,
|
|
std::map<std::string, base::FilePath> files_to_preload,
|
|
bool terminate_on_shutdown) {
|
|
GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line.get(),
|
|
data_.id);
|
|
LaunchWithoutExtraCommandLineSwitches(
|
|
std::move(delegate), std::move(cmd_line), std::move(files_to_preload),
|
|
terminate_on_shutdown);
|
|
}
|
|
|
|
const ChildProcessData& BrowserChildProcessHostImpl::GetData() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
return data_;
|
|
}
|
|
|
|
ChildProcessHost* BrowserChildProcessHostImpl::GetHost() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
return child_process_host_.get();
|
|
}
|
|
|
|
const base::Process& BrowserChildProcessHostImpl::GetProcess() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
return data_.GetProcess();
|
|
}
|
|
|
|
std::unique_ptr<base::PersistentMemoryAllocator>
|
|
BrowserChildProcessHostImpl::TakeMetricsAllocator() {
|
|
return std::move(metrics_allocator_);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::SetName(const std::u16string& name) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
data_.name = name;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::SetMetricsName(
|
|
const std::string& metrics_name) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
data_.metrics_name = metrics_name;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::SetProcess(base::Process process) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
data_.SetProcess(std::move(process));
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::ForceShutdown() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
g_child_process_list.Get().remove(this);
|
|
child_process_host_->ForceShutdown();
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
|
|
child_process_host_->AddFilter(filter->GetFilter());
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::LaunchWithoutExtraCommandLineSwitches(
|
|
std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
|
|
std::unique_ptr<base::CommandLine> cmd_line,
|
|
std::map<std::string, base::FilePath> files_to_preload,
|
|
bool terminate_on_shutdown) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
const base::CommandLine& browser_command_line =
|
|
*base::CommandLine::ForCurrentProcess();
|
|
static const char* const kForwardSwitches[] = {
|
|
switches::kDisableInProcessStackTraces,
|
|
switches::kDisableBestEffortTasks,
|
|
switches::kDisableLogging,
|
|
switches::kEnableLogging,
|
|
switches::kIPCConnectionTimeout,
|
|
switches::kLogBestEffortTasks,
|
|
switches::kLogFile,
|
|
switches::kLoggingLevel,
|
|
switches::kMojoCoreLibraryPath,
|
|
switches::kPerfettoDisableInterning,
|
|
switches::kTraceToConsole,
|
|
switches::kV,
|
|
switches::kVModule,
|
|
};
|
|
cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
|
|
base::size(kForwardSwitches));
|
|
|
|
// All processes should have a non-empty metrics name.
|
|
if (data_.metrics_name.empty())
|
|
data_.metrics_name = GetProcessTypeNameInEnglish(data_.process_type);
|
|
|
|
data_.sandbox_type = delegate->GetSandboxType();
|
|
|
|
// Note that if this host has a legacy IPC Channel, we don't dispatch any
|
|
// connection status notifications until we observe OnChannelConnected().
|
|
if (!has_legacy_ipc_channel_)
|
|
notify_child_connection_status_ = true;
|
|
|
|
child_process_ = std::make_unique<ChildProcessLauncher>(
|
|
std::move(delegate), std::move(cmd_line), data_.id, this,
|
|
std::move(*child_process_host_->GetMojoInvitation()),
|
|
base::BindRepeating(&BrowserChildProcessHostImpl::OnMojoError,
|
|
weak_factory_.GetWeakPtr(),
|
|
base::ThreadTaskRunnerHandle::Get()),
|
|
std::move(files_to_preload), terminate_on_shutdown);
|
|
ShareMetricsAllocatorToProcess();
|
|
|
|
if (!has_legacy_ipc_channel_)
|
|
OnProcessConnected();
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
|
|
ProcessType process_type) {
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.BadMessgeTerminated", process_type,
|
|
PROCESS_TYPE_MAX);
|
|
}
|
|
|
|
#if defined(OS_ANDROID)
|
|
void BrowserChildProcessHostImpl::EnableWarmUpConnection() {
|
|
can_use_warm_up_connection_ = true;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::DumpProcessStack() {
|
|
if (!child_process_)
|
|
return;
|
|
child_process_->DumpProcessStack();
|
|
}
|
|
#endif
|
|
|
|
ChildProcessTerminationInfo BrowserChildProcessHostImpl::GetTerminationInfo(
|
|
bool known_dead) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
if (!child_process_) {
|
|
// If the delegate doesn't use Launch() helper.
|
|
ChildProcessTerminationInfo info;
|
|
info.status = base::GetTerminationStatus(data_.GetProcess().Handle(),
|
|
&info.exit_code);
|
|
return info;
|
|
}
|
|
return child_process_->GetChildTerminationInfo(known_dead);
|
|
}
|
|
|
|
bool BrowserChildProcessHostImpl::OnMessageReceived(
|
|
const IPC::Message& message) {
|
|
return delegate_->OnMessageReceived(message);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
DCHECK(has_legacy_ipc_channel_);
|
|
notify_child_connection_status_ = true;
|
|
|
|
delegate_->OnChannelConnected(peer_pid);
|
|
|
|
OnProcessConnected();
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnProcessConnected() {
|
|
#if defined(OS_WIN)
|
|
// From this point onward, the exit of the child process is detected by an
|
|
// error on the IPC channel or ChildProcessHost pipe.
|
|
early_exit_watcher_.StopWatching();
|
|
#endif
|
|
|
|
if (IsProcessLaunched()) {
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&NotifyProcessLaunchedAndConnected, data_.Duplicate()));
|
|
}
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnChannelError() {
|
|
delegate_->OnChannelError();
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnBadMessageReceived(
|
|
const IPC::Message& message) {
|
|
std::string log_message = "Bad message received of type: ";
|
|
if (message.IsValid()) {
|
|
log_message += std::to_string(message.type());
|
|
} else {
|
|
log_message += "unknown";
|
|
}
|
|
TerminateOnBadMessageReceived(log_message);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::TerminateOnBadMessageReceived(
|
|
const std::string& error) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
// Create a memory dump. This will contain enough stack frames to work out
|
|
// what the bad message was.
|
|
base::debug::DumpWithoutCrashing();
|
|
|
|
TerminateProcessForBadMessage(weak_factory_.GetWeakPtr(), error);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnChannelInitialized(IPC::Channel* channel) {
|
|
has_legacy_ipc_channel_ = true;
|
|
|
|
// When using a legacy IPC Channel, we defer any notifications until the
|
|
// Channel handshake is complete. See OnChannelConnected().
|
|
notify_child_connection_status_ = false;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnChildDisconnected() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
tracing_registration_.reset();
|
|
|
|
#if defined(OS_WIN)
|
|
// OnChildDisconnected may be called without OnChannelConnected, so stop the
|
|
// early exit watcher so GetTerminationStatus can close the process handle.
|
|
early_exit_watcher_.StopWatching();
|
|
#endif
|
|
const base::Process& process = data_.GetProcess();
|
|
if (child_process_.get() || (process.IsValid() && !process.is_current())) {
|
|
ChildProcessTerminationInfo info =
|
|
GetTerminationInfo(true /* known_dead */);
|
|
#if defined(OS_ANDROID)
|
|
// Do not treat clean_exit, ie when child process exited due to quitting
|
|
// its main loop, as a crash.
|
|
if (!info.clean_exit) {
|
|
delegate_->OnProcessCrashed(info.exit_code);
|
|
}
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&NotifyProcessKilled, data_.Duplicate(), info));
|
|
#else // OS_ANDROID
|
|
switch (info.status) {
|
|
case base::TERMINATION_STATUS_PROCESS_CRASHED:
|
|
case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: {
|
|
delegate_->OnProcessCrashed(info.exit_code);
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&NotifyProcessCrashed, data_.Duplicate(), info));
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
|
|
static_cast<ProcessType>(data_.process_type),
|
|
PROCESS_TYPE_MAX);
|
|
break;
|
|
}
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
|
|
#endif
|
|
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
|
|
delegate_->OnProcessCrashed(info.exit_code);
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&NotifyProcessKilled, data_.Duplicate(), info));
|
|
// Report that this child process was killed.
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2",
|
|
static_cast<ProcessType>(data_.process_type),
|
|
PROCESS_TYPE_MAX);
|
|
break;
|
|
}
|
|
case base::TERMINATION_STATUS_STILL_RUNNING: {
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive2",
|
|
static_cast<ProcessType>(data_.process_type),
|
|
PROCESS_TYPE_MAX);
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
#endif // OS_ANDROID
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected2",
|
|
static_cast<ProcessType>(data_.process_type),
|
|
PROCESS_TYPE_MAX);
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
if (info.status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2.OOM",
|
|
static_cast<ProcessType>(data_.process_type),
|
|
PROCESS_TYPE_MAX);
|
|
}
|
|
#endif
|
|
}
|
|
delete delegate_; // Will delete us
|
|
}
|
|
|
|
bool BrowserChildProcessHostImpl::Send(IPC::Message* message) {
|
|
DCHECK(has_legacy_ipc_channel_);
|
|
return child_process_host_->Send(message);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::CreateMetricsAllocator() {
|
|
// Create a persistent memory segment for subprocess histograms only if
|
|
// they're active in the browser.
|
|
// TODO(bcwhite): Remove this once persistence is always enabled.
|
|
if (!base::GlobalHistogramAllocator::Get())
|
|
return;
|
|
|
|
// Determine the correct parameters based on the process type.
|
|
size_t memory_size;
|
|
base::StringPiece metrics_name;
|
|
switch (data_.process_type) {
|
|
case PROCESS_TYPE_UTILITY:
|
|
// This needs to be larger for the network service.
|
|
memory_size = 256 << 10; // 256 KiB
|
|
metrics_name = "UtilityMetrics";
|
|
break;
|
|
|
|
case PROCESS_TYPE_ZYGOTE:
|
|
memory_size = 64 << 10; // 64 KiB
|
|
metrics_name = "ZygoteMetrics";
|
|
break;
|
|
|
|
case PROCESS_TYPE_SANDBOX_HELPER:
|
|
memory_size = 64 << 10; // 64 KiB
|
|
metrics_name = "SandboxHelperMetrics";
|
|
break;
|
|
|
|
case PROCESS_TYPE_GPU:
|
|
// This needs to be larger for the display-compositor in the gpu process.
|
|
memory_size = 256 << 10; // 256 KiB
|
|
metrics_name = "GpuMetrics";
|
|
break;
|
|
|
|
case PROCESS_TYPE_PPAPI_PLUGIN:
|
|
memory_size = 64 << 10; // 64 KiB
|
|
metrics_name = "PpapiPluginMetrics";
|
|
break;
|
|
|
|
case PROCESS_TYPE_PPAPI_BROKER:
|
|
memory_size = 64 << 10; // 64 KiB
|
|
metrics_name = "PpapiBrokerMetrics";
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
// Create the shared memory segment and attach an allocator to it.
|
|
// Mapping the memory shouldn't fail but be safe if it does; everything
|
|
// will continue to work but just as if persistence weren't available.
|
|
base::WritableSharedMemoryRegion shm_region =
|
|
base::WritableSharedMemoryRegion::Create(memory_size);
|
|
base::WritableSharedMemoryMapping shm_mapping = shm_region.Map();
|
|
if (!shm_region.IsValid() || !shm_mapping.IsValid())
|
|
return;
|
|
metrics_allocator_ =
|
|
std::make_unique<base::WritableSharedPersistentMemoryAllocator>(
|
|
std::move(shm_mapping), static_cast<uint64_t>(data_.id),
|
|
metrics_name);
|
|
metrics_shared_region_ = std::move(shm_region);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::ShareMetricsAllocatorToProcess() {
|
|
if (metrics_allocator_) {
|
|
HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
|
|
GetHost(), std::move(metrics_shared_region_));
|
|
} else {
|
|
HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
|
|
GetHost(), base::WritableSharedMemoryRegion());
|
|
}
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnProcessLaunchFailed(int error_code) {
|
|
delegate_->OnProcessLaunchFailed(error_code);
|
|
notify_child_connection_status_ = false;
|
|
delete delegate_; // Will delete us
|
|
}
|
|
|
|
#if defined(OS_ANDROID)
|
|
bool BrowserChildProcessHostImpl::CanUseWarmUpConnection() {
|
|
return can_use_warm_up_connection_;
|
|
}
|
|
#endif
|
|
|
|
void BrowserChildProcessHostImpl::OnProcessLaunched() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
const base::Process& process = child_process_->GetProcess();
|
|
DCHECK(process.IsValid());
|
|
|
|
#if defined(OS_MAC)
|
|
ChildProcessTaskPortProvider::GetInstance()->OnChildProcessLaunched(
|
|
process.Pid(),
|
|
static_cast<ChildProcessHostImpl*>(child_process_host_.get())
|
|
->child_process());
|
|
#endif
|
|
|
|
#if defined(OS_WIN)
|
|
// Start a WaitableEventWatcher that will invoke OnProcessExitedEarly if the
|
|
// child process exits. This watcher is stopped once the IPC channel is
|
|
// connected and the exit of the child process is detecter by an error on the
|
|
// IPC channel thereafter.
|
|
DCHECK(!early_exit_watcher_.GetWatchedObject());
|
|
early_exit_watcher_.StartWatchingOnce(process.Handle(), this);
|
|
#endif
|
|
|
|
data_.SetProcess(process.Duplicate());
|
|
delegate_->OnProcessLaunched();
|
|
|
|
if (notify_child_connection_status_) {
|
|
GetUIThreadTaskRunner({})->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(&NotifyProcessLaunchedAndConnected, data_.Duplicate()));
|
|
}
|
|
|
|
#if BUILDFLAG(IS_CHROMEOS_ASH)
|
|
// In ChromeOS, there are still child processes of NaCl modules, and they
|
|
// don't contribute to tracing actually. So do not register those clients
|
|
// to the tracing service. See https://crbug.com/1101468.
|
|
if (data_.process_type >= PROCESS_TYPE_CONTENT_END)
|
|
return;
|
|
#endif
|
|
|
|
tracing_registration_ = TracingServiceController::Get().RegisterClient(
|
|
process.Pid(), base::BindRepeating(&BindTracedProcessFromUIThread,
|
|
weak_factory_.GetWeakPtr()));
|
|
BackgroundTracingManagerImpl::ActivateForProcess(
|
|
GetData().id,
|
|
static_cast<ChildProcessHostImpl*>(GetHost())->child_process());
|
|
|
|
#if defined(OS_POSIX) && !defined(OS_ANDROID)
|
|
system_tracing_service_ = std::make_unique<tracing::SystemTracingService>();
|
|
child_process()->EnableSystemTracingService(
|
|
system_tracing_service_->BindAndPassPendingRemote());
|
|
#endif
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::RegisterCoordinatorClient(
|
|
mojo::PendingReceiver<memory_instrumentation::mojom::Coordinator> receiver,
|
|
mojo::PendingRemote<memory_instrumentation::mojom::ClientProcess>
|
|
client_process) {
|
|
// Intentionally disallow non-browser processes from getting a Coordinator.
|
|
receiver.reset();
|
|
|
|
// The child process may have already terminated by the time this message is
|
|
// dispatched. We do nothing in that case.
|
|
if (!IsProcessLaunched())
|
|
return;
|
|
|
|
base::trace_event::MemoryDumpManager::GetInstance()
|
|
->GetDumpThreadTaskRunner()
|
|
->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(
|
|
[](mojo::PendingReceiver<
|
|
memory_instrumentation::mojom::Coordinator> receiver,
|
|
mojo::PendingRemote<
|
|
memory_instrumentation::mojom::ClientProcess>
|
|
client_process,
|
|
memory_instrumentation::mojom::ProcessType process_type,
|
|
base::ProcessId process_id,
|
|
absl::optional<std::string> service_name) {
|
|
GetMemoryInstrumentationRegistry()->RegisterClientProcess(
|
|
std::move(receiver), std::move(client_process),
|
|
process_type, process_id, std::move(service_name));
|
|
},
|
|
std::move(receiver), std::move(client_process),
|
|
GetCoordinatorClientProcessType(
|
|
static_cast<ProcessType>(data_.process_type)),
|
|
child_process_->GetProcess().Pid(), delegate_->GetServiceName()));
|
|
}
|
|
|
|
bool BrowserChildProcessHostImpl::IsProcessLaunched() const {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::UI);
|
|
|
|
return child_process_.get() && child_process_->GetProcess().IsValid();
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::OnMojoError(
|
|
base::WeakPtr<BrowserChildProcessHostImpl> process,
|
|
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
|
|
const std::string& error) {
|
|
// Create a memory dump with the error message captured in a crash key value.
|
|
// This will make it easy to determine details about what interface call
|
|
// failed.
|
|
//
|
|
// It is important to call DumpWithoutCrashing synchronously - this will help
|
|
// to preserve the callstack and the crash keys present when the bad mojo
|
|
// message was received.
|
|
mojo::debug::ScopedMessageErrorCrashKey scoped_error_key(error);
|
|
base::debug::DumpWithoutCrashing();
|
|
|
|
if (task_runner->BelongsToCurrentThread()) {
|
|
TerminateProcessForBadMessage(process, error);
|
|
} else {
|
|
task_runner->PostTask(
|
|
FROM_HERE,
|
|
base::BindOnce(
|
|
&BrowserChildProcessHostImpl::TerminateProcessForBadMessage,
|
|
process, error));
|
|
}
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::TerminateProcessForBadMessage(
|
|
base::WeakPtr<BrowserChildProcessHostImpl> process,
|
|
const std::string& error) {
|
|
if (!process)
|
|
return;
|
|
HistogramBadMessageTerminated(
|
|
static_cast<ProcessType>(process->data_.process_type));
|
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
switches::kDisableKillAfterBadIPC)) {
|
|
return;
|
|
}
|
|
LOG(ERROR) << "Terminating child process for bad message: " << error;
|
|
process->child_process_->Terminate(RESULT_CODE_KILLED_BAD_MESSAGE);
|
|
}
|
|
|
|
#if defined(OS_WIN)
|
|
|
|
void BrowserChildProcessHostImpl::OnObjectSignaled(HANDLE object) {
|
|
OnChildDisconnected();
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace content
|