
This change applies clang-tidy's modernize-use-auto [1] in /content/browser. This change does not rewrite new and cast expressions. Reproduction steps: - run clang-tidy's modernize-use-auto - run git cl format - manually remove unused typedefs due to -Wunused-local-typedef error [1] https://clang.llvm.org/extra/clang-tidy/checks/modernize-use-auto.html This CL was uploaded by git cl split. R=boliu@chromium.org, mkwst@chromium.org Bug: 890902 Change-Id: I06146497aa7a8cba7516eb17497ca33454141b2a Reviewed-on: https://chromium-review.googlesource.com/c/1257909 Reviewed-by: Daniel Cheng <dcheng@chromium.org> Reviewed-by: Mike West <mkwst@chromium.org> Reviewed-by: Bo <boliu@chromium.org> Commit-Queue: Jan Wilken Dörrie <jdoerrie@chromium.org> Cr-Commit-Position: refs/heads/master@{#597544}
663 lines
23 KiB
C++
663 lines
23 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 "base/base_switches.h"
|
|
#include "base/bind.h"
|
|
#include "base/command_line.h"
|
|
#include "base/debug/crash_logging.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/macros.h"
|
|
#include "base/metrics/field_trial.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/stl_util.h"
|
|
#include "base/strings/string_util.h"
|
|
#include "base/strings/stringprintf.h"
|
|
#include "base/synchronization/waitable_event.h"
|
|
#include "base/task/post_task.h"
|
|
#include "base/threading/thread_task_runner_handle.h"
|
|
#include "build/build_config.h"
|
|
#include "components/tracing/common/trace_startup_config.h"
|
|
#include "components/tracing/common/tracing_switches.h"
|
|
#include "content/browser/bad_message.h"
|
|
#include "content/browser/browser_main_loop.h"
|
|
#include "content/browser/histogram_controller.h"
|
|
#include "content/browser/loader/resource_message_filter.h"
|
|
#include "content/browser/service_manager/service_manager_context.h"
|
|
#include "content/browser/tracing/trace_message_filter.h"
|
|
#include "content/common/child_process_host_impl.h"
|
|
#include "content/common/service_manager/child_connection.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_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/common/connection_filter.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 "content/public/common/service_manager_connection.h"
|
|
#include "mojo/public/cpp/system/platform_handle.h"
|
|
#include "services/service_manager/embedder/switches.h"
|
|
|
|
#if defined(OS_MACOSX)
|
|
#include "content/browser/mach_broker_mac.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 NotifyProcessHostConnected(const ChildProcessData& data) {
|
|
for (auto& observer : g_browser_child_process_observers.Get())
|
|
observer.BrowserChildProcessHostConnected(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);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
BrowserChildProcessHost* BrowserChildProcessHost::Create(
|
|
content::ProcessType process_type,
|
|
BrowserChildProcessHostDelegate* delegate) {
|
|
return Create(process_type, delegate, std::string());
|
|
}
|
|
|
|
BrowserChildProcessHost* BrowserChildProcessHost::Create(
|
|
content::ProcessType process_type,
|
|
BrowserChildProcessHostDelegate* delegate,
|
|
const std::string& service_name) {
|
|
return new BrowserChildProcessHostImpl(process_type, delegate, service_name);
|
|
}
|
|
|
|
BrowserChildProcessHost* BrowserChildProcessHost::FromID(int child_process_id) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
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_MACOSX)
|
|
base::PortProvider* BrowserChildProcessHost::GetPortProvider() {
|
|
return MachBroker::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,
|
|
const std::string& service_name)
|
|
: data_(process_type),
|
|
delegate_(delegate),
|
|
channel_(nullptr),
|
|
is_channel_connected_(false),
|
|
notify_child_disconnected_(false),
|
|
weak_factory_(this) {
|
|
data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId();
|
|
|
|
child_process_host_.reset(ChildProcessHost::Create(this));
|
|
AddFilter(new TraceMessageFilter(data_.id));
|
|
|
|
g_child_process_list.Get().push_back(this);
|
|
GetContentClient()->browser()->BrowserChildProcessHostCreated(this);
|
|
|
|
if (!service_name.empty()) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
service_manager::Identity child_identity(
|
|
service_name, service_manager::mojom::kInheritUserID,
|
|
base::StringPrintf("%d", data_.id));
|
|
child_connection_.reset(
|
|
new ChildConnection(child_identity, &mojo_invitation_,
|
|
ServiceManagerContext::GetConnectorForIOThread(),
|
|
base::ThreadTaskRunnerHandle::Get()));
|
|
data_.metrics_name = service_name;
|
|
}
|
|
|
|
// Create a persistent memory segment for subprocess histograms.
|
|
CreateMetricsAllocator();
|
|
}
|
|
|
|
BrowserChildProcessHostImpl::~BrowserChildProcessHostImpl() {
|
|
g_child_process_list.Get().remove(this);
|
|
|
|
if (notify_child_disconnected_) {
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
base::BindOnce(&NotifyProcessHostDisconnected, data_.Duplicate()));
|
|
}
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::TerminateAll() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
// 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::CopyFeatureAndFieldTrialFlags(
|
|
base::CommandLine* cmd_line) {
|
|
// If we run base::FieldTrials, we want to pass to their state to the
|
|
// child process so that it can act in accordance with each state.
|
|
base::FieldTrialList::CopyFieldTrialStateToFlags(
|
|
switches::kFieldTrialHandle, switches::kEnableFeatures,
|
|
switches::kDisableFeatures, cmd_line);
|
|
}
|
|
|
|
// static
|
|
void BrowserChildProcessHostImpl::CopyTraceStartupFlags(
|
|
base::CommandLine* cmd_line) {
|
|
if (tracing::TraceStartupConfig::GetInstance()->IsEnabled()) {
|
|
const auto trace_config =
|
|
tracing::TraceStartupConfig::GetInstance()->GetTraceConfig();
|
|
if (!trace_config.IsArgumentFilterEnabled()) {
|
|
// The only trace option that we can pass through switches is the record
|
|
// mode. Other trace options should have the default value.
|
|
//
|
|
// TODO(chiniforooshan): Add other trace options to switches if, for
|
|
// example, they are used in a telemetry test that needs startup trace
|
|
// events from renderer processes.
|
|
cmd_line->AppendSwitchASCII(switches::kTraceStartup,
|
|
trace_config.ToCategoryFilterString());
|
|
cmd_line->AppendSwitchASCII(
|
|
switches::kTraceStartupRecordMode,
|
|
base::trace_event::TraceConfig::TraceRecordModeToStr(
|
|
trace_config.GetTraceRecordMode()));
|
|
}
|
|
}
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::Launch(
|
|
std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
|
|
std::unique_ptr<base::CommandLine> cmd_line,
|
|
bool terminate_on_shutdown) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
|
GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line.get(),
|
|
data_.id);
|
|
|
|
const base::CommandLine& browser_command_line =
|
|
*base::CommandLine::ForCurrentProcess();
|
|
static const char* const kForwardSwitches[] = {
|
|
service_manager::switches::kDisableInProcessStackTraces,
|
|
switches::kDisableBackgroundTasks,
|
|
switches::kDisableLogging,
|
|
switches::kEnableLogging,
|
|
switches::kIPCConnectionTimeout,
|
|
switches::kLoggingLevel,
|
|
switches::kTraceToConsole,
|
|
switches::kV,
|
|
switches::kVModule,
|
|
};
|
|
cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
|
|
arraysize(kForwardSwitches));
|
|
|
|
if (child_connection_) {
|
|
cmd_line->AppendSwitchASCII(
|
|
service_manager::switches::kServiceRequestChannelToken,
|
|
child_connection_->service_token());
|
|
}
|
|
|
|
// All processes should have a non-empty metrics name.
|
|
DCHECK(!data_.metrics_name.empty());
|
|
|
|
notify_child_disconnected_ = true;
|
|
child_process_.reset(new ChildProcessLauncher(
|
|
std::move(delegate), std::move(cmd_line), data_.id, this,
|
|
std::move(mojo_invitation_),
|
|
base::Bind(&BrowserChildProcessHostImpl::OnMojoError,
|
|
weak_factory_.GetWeakPtr(),
|
|
base::ThreadTaskRunnerHandle::Get()),
|
|
terminate_on_shutdown));
|
|
ShareMetricsAllocatorToProcess();
|
|
}
|
|
|
|
const ChildProcessData& BrowserChildProcessHostImpl::GetData() const {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
return data_;
|
|
}
|
|
|
|
ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
return child_process_host_.get();
|
|
}
|
|
|
|
const base::Process& BrowserChildProcessHostImpl::GetProcess() const {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
DCHECK(child_process_.get())
|
|
<< "Requesting a child process handle before launching.";
|
|
DCHECK(child_process_->GetProcess().IsValid())
|
|
<< "Requesting a child process handle before launch has completed OK.";
|
|
return child_process_->GetProcess();
|
|
}
|
|
|
|
std::unique_ptr<base::SharedPersistentMemoryAllocator>
|
|
BrowserChildProcessHostImpl::TakeMetricsAllocator() {
|
|
return std::move(metrics_allocator_);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::SetName(const base::string16& name) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
data_.name = name;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::SetMetricsName(
|
|
const std::string& metrics_name) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
data_.metrics_name = metrics_name;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
data_.SetHandle(handle);
|
|
}
|
|
|
|
service_manager::mojom::ServiceRequest
|
|
BrowserChildProcessHostImpl::TakeInProcessServiceRequest() {
|
|
auto invitation = std::move(mojo_invitation_);
|
|
return service_manager::mojom::ServiceRequest(
|
|
invitation.ExtractMessagePipe(child_connection_->service_token()));
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::ForceShutdown() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
g_child_process_list.Get().remove(this);
|
|
child_process_host_->ForceShutdown();
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
|
|
child_process_host_->AddFilter(filter->GetFilter());
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::BindInterface(
|
|
const std::string& interface_name,
|
|
mojo::ScopedMessagePipeHandle interface_pipe) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
if (!child_connection_)
|
|
return;
|
|
|
|
child_connection_->BindInterface(interface_name, std::move(interface_pipe));
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
|
|
ProcessType process_type) {
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.BadMessgeTerminated", process_type,
|
|
PROCESS_TYPE_MAX);
|
|
}
|
|
|
|
ChildProcessTerminationInfo BrowserChildProcessHostImpl::GetTerminationInfo(
|
|
bool known_dead) {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
if (!child_process_) {
|
|
// If the delegate doesn't use Launch() helper.
|
|
ChildProcessTerminationInfo info;
|
|
info.status =
|
|
base::GetTerminationStatus(data_.GetHandle(), &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::IO);
|
|
|
|
is_channel_connected_ = true;
|
|
notify_child_disconnected_ = true;
|
|
|
|
#if defined(OS_WIN)
|
|
// From this point onward, the exit of the child process is detected by an
|
|
// error on the IPC channel.
|
|
early_exit_watcher_.StopWatching();
|
|
#endif
|
|
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
base::BindOnce(&NotifyProcessHostConnected, data_.Duplicate()));
|
|
|
|
delegate_->OnChannelConnected(peer_pid);
|
|
|
|
if (IsProcessLaunched()) {
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
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) {
|
|
HistogramBadMessageTerminated(static_cast<ProcessType>(data_.process_type));
|
|
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
|
|
switches::kDisableKillAfterBadIPC)) {
|
|
return;
|
|
}
|
|
LOG(ERROR) << "Terminating child process for bad IPC message: " << error;
|
|
// Create a memory dump. This will contain enough stack frames to work out
|
|
// what the bad message was.
|
|
base::debug::DumpWithoutCrashing();
|
|
|
|
child_process_->Terminate(RESULT_CODE_KILLED_BAD_MESSAGE);
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnChannelInitialized(IPC::Channel* channel) {
|
|
channel_ = channel;
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnChildDisconnected() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
#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
|
|
if (child_process_.get() || data_.GetHandle()) {
|
|
ChildProcessTerminationInfo info =
|
|
GetTerminationInfo(true /* known_dead */);
|
|
#if defined(OS_ANDROID)
|
|
delegate_->OnProcessCrashed(info.exit_code);
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
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);
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
base::BindOnce(&NotifyProcessCrashed, data_.Duplicate(), info));
|
|
UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
|
|
static_cast<ProcessType>(data_.process_type),
|
|
PROCESS_TYPE_MAX);
|
|
break;
|
|
}
|
|
#if defined(OS_CHROMEOS)
|
|
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
|
|
#endif
|
|
case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
|
|
delegate_->OnProcessCrashed(info.exit_code);
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
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 defined(OS_CHROMEOS)
|
|
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
|
|
}
|
|
channel_ = nullptr;
|
|
delete delegate_; // Will delete us
|
|
}
|
|
|
|
bool BrowserChildProcessHostImpl::Send(IPC::Message* message) {
|
|
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:
|
|
// Report new processes. "Custom" ones are renumbered to 1000+ so that
|
|
// they won't conflict with any standard ones in the future.
|
|
int process_type = data_.process_type;
|
|
if (process_type >= PROCESS_TYPE_CONTENT_END)
|
|
process_type += 1000 - PROCESS_TYPE_CONTENT_END;
|
|
base::UmaHistogramSparse(
|
|
"UMA.SubprocessMetricsProvider.UntrackedProcesses", process_type);
|
|
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.
|
|
std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
|
|
if (!shm->CreateAndMapAnonymous(memory_size))
|
|
return;
|
|
metrics_allocator_.reset(new base::SharedPersistentMemoryAllocator(
|
|
std::move(shm), static_cast<uint64_t>(data_.id), metrics_name,
|
|
/*readonly=*/false));
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::ShareMetricsAllocatorToProcess() {
|
|
if (metrics_allocator_) {
|
|
HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
|
|
GetHost(),
|
|
mojo::WrapSharedMemoryHandle(
|
|
metrics_allocator_->shared_memory()->handle().Duplicate(),
|
|
metrics_allocator_->shared_memory()->mapped_size(),
|
|
mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite));
|
|
} else {
|
|
HistogramController::GetInstance()->SetHistogramMemory<ChildProcessHost>(
|
|
GetHost(), mojo::ScopedSharedBufferHandle());
|
|
}
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnProcessLaunchFailed(int error_code) {
|
|
delegate_->OnProcessLaunchFailed(error_code);
|
|
notify_child_disconnected_ = false;
|
|
delete delegate_; // Will delete us
|
|
}
|
|
|
|
void BrowserChildProcessHostImpl::OnProcessLaunched() {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
|
const base::Process& process = child_process_->GetProcess();
|
|
DCHECK(process.IsValid());
|
|
|
|
if (child_connection_)
|
|
child_connection_->SetProcessHandle(process.Handle());
|
|
|
|
#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_.SetHandle(process.Handle());
|
|
delegate_->OnProcessLaunched();
|
|
|
|
if (is_channel_connected_) {
|
|
base::PostTaskWithTraits(
|
|
FROM_HERE, {BrowserThread::UI},
|
|
base::BindOnce(&NotifyProcessLaunchedAndConnected, data_.Duplicate()));
|
|
}
|
|
}
|
|
|
|
bool BrowserChildProcessHostImpl::IsProcessLaunched() const {
|
|
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
|
|
|
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) {
|
|
if (!task_runner->BelongsToCurrentThread()) {
|
|
task_runner->PostTask(
|
|
FROM_HERE, base::BindOnce(&BrowserChildProcessHostImpl::OnMojoError,
|
|
process, task_runner, error));
|
|
return;
|
|
}
|
|
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 Mojo message: " << 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.
|
|
base::debug::ScopedCrashKeyString scoped_error_key(
|
|
bad_message::GetMojoErrorCrashKey(), error);
|
|
base::debug::DumpWithoutCrashing();
|
|
process->child_process_->Terminate(RESULT_CODE_KILLED_BAD_MESSAGE);
|
|
}
|
|
|
|
#if defined(OS_WIN)
|
|
|
|
void BrowserChildProcessHostImpl::OnObjectSignaled(HANDLE object) {
|
|
OnChildDisconnected();
|
|
}
|
|
|
|
#endif
|
|
|
|
} // namespace content
|