0
Files
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
src/content/browser/browser_child_process_observer_browsertest.cc
Emily Andrews 2677e32f02 Move Service Process Host files to a separate folder
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}
2025-02-24 10:37:05 -08:00

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