From a031d00695c4210a371905e8ecf582b35f08d7eb Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Tue, 12 May 2026 17:20:40 +0200 Subject: [PATCH] WebContent: Exit cleanly when browser IPC disconnects Exit WebContent immediately when either browser-side IPC peer disconnects. Plumb Unix process exit status through LibWebView so the browser process can tell clean owner-driven shutdown apart from renderer crashes. This keeps nonzero exits and signal deaths reported as crashes, while letting status 0 exits disappear without making test-web report the page as crashed. --- Libraries/LibWebView/Application.cpp | 14 +++++++++++--- Libraries/LibWebView/Application.h | 2 +- Libraries/LibWebView/ProcessManager.cpp | 6 +++--- Libraries/LibWebView/ProcessManager.h | 2 +- Libraries/LibWebView/ProcessMonitor.cpp | 6 +++--- Libraries/LibWebView/ProcessMonitor.h | 4 ++-- Services/WebContent/ConnectionFromClient.cpp | 7 +++++-- Tests/LibWeb/test-web/TestRunCapture.cpp | 4 ++-- Tests/LibWeb/test-web/TestRunCapture.h | 2 +- 9 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Libraries/LibWebView/Application.cpp b/Libraries/LibWebView/Application.cpp index 74eccec48a..63c9e3dd5b 100644 --- a/Libraries/LibWebView/Application.cpp +++ b/Libraries/LibWebView/Application.cpp @@ -35,6 +35,10 @@ # include #endif +#if !defined(AK_OS_WINDOWS) +# include +#endif + namespace WebView { Application* Application::s_the = nullptr; @@ -472,8 +476,8 @@ ErrorOr Application::launch_services() m_bookmark_store_observer = make(); m_process_manager = make(); - m_process_manager->on_process_exited = [this](Process&& process) { - process_did_exit(move(process)); + m_process_manager->on_process_exited = [this](Process&& process, Optional exit_status) { + process_did_exit(move(process), exit_status); }; if (m_browser_options.disable_sql_database == DisableSQLDatabase::No) { @@ -727,7 +731,7 @@ Optional Application::find_process(pid_t pid) return m_process_manager->find_process(pid); } -void Application::process_did_exit(Process&& process) +void Application::process_did_exit(Process&& process, Optional exit_status) { if (m_event_loop->was_exit_requested()) return; @@ -751,6 +755,10 @@ void Application::process_did_exit(Process&& process) } break; case ProcessType::WebContent: +#if !defined(AK_OS_WINDOWS) + if (exit_status.has_value() && WIFEXITED(*exit_status) && WEXITSTATUS(*exit_status) == 0) + break; +#endif if (auto client = process.client(); client.has_value()) client->notify_all_views_of_crash(); break; diff --git a/Libraries/LibWebView/Application.h b/Libraries/LibWebView/Application.h index 3a20062b9b..94436815e6 100644 --- a/Libraries/LibWebView/Application.h +++ b/Libraries/LibWebView/Application.h @@ -171,7 +171,7 @@ protected: ErrorOr initialize(Main::Arguments const&); - virtual void process_did_exit(Process&&); + virtual void process_did_exit(Process&&, Optional exit_status); virtual void create_platform_arguments(Core::ArgsParser&) { } virtual void create_platform_options(BrowserOptions&, RequestServerOptions&, WebContentOptions&) { } diff --git a/Libraries/LibWebView/ProcessManager.cpp b/Libraries/LibWebView/ProcessManager.cpp index 8b3b009090..e8ebb97a72 100644 --- a/Libraries/LibWebView/ProcessManager.cpp +++ b/Libraries/LibWebView/ProcessManager.cpp @@ -49,10 +49,10 @@ StringView process_name_from_type(ProcessType type) ProcessManager::ProcessManager() : on_process_added([](Process&) {}) - , on_process_exited([](Process&&) {}) - , m_process_monitor(ProcessMonitor([this](pid_t pid) { + , on_process_exited([](Process&&, Optional) {}) + , m_process_monitor(ProcessMonitor([this](pid_t pid, Optional exit_status) { if (auto process = remove_process(pid); process.has_value()) - on_process_exited(process.release_value()); + on_process_exited(process.release_value(), exit_status); })) { add_process(Process(WebView::ProcessType::Browser, nullptr, Core::Process::current())); diff --git a/Libraries/LibWebView/ProcessManager.h b/Libraries/LibWebView/ProcessManager.h index b9d340bc37..052fa3ee71 100644 --- a/Libraries/LibWebView/ProcessManager.h +++ b/Libraries/LibWebView/ProcessManager.h @@ -40,7 +40,7 @@ public: JsonValue serialize_json(); Function on_process_added; // test-web - Function on_process_exited; + Function exit_status)> on_process_exited; private: void verify_event_loop() const; diff --git a/Libraries/LibWebView/ProcessMonitor.cpp b/Libraries/LibWebView/ProcessMonitor.cpp index c9129ac59b..e5fca1d793 100644 --- a/Libraries/LibWebView/ProcessMonitor.cpp +++ b/Libraries/LibWebView/ProcessMonitor.cpp @@ -12,7 +12,7 @@ namespace WebView { -ProcessMonitor::ProcessMonitor(Function exit_handler) +ProcessMonitor::ProcessMonitor(Function exit_status)> exit_handler) : m_on_process_exit(move(exit_handler)) { #if !defined(AK_OS_WINDOWS) @@ -23,7 +23,7 @@ ProcessMonitor::ProcessMonitor(Function exit_handler) if (m_monitored_processes.contains(pid)) { if (WIFEXITED(status) || WIFSIGNALED(status)) { m_monitored_processes.remove(pid); - m_on_process_exit(pid); + m_on_process_exit(pid, status); } } result = Core::System::waitpid(-1, WNOHANG); @@ -51,7 +51,7 @@ void ProcessMonitor::add_process(pid_t pid) #if defined(AK_OS_WINDOWS) Core::EventLoop::register_process(pid, [this](pid_t pid) { m_monitored_processes.remove(pid); - m_on_process_exit(pid); + m_on_process_exit(pid, {}); }); #endif } diff --git a/Libraries/LibWebView/ProcessMonitor.h b/Libraries/LibWebView/ProcessMonitor.h index d3fcf72ef9..03e0091a85 100644 --- a/Libraries/LibWebView/ProcessMonitor.h +++ b/Libraries/LibWebView/ProcessMonitor.h @@ -13,13 +13,13 @@ namespace WebView { class ProcessMonitor { public: - ProcessMonitor(Function exit_handler); + ProcessMonitor(Function exit_status)> exit_handler); ~ProcessMonitor(); void add_process(pid_t pid); private: - Function m_on_process_exit; + Function exit_status)> m_on_process_exit; HashTable m_monitored_processes; [[maybe_unused]] int m_signal_handle { -1 }; }; diff --git a/Services/WebContent/ConnectionFromClient.cpp b/Services/WebContent/ConnectionFromClient.cpp index b9a3349ff5..c4db75052f 100644 --- a/Services/WebContent/ConnectionFromClient.cpp +++ b/Services/WebContent/ConnectionFromClient.cpp @@ -78,7 +78,10 @@ class CompositorConnectionFromClient final C_OBJECT(CompositorConnectionFromClient) public: - virtual void die() override { } + virtual void die() override + { + _exit(0); + } private: explicit CompositorConnectionFromClient(NonnullOwnPtr transport) @@ -134,7 +137,7 @@ ConnectionFromClient::~ConnectionFromClient() = default; void ConnectionFromClient::die() { - Web::Platform::EventLoopPlugin::the().quit(); + _exit(0); } Messages::WebContentServer::InitTransportResponse ConnectionFromClient::init_transport([[maybe_unused]] int peer_pid) diff --git a/Tests/LibWeb/test-web/TestRunCapture.cpp b/Tests/LibWeb/test-web/TestRunCapture.cpp index 52f604c467..676debe08b 100644 --- a/Tests/LibWeb/test-web/TestRunCapture.cpp +++ b/Tests/LibWeb/test-web/TestRunCapture.cpp @@ -29,9 +29,9 @@ TestRunCapture::TestRunCapture() setup_output_capture_for_helper_process(process); }; m_previous_on_process_exited = move(process_manager.on_process_exited); - process_manager.on_process_exited = [this](WebView::Process&& process) { + process_manager.on_process_exited = [this](WebView::Process&& process, Optional exit_status) { consume_helper_capture(process.pid()); - m_previous_on_process_exited(move(process)); + m_previous_on_process_exited(move(process), exit_status); }; process_manager.for_each_process([this](WebView::Process& process) { diff --git a/Tests/LibWeb/test-web/TestRunCapture.h b/Tests/LibWeb/test-web/TestRunCapture.h index 4f9f58e569..006a59b98f 100644 --- a/Tests/LibWeb/test-web/TestRunCapture.h +++ b/Tests/LibWeb/test-web/TestRunCapture.h @@ -72,7 +72,7 @@ private: void consume_helper_capture(pid_t pid); void destroy_view_capture_of(TestWebView const& view); - Function m_previous_on_process_exited; + Function exit_status)> m_previous_on_process_exited; HashMap> m_test_output_captures; HashMap> m_helper_output_captures; CaptureFile m_helper_output;