android_webview
apps
ash
base
build
build_overrides
buildtools
cc
chrome
chromecast
chromeos
clank
codelabs
components
content
app
app_shim_remote_cocoa
browser
accessibility
aggregation_service
ai
android
attribution_reporting
audio
background_fetch
background_sync
blob_storage
bluetooth
broadcast_channel
browser_plugin
browsing_data
browsing_topics
btm
buckets
cache_storage
client_hints
closewatcher
cocoa
code_cache
compositor
compute_pressure
contacts
content_index
cookie_deprecation_label
cookie_insight_list
cookie_store
date_time_chooser
device
device_posture
device_sensors
devtools
direct_sockets
display_cutout
dom_storage
download
fenced_frame
file_system
file_system_access
fingerprinting_protection
first_party_sets
font_access
font_unique_name_lookup
generic_sensor
geolocation
gpu
handwriting
hid
hyphenation
idle
image_capture
indexed_db
installedapp
interest_group
keyboard_lock
loader
lock_screen
locks
manifest
media
media_session
memory
memory_pressure
metrics
navigation_transitions
network
notifications
origin_trials
payments
performance_manager
permissions
picture_in_picture
preloading
presentation
private_aggregation
process_internals
push_messaging
quota
reduce_accept_language
renderer_host
resources
scheduler
screen_details
screen_orientation
screenlock_monitor
security
serial
service_host
service_worker
shape_detection
shared_storage
smart_card
sms
speech
ssl
storage_access
system_dns_resolution
tpcd_heuristics
tracing
usb
wake_lock
web_contents
web_database
web_package
webauth
webid
webrtc
websockets
webtransport
webui
worker_host
xr
zygote_host
BACK_FORWARD_CACHE_OWNERS
BUILD.gn
CHILD_PROCESS_SECURITY_POLICY_OWNERS
DEPS
OWNERS
PRESUBMIT.py
README.md
about_url_loader_factory.cc
about_url_loader_factory.h
accent_color_browsertest.cc
after_startup_task_utils.cc
after_startup_task_utils.h
agent_cluster_key.cc
agent_cluster_key.h
agent_cluster_key_unittest.cc
back_forward_cache_basics_browsertest.cc
back_forward_cache_browsertest.cc
back_forward_cache_browsertest.h
back_forward_cache_features_browsertest.cc
back_forward_cache_internal_browsertest.cc
back_forward_cache_network_request_browsertest.cc
back_forward_cache_no_store_browsertest.cc
back_forward_cache_not_restored_reasons_browsertest.cc
back_forward_cache_test_util.cc
back_forward_cache_test_util.h
bad_message.cc
bad_message.h
battery_monitor_browsertest.cc
bookmarklet_browsertest.cc
browser_child_process_host_impl.cc
browser_child_process_host_impl.h
browser_child_process_host_impl_receiver_bindings.cc
browser_child_process_observer_browsertest.cc
browser_context.cc
browser_context_impl.cc
browser_context_impl.h
browser_interface_binders.cc
browser_interface_binders.h
browser_interface_broker_impl.h
browser_main.cc
browser_main.h
browser_main_loop.cc
browser_main_loop.h
browser_main_loop_unittest.cc
browser_main_runner_impl.cc
browser_main_runner_impl.h
browser_process_io_thread.cc
browser_process_io_thread.h
browser_task_traits_nocompile.nc
browser_thread_browsertest.cc
browser_thread_impl.cc
browser_thread_impl.h
browser_thread_nocompile.nc
browser_thread_unittest.cc
browser_url_handler_impl.cc
browser_url_handler_impl.h
browser_url_handler_impl_unittest.cc
browsing_instance.cc
browsing_instance.h
byte_stream.cc
byte_stream.h
byte_stream_unittest.cc
can_commit_status.h
child_process_host_impl.cc
child_process_host_impl.h
child_process_launcher.cc
child_process_launcher.h
child_process_launcher_browsertest.cc
child_process_launcher_helper.cc
child_process_launcher_helper.h
child_process_launcher_helper_android.cc
child_process_launcher_helper_fuchsia.cc
child_process_launcher_helper_ios.mm
child_process_launcher_helper_linux.cc
child_process_launcher_helper_mac.cc
child_process_launcher_helper_posix.cc
child_process_launcher_helper_posix.h
child_process_launcher_helper_tvos.mm
child_process_launcher_helper_win.cc
child_process_sandbox_support_win_unittest.cc
child_process_security_policy_browsertest.cc
child_process_security_policy_impl.cc
child_process_security_policy_impl.h
child_process_security_policy_unittest.cc
child_process_task_port_provider_mac.cc
child_process_task_port_provider_mac.h
child_process_task_port_provider_mac_unittest.cc
child_thread_type_switcher_linux.cc
child_thread_type_switcher_linux.h
content_security_policy_browsertest.cc
context_factory.cc
cross_site_transfer_browsertest.cc
data_decoder_browsertest.cc
data_url_loader_factory.cc
data_url_loader_factory.h
database_browsertest.cc
do_not_track_browsertest.cc
eye_dropper_chooser_impl.cc
eye_dropper_chooser_impl.h
feature_observer.cc
feature_observer.h
field_trial_recorder.cc
field_trial_recorder.h
field_trial_synchronizer.cc
field_trial_synchronizer.h
find_in_page_client.cc
find_in_page_client.h
find_request_manager.cc
find_request_manager.h
find_request_manager_browsertest.cc
font_list_async.cc
font_preferences_browsertest.cc
font_service.cc
font_service.h
form_controls_browsertest.cc
framebusting_browsertest.cc
guest_page_holder_impl.cc
guest_page_holder_impl.h
host_zoom_level_context.cc
host_zoom_level_context.h
host_zoom_map_impl.cc
host_zoom_map_impl.h
host_zoom_map_impl_browsertest.cc
host_zoom_map_impl_unittest.cc
in_memory_federated_permission_context.cc
in_memory_federated_permission_context.h
isolated_origin_browsertest.cc
isolated_origin_util.cc
isolated_origin_util.h
isolation_context.cc
isolation_context.h
keyboard_lock_browsertest.cc
keyboard_lock_browsertest.h
keyboard_lock_browsertest_ios.mm
keyboard_lock_browsertest_mac.mm
largest_contentful_paint_browsertests.cc
launch_as_mojo_client_browsertest.cc
log_console_message.cc
log_console_message.h
message_port_close_event_browsertest.cc
message_port_provider.cc
message_port_provider_browsertest.cc
mime_registry_impl.cc
mime_registry_impl.h
mojo_binder_policy_applier.cc
mojo_binder_policy_applier.h
mojo_binder_policy_applier_unittest.cc
mojo_binder_policy_map_impl.cc
mojo_binder_policy_map_impl.h
mojo_binder_policy_map_impl_unittest.cc
mojo_sandbox_browsertest.cc
native_profiling.pdl
navigation_browsertest.cc
navigation_mhtml_browsertest.cc
navigation_or_document_handle.cc
navigation_or_document_handle.h
navigation_subresource_loader_params.cc
navigation_subresource_loader_params.h
net_info_browsertest.cc
network_context_client_base_impl.cc
network_context_client_base_impl.h
network_context_client_base_impl_unittest.cc
network_sandbox.cc
network_sandbox.h
network_sandbox_grant_result.h
network_service_browsertest.cc
network_service_client.cc
network_service_client.h
network_service_instance_impl.cc
network_service_instance_impl.h
network_service_instance_impl_unittest.cc
network_service_restart_browsertest.cc
origin_agent_cluster_isolation_state.cc
origin_agent_cluster_isolation_state.h
per_web_ui_browser_interface_broker.cc
performance_memory_browsertest.cc
performance_timeline_browsertest.cc
plugin_list.cc
plugin_list.h
plugin_list_unittest.cc
plugin_service_impl.cc
plugin_service_impl.h
plugin_service_impl_browsertest.cc
pointer_lock_browsertest.cc
pointer_lock_browsertest.h
pointer_lock_browsertest_ios.mm
pointer_lock_browsertest_mac.mm
posix_file_descriptor_info_impl.cc
posix_file_descriptor_info_impl.h
posix_file_descriptor_info_impl_unittest.cc
power_monitor_browsertest.cc
ppapi_plugin_process_host.cc
ppapi_plugin_process_host.h
ppapi_plugin_process_host_receiver_bindings.cc
ppapi_plugin_sandboxed_process_launcher_delegate.cc
ppapi_plugin_sandboxed_process_launcher_delegate.h
process_lock.cc
process_lock.h
process_reuse_policy.h
process_visibility_util.cc
profiling_utils.cc
resource_context_impl.cc
resource_context_impl.h
resource_coordinator_service.cc
resource_loading_browsertest.cc
sandbox_host_linux.cc
sandbox_host_linux.h
sandbox_ipc_linux.cc
sandbox_ipc_linux.h
sandbox_mac_unittest.mm
sandbox_parameters_mac.h
sandbox_parameters_mac.mm
sandbox_support_impl.h
sandbox_support_mac_impl.mm
sandbox_support_win_impl.cc
scoped_active_url.cc
scoped_active_url.h
security_exploit_browsertest.cc
session_history_browsertest.cc
shareable_file_reference_unittest.cc
site_info.cc
site_info.h
site_instance_group.cc
site_instance_group.h
site_instance_group_browsertest.cc
site_instance_group_unittest.cc
site_instance_impl.cc
site_instance_impl.h
site_instance_impl_unittest.cc
site_isolation_policy_unittest.cc
site_per_process_browsertest.cc
site_per_process_browsertest.h
site_per_process_hit_test_browsertest.cc
site_per_process_layout_browsertest.cc
site_per_process_mac_browsertest.mm
site_per_process_mixed_content_browsertest.cc
site_per_process_oopsif_browsertest.cc
site_per_process_sad_frame_browsertest.cc
site_per_process_scroll_browsertest.cc
site_per_process_unload_browsertest.cc
snapshot_browsertest.cc
ssl_private_key_impl.cc
ssl_private_key_impl.h
startup_data_impl.cc
startup_data_impl.h
startup_helper.cc
startup_helper.h
startup_task_runner.cc
startup_task_runner.h
startup_task_runner_unittest.cc
storage_partition_config_unittest.cc
storage_partition_impl.cc
storage_partition_impl.h
storage_partition_impl_browsertest.cc
storage_partition_impl_map.cc
storage_partition_impl_map.h
storage_partition_impl_map_unittest.cc
storage_partition_impl_unittest.cc
storage_service_restart_browsertest.cc
storage_service_sandbox_browsertest.cc
synthetic_trial_syncer.cc
text_fragment_browsertest.cc
theme_helper.cc
theme_helper.h
theme_helper_mac.h
theme_helper_mac.mm
ukm_internals_ui.cc
ukm_internals_ui.h
url_info.cc
url_info.h
url_loader_factory_params_helper.cc
url_loader_factory_params_helper.h
v8_snapshot_files.cc
v8_snapshot_files.h
vibration_browsertest.cc
video_capture_service_impl.cc
video_capture_service_impl.h
web_exposed_isolation_info.cc
web_exposed_isolation_info.h
web_exposed_isolation_info_nocompile.nc
web_exposed_isolation_info_unittest.cc
web_ui_browser_interface_broker_registry.cc
webkit_browsertest.cc
worker_network_isolation_key_browsertest.cc
zoom_browsertest.cc
child
common
gpu
ppapi_plugin
public
renderer
services
shell
test
utility
web_test
zygote
BUILD.gn
DEPS
DIR_METADATA
OWNERS
README.md
architecture.png
content_resources.grd
crypto
dbus
device
docs
extensions
fuchsia_web
gin
google_apis
gpu
headless
infra
internal
ios
ios_internal
ipc
media
mojo
native_client
native_client_sdk
net
pdf
ppapi
printing
remoting
rlz
sandbox
services
signing_keys
skia
sql
storage
styleguide
testing
third_party
tools
ui
url
v8
webkit
.clang-format
.clang-tidy
.clangd
.git-blame-ignore-revs
.gitallowed
.gitattributes
.gitignore
.gitmodules
.gn
.mailmap
.rustfmt.toml
.vpython3
.yapfignore
ATL_OWNERS
AUTHORS
BUILD.gn
CODE_OF_CONDUCT.md
CPPLINT.cfg
CRYPTO_OWNERS
DEPS
DIR_METADATA
LICENSE
LICENSE.chromium_os
OWNERS
PRESUBMIT.py
PRESUBMIT_test.py
PRESUBMIT_test_mocks.py
README.md
WATCHLISTS
codereview.settings

This change moves service process host code into its own service_host folder. This change should modify no functionality. Bug: 41493609 Change-Id: I5b760717dc42340921bf7d6699c147baa2772cf2 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6089368 Reviewed-by: Alex Moshchuk <alexmos@chromium.org> Reviewed-by: Alex Gough <ajgo@chromium.org> Commit-Queue: Emily Andrews <emiled@microsoft.com> Cr-Commit-Position: refs/heads/main@{#1424005}
582 lines
19 KiB
C++
582 lines
19 KiB
C++
// Copyright 2022 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/public/browser/browser_child_process_observer.h"
|
|
|
|
#include "base/functional/bind.h"
|
|
#include "base/run_loop.h"
|
|
#include "build/build_config.h"
|
|
#include "content/browser/browser_child_process_host_impl.h"
|
|
#include "content/browser/child_process_host_impl.h"
|
|
#include "content/browser/service_host/utility_process_host.h"
|
|
#include "content/public/browser/browser_child_process_host.h"
|
|
#include "content/public/browser/browser_child_process_host_delegate.h"
|
|
#include "content/public/browser/child_process_data.h"
|
|
#include "content/public/common/content_switches.h"
|
|
#include "content/public/common/process_type.h"
|
|
#include "content/public/common/sandboxed_process_launcher_delegate.h"
|
|
#include "content/public/test/browser_test.h"
|
|
#include "content/public/test/content_browser_test.h"
|
|
#include "content/public/test/test_service.mojom.h"
|
|
#include "sandbox/policy/sandbox_type.h"
|
|
#include "testing/gmock/include/gmock/gmock.h"
|
|
|
|
namespace content {
|
|
|
|
namespace {
|
|
|
|
// An enum that represent the different type of notitifcations that exist in
|
|
// BrowserChildProcessObserver.
|
|
enum class Notification {
|
|
kLaunchedAndConnected,
|
|
kDisconnected,
|
|
kCrashed,
|
|
kKilled,
|
|
kLaunchFailed,
|
|
kExitedNormally,
|
|
};
|
|
|
|
// Nicer test output.
|
|
std::ostream& operator<<(std::ostream& os, Notification notification) {
|
|
switch (notification) {
|
|
case Notification::kLaunchedAndConnected:
|
|
os << "LaunchedAndConnected";
|
|
break;
|
|
case Notification::kDisconnected:
|
|
os << "Disconnected";
|
|
break;
|
|
case Notification::kCrashed:
|
|
os << "Crashed";
|
|
break;
|
|
case Notification::kKilled:
|
|
os << "Killed";
|
|
break;
|
|
case Notification::kLaunchFailed:
|
|
os << "LaunchFailed";
|
|
break;
|
|
case Notification::kExitedNormally:
|
|
os << "ExitedNormally";
|
|
break;
|
|
}
|
|
return os;
|
|
}
|
|
|
|
// Returns true if a child process whose ID is |child_id| is still alive.
|
|
bool IsHostAlive(int child_id) {
|
|
return BrowserChildProcessHost::FromID(child_id) != nullptr;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// A test BrowserChildProcessObserver that transforms every call to one of the
|
|
// observer's method to a call to the notification callback.
|
|
class BrowserChildProcessNotificationObserver
|
|
: public BrowserChildProcessObserver {
|
|
public:
|
|
using OnNotificationCallback =
|
|
base::RepeatingCallback<void(Notification notification)>;
|
|
|
|
BrowserChildProcessNotificationObserver(
|
|
int child_id,
|
|
OnNotificationCallback on_notification_callback)
|
|
: child_id_(child_id),
|
|
on_notification_callback_(std::move(on_notification_callback)) {
|
|
BrowserChildProcessObserver::Add(this);
|
|
}
|
|
|
|
~BrowserChildProcessNotificationObserver() override {
|
|
BrowserChildProcessObserver::Remove(this);
|
|
}
|
|
|
|
protected:
|
|
// BrowserChildProcessObserver:
|
|
void BrowserChildProcessLaunchedAndConnected(
|
|
const ChildProcessData& data) override {
|
|
OnNotification(data, Notification::kLaunchedAndConnected);
|
|
}
|
|
void BrowserChildProcessHostDisconnected(
|
|
const ChildProcessData& data) override {
|
|
OnNotification(data, Notification::kDisconnected);
|
|
}
|
|
void BrowserChildProcessCrashed(
|
|
const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) override {
|
|
OnNotification(data, Notification::kCrashed);
|
|
}
|
|
void BrowserChildProcessKilled(
|
|
const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) override {
|
|
OnNotification(data, Notification::kKilled);
|
|
}
|
|
void BrowserChildProcessLaunchFailed(
|
|
const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) override {
|
|
OnNotification(data, Notification::kLaunchFailed);
|
|
}
|
|
void BrowserChildProcessExitedNormally(
|
|
const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) override {
|
|
OnNotification(data, Notification::kExitedNormally);
|
|
}
|
|
|
|
void OnNotification(const ChildProcessData& data, Notification notification) {
|
|
if (data.id == child_id_)
|
|
on_notification_callback_.Run(notification);
|
|
}
|
|
|
|
private:
|
|
// Every notification coming for a child with a different ID will be ignored.
|
|
int child_id_;
|
|
|
|
// The callback to invoke every time a method of the observer is called.
|
|
OnNotificationCallback on_notification_callback_;
|
|
};
|
|
|
|
// A helper class that allows the user to wait until a specific |notification|
|
|
// is sent for a child process whose ID matches |child_id|.
|
|
class WaitForNotificationObserver {
|
|
public:
|
|
WaitForNotificationObserver(int child_id, Notification notification)
|
|
: inner_observer_(
|
|
child_id,
|
|
base::BindRepeating(&WaitForNotificationObserver::OnNotification,
|
|
base::Unretained(this))),
|
|
notification_(notification) {}
|
|
|
|
~WaitForNotificationObserver() = default;
|
|
|
|
// Waits until the notification is received. Returns immediately if it was
|
|
// already received.
|
|
void Wait() {
|
|
if (notification_received_)
|
|
return;
|
|
|
|
DCHECK(!run_loop_.running());
|
|
run_loop_.Run();
|
|
}
|
|
|
|
private:
|
|
void OnNotification(Notification notification) {
|
|
if (notification != notification_)
|
|
return;
|
|
|
|
notification_received_ = true;
|
|
if (run_loop_.running())
|
|
run_loop_.Quit();
|
|
}
|
|
|
|
BrowserChildProcessNotificationObserver inner_observer_;
|
|
Notification notification_;
|
|
base::RunLoop run_loop_;
|
|
bool notification_received_ = false;
|
|
};
|
|
|
|
class TestSandboxedProcessLauncherDelegate
|
|
: public SandboxedProcessLauncherDelegate {
|
|
public:
|
|
explicit TestSandboxedProcessLauncherDelegate(
|
|
sandbox::mojom::Sandbox sandbox_type)
|
|
: sandbox_type_(sandbox_type) {}
|
|
~TestSandboxedProcessLauncherDelegate() override = default;
|
|
|
|
// SandboxedProcessLauncherDelegate:
|
|
sandbox::mojom::Sandbox GetSandboxType() override { return sandbox_type_; }
|
|
|
|
private:
|
|
sandbox::mojom::Sandbox sandbox_type_;
|
|
};
|
|
|
|
// A test-specific type of process host. Self-owned.
|
|
class TestProcessHost : public BrowserChildProcessHostDelegate {
|
|
public:
|
|
static base::WeakPtr<TestProcessHost> Create() {
|
|
auto* instance = new TestProcessHost();
|
|
return instance->GetWeakPtr();
|
|
}
|
|
|
|
TestProcessHost()
|
|
: process_(BrowserChildProcessHost::Create(
|
|
PROCESS_TYPE_UTILITY,
|
|
this,
|
|
ChildProcessHost::IpcMode::kNormal)) {}
|
|
~TestProcessHost() override = default;
|
|
|
|
// Returns the ID of the child process.
|
|
int GetID() { return process_->GetData().id; }
|
|
|
|
// Binds to the test service on the child process and returns the bound
|
|
// remote.
|
|
mojo::Remote<mojom::TestService> BindTestService() {
|
|
mojo::Remote<mojom::TestService> test_service;
|
|
|
|
static_cast<ChildProcessHostImpl*>(process_->GetHost())
|
|
->child_process()
|
|
->BindServiceInterface(test_service.BindNewPipeAndPassReceiver());
|
|
|
|
return test_service;
|
|
}
|
|
|
|
// Returns the command line used to launch the child process.
|
|
std::unique_ptr<base::CommandLine> GetChildCommandLine() {
|
|
base::FilePath child_path =
|
|
ChildProcessHost::GetChildPath(ChildProcessHost::CHILD_NORMAL);
|
|
auto command_line = std::make_unique<base::CommandLine>(child_path);
|
|
|
|
command_line->AppendSwitchASCII(switches::kProcessType,
|
|
switches::kUtilityProcess);
|
|
command_line->AppendSwitchASCII(switches::kUtilitySubType,
|
|
"Test Utility Process");
|
|
sandbox::policy::SetCommandLineFlagsForSandboxType(command_line.get(),
|
|
sandbox_type_);
|
|
|
|
return command_line;
|
|
}
|
|
|
|
// Launches the child process using the default test launcher delegate.
|
|
void LaunchProcess() {
|
|
LaunchProcessWithDelegate(
|
|
std::make_unique<TestSandboxedProcessLauncherDelegate>(sandbox_type_));
|
|
}
|
|
|
|
// Launches the child process using a supplied sandbox delegate.
|
|
void LaunchProcessWithDelegate(
|
|
std::unique_ptr<SandboxedProcessLauncherDelegate>
|
|
sandboxed_process_launcher_delegate) {
|
|
process_->SetName(u"Test utility process");
|
|
|
|
auto command_line = GetChildCommandLine();
|
|
bool terminate_on_shutdown = true;
|
|
|
|
process_->Launch(std::move(sandboxed_process_launcher_delegate),
|
|
std::move(command_line), terminate_on_shutdown);
|
|
|
|
test_service_ = BindTestService();
|
|
}
|
|
|
|
// Requests the child process to shutdown.
|
|
void ForceShutdown() { process_->GetHost()->ForceShutdown(); }
|
|
|
|
// Disconnects the bound remote from the test service.
|
|
void Disconnect() { test_service_.reset(); }
|
|
|
|
// Sets the sandbox type to use for the child process.
|
|
void SetSandboxType(sandbox::mojom::Sandbox sandbox_type) {
|
|
sandbox_type_ = sandbox_type;
|
|
}
|
|
|
|
mojom::TestService* service() const { return test_service_.get(); }
|
|
|
|
base::WeakPtr<TestProcessHost> GetWeakPtr() {
|
|
return weak_ptr_factory_.GetWeakPtr();
|
|
}
|
|
|
|
private:
|
|
sandbox::mojom::Sandbox sandbox_type_ = sandbox::mojom::Sandbox::kUtility;
|
|
|
|
std::unique_ptr<BrowserChildProcessHost> process_;
|
|
|
|
mojo::Remote<mojom::TestService> test_service_;
|
|
|
|
base::WeakPtrFactory<TestProcessHost> weak_ptr_factory_{this};
|
|
};
|
|
|
|
// A helper class that exposes which notifications were sent for a specific
|
|
// child process.
|
|
class TestBrowserChildProcessObserver {
|
|
public:
|
|
explicit TestBrowserChildProcessObserver(int child_id)
|
|
: inner_observer_(child_id,
|
|
base::BindRepeating(
|
|
&TestBrowserChildProcessObserver::OnNotification,
|
|
base::Unretained(this))) {}
|
|
|
|
~TestBrowserChildProcessObserver() = default;
|
|
|
|
// Returns the notifications received for |child_id|.
|
|
const std::vector<Notification>& notifications() const {
|
|
return notifications_;
|
|
}
|
|
|
|
private:
|
|
void OnNotification(Notification notification) {
|
|
notifications_.push_back(notification);
|
|
}
|
|
|
|
BrowserChildProcessNotificationObserver inner_observer_;
|
|
|
|
std::vector<Notification> notifications_;
|
|
};
|
|
|
|
class BrowserChildProcessObserverBrowserTest : public ContentBrowserTest {};
|
|
|
|
// Tests that launching and then using ForceShutdown() results in a normal
|
|
// termination.
|
|
#if defined(ADDRESS_SANITIZER)
|
|
// TODO(crbug.com/40238612): Fix ASAN failures on trybot.
|
|
#define MAYBE_LaunchAndForceShutdown DISABLED_LaunchAndForceShutdown
|
|
#else
|
|
#define MAYBE_LaunchAndForceShutdown LaunchAndForceShutdown
|
|
#endif
|
|
IN_PROC_BROWSER_TEST_F(BrowserChildProcessObserverBrowserTest,
|
|
MAYBE_LaunchAndForceShutdown) {
|
|
base::WeakPtr<TestProcessHost> host = TestProcessHost::Create();
|
|
int child_id = host->GetID();
|
|
|
|
TestBrowserChildProcessObserver observer(child_id);
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id,
|
|
Notification::kLaunchedAndConnected);
|
|
host->LaunchProcess();
|
|
waiter.Wait();
|
|
}
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id, Notification::kDisconnected);
|
|
host->ForceShutdown();
|
|
waiter.Wait();
|
|
}
|
|
|
|
Notification kExitNotification =
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
// TODO(pmonette): On Android, this currently causes a killed
|
|
// notification. Consider fixing.
|
|
Notification::kKilled;
|
|
#else
|
|
Notification::kExitedNormally;
|
|
#endif // BUILDFLAG(IS_ANDROID)
|
|
|
|
// The host should be deleted now.
|
|
EXPECT_FALSE(host);
|
|
EXPECT_FALSE(IsHostAlive(child_id));
|
|
EXPECT_THAT(observer.notifications(),
|
|
testing::ElementsAreArray({Notification::kLaunchedAndConnected,
|
|
kExitNotification,
|
|
Notification::kDisconnected}));
|
|
}
|
|
|
|
// Tests that launching and then deleting the host results in a normal
|
|
// termination.
|
|
IN_PROC_BROWSER_TEST_F(BrowserChildProcessObserverBrowserTest,
|
|
LaunchAndDelete) {
|
|
base::WeakPtr<TestProcessHost> host = TestProcessHost::Create();
|
|
int child_id = host->GetID();
|
|
|
|
TestBrowserChildProcessObserver observer(child_id);
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id,
|
|
Notification::kLaunchedAndConnected);
|
|
host->LaunchProcess();
|
|
waiter.Wait();
|
|
}
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id, Notification::kDisconnected);
|
|
delete host.get();
|
|
waiter.Wait();
|
|
}
|
|
|
|
// The host should be deleted now.
|
|
EXPECT_FALSE(host);
|
|
EXPECT_FALSE(IsHostAlive(child_id));
|
|
EXPECT_THAT(observer.notifications(),
|
|
testing::ElementsAreArray({Notification::kLaunchedAndConnected,
|
|
Notification::kExitedNormally,
|
|
Notification::kDisconnected}));
|
|
}
|
|
|
|
// Tests that launching and then disconnecting the service channel results in a
|
|
// normal termination.
|
|
// Note: This only works for services bound using BindServiceInterface(), not
|
|
// BindReceiver().
|
|
#if defined(ADDRESS_SANITIZER)
|
|
// TODO(crbug.com/40238612): Fix ASAN failures on trybot.
|
|
#define MAYBE_LaunchAndDisconnect DISABLED_LaunchAndDisconnect
|
|
#else
|
|
#define MAYBE_LaunchAndDisconnect LaunchAndDisconnect
|
|
#endif
|
|
IN_PROC_BROWSER_TEST_F(BrowserChildProcessObserverBrowserTest,
|
|
MAYBE_LaunchAndDisconnect) {
|
|
base::WeakPtr<TestProcessHost> host = TestProcessHost::Create();
|
|
int child_id = host->GetID();
|
|
|
|
TestBrowserChildProcessObserver observer(child_id);
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id,
|
|
Notification::kLaunchedAndConnected);
|
|
host->LaunchProcess();
|
|
waiter.Wait();
|
|
}
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id, Notification::kDisconnected);
|
|
host->Disconnect();
|
|
waiter.Wait();
|
|
}
|
|
|
|
Notification kExitNotification =
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
// On Android, kKilled is always sent in the case of a crash.
|
|
Notification::kKilled;
|
|
#else
|
|
Notification::kExitedNormally;
|
|
#endif // BUILDFLAG(IS_ANDROID)
|
|
|
|
// The host should be deleted now.
|
|
EXPECT_FALSE(host);
|
|
EXPECT_FALSE(IsHostAlive(child_id));
|
|
EXPECT_THAT(observer.notifications(), testing::ElementsAreArray({
|
|
Notification::kLaunchedAndConnected,
|
|
kExitNotification,
|
|
Notification::kDisconnected,
|
|
}));
|
|
}
|
|
|
|
// Tests that launching and then causing a crash the host results in a crashed
|
|
// notification.
|
|
// TODO(crbug.com/40868150): Times out on Android tests.
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
#define MAYBE_LaunchAndCrash DISABLED_LaunchAndCrash
|
|
#else
|
|
#define MAYBE_LaunchAndCrash LaunchAndCrash
|
|
#endif
|
|
IN_PROC_BROWSER_TEST_F(BrowserChildProcessObserverBrowserTest,
|
|
MAYBE_LaunchAndCrash) {
|
|
base::WeakPtr<TestProcessHost> host = TestProcessHost::Create();
|
|
int child_id = host->GetID();
|
|
|
|
TestBrowserChildProcessObserver observer(child_id);
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id,
|
|
Notification::kLaunchedAndConnected);
|
|
host->LaunchProcess();
|
|
waiter.Wait();
|
|
}
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id, Notification::kDisconnected);
|
|
host->service()->DoCrashImmediately(base::DoNothing());
|
|
waiter.Wait();
|
|
}
|
|
|
|
Notification kCrashedNotification =
|
|
#if BUILDFLAG(IS_ANDROID)
|
|
// On Android, kKilled is always sent in the case of a crash.
|
|
Notification::kKilled;
|
|
#else
|
|
Notification::kCrashed;
|
|
#endif // BUILDFLAG(IS_ANDROID)
|
|
|
|
// The host should be deleted now.
|
|
EXPECT_FALSE(host);
|
|
EXPECT_FALSE(IsHostAlive(child_id));
|
|
EXPECT_THAT(observer.notifications(),
|
|
testing::ElementsAreArray({Notification::kLaunchedAndConnected,
|
|
kCrashedNotification,
|
|
Notification::kDisconnected}));
|
|
}
|
|
|
|
// Tests that kLaunchFailed is correctly sent when the child process fails to
|
|
// launch.
|
|
//
|
|
// This test won't work as-is on POSIX platforms, where fork()+exec() is used to
|
|
// launch child processes, failure does not happen until exec(), therefore the
|
|
// test will see a valid child process followed by a
|
|
// TERMINATION_STATUS_ABNORMAL_TERMINATION of the forked process. However,
|
|
// posix_spawn() is used on macOS.
|
|
// See also ServiceProcessLauncherTest.FailToLaunchProcess.
|
|
#if !BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_MAC)
|
|
IN_PROC_BROWSER_TEST_F(BrowserChildProcessObserverBrowserTest, LaunchFailed) {
|
|
base::WeakPtr<TestProcessHost> host = TestProcessHost::Create();
|
|
int child_id = host->GetID();
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
// The Windows sandbox does not like the child process being a different
|
|
// process, so launch unsandboxed for the purpose of this test.
|
|
host->SetSandboxType(sandbox::mojom::Sandbox::kNoSandbox);
|
|
#endif
|
|
|
|
// Simulate a catastrophic launch failure for all child processes by
|
|
// making the path to the process non-existent.
|
|
base::CommandLine::ForCurrentProcess()->AppendSwitchPath(
|
|
switches::kBrowserSubprocessPath,
|
|
base::FilePath(FILE_PATH_LITERAL("non_existent_path")));
|
|
|
|
TestBrowserChildProcessObserver observer(child_id);
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id, Notification::kLaunchFailed);
|
|
host->LaunchProcess();
|
|
waiter.Wait();
|
|
}
|
|
|
|
// The host should be deleted now.
|
|
EXPECT_FALSE(host);
|
|
EXPECT_FALSE(IsHostAlive(child_id));
|
|
EXPECT_THAT(observer.notifications(),
|
|
testing::ElementsAreArray({Notification::kLaunchFailed}));
|
|
}
|
|
#endif // !BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_MAC)
|
|
|
|
#if BUILDFLAG(IS_WIN)
|
|
class TestPreSpawnTargetFailureSandboxedProcessLauncherDelegate
|
|
: public TestSandboxedProcessLauncherDelegate {
|
|
public:
|
|
using TestSandboxedProcessLauncherDelegate::
|
|
TestSandboxedProcessLauncherDelegate;
|
|
|
|
// SandboxedProcessLauncherDelegate:
|
|
bool PreSpawnTarget(sandbox::TargetPolicy* policy) override {
|
|
// Force a failure in PreSpawnTarget().
|
|
return false;
|
|
}
|
|
};
|
|
|
|
// Override the observer to verify the error occurred in PreSpawnTarget().
|
|
class TestPreSpawnTargetFailureBrowserChildProcessNotificationObserver
|
|
: public BrowserChildProcessNotificationObserver {
|
|
public:
|
|
using BrowserChildProcessNotificationObserver::
|
|
BrowserChildProcessNotificationObserver;
|
|
|
|
// BrowserChildProcessObserver:
|
|
void BrowserChildProcessLaunchFailed(
|
|
const ChildProcessData& data,
|
|
const ChildProcessTerminationInfo& info) override {
|
|
EXPECT_EQ(info.exit_code, sandbox::SBOX_ERROR_DELEGATE_PRE_SPAWN);
|
|
BrowserChildProcessNotificationObserver::OnNotification(
|
|
data, Notification::kLaunchFailed);
|
|
}
|
|
};
|
|
|
|
// Tests that a pre spawn failure results in a failed launch.
|
|
IN_PROC_BROWSER_TEST_F(BrowserChildProcessObserverBrowserTest,
|
|
LaunchPreSpawnFailed) {
|
|
base::WeakPtr<TestProcessHost> host = TestProcessHost::Create();
|
|
int child_id = host->GetID();
|
|
|
|
TestBrowserChildProcessObserver observer(child_id);
|
|
|
|
{
|
|
WaitForNotificationObserver waiter(child_id, Notification::kLaunchFailed);
|
|
host->LaunchProcessWithDelegate(
|
|
std::make_unique<
|
|
TestPreSpawnTargetFailureSandboxedProcessLauncherDelegate>(
|
|
sandbox::mojom::Sandbox::kUtility));
|
|
waiter.Wait();
|
|
}
|
|
|
|
// The host should be deleted now.
|
|
EXPECT_FALSE(host);
|
|
EXPECT_FALSE(IsHostAlive(child_id));
|
|
EXPECT_THAT(observer.notifications(),
|
|
testing::ElementsAreArray({Notification::kLaunchFailed}));
|
|
}
|
|
#endif // BUILDFLAG(IS_WIN)
|
|
|
|
} // namespace content
|