mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 13:19:05 +00:00
LibWebView: Create a spare WebContent process
Since cross-site navigation is a pretty frequent task, creating a spare process is commonplace in other browsers to reduce the overhead of directing the target site to a new process. We store this process on the WebView application. If it is unavailable, we queue a task to create it later.
This commit is contained in:
parent
5810c8073e
commit
aca4385daf
Notes:
github-actions[bot]
2025-03-11 11:11:42 +00:00
Author: https://github.com/trflynn89
Commit: aca4385daf
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3882
Reviewed-by: https://github.com/gmta ✅
8 changed files with 98 additions and 9 deletions
|
@ -191,6 +191,52 @@ void Application::initialize(Main::Arguments const& arguments, URL::URL new_tab_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ErrorOr<NonnullRefPtr<WebContentClient>> create_web_content_client(Optional<ViewImplementation&> view)
|
||||||
|
{
|
||||||
|
auto request_server_socket = TRY(connect_new_request_server_client());
|
||||||
|
auto image_decoder_socket = TRY(connect_new_image_decoder_client());
|
||||||
|
|
||||||
|
if (view.has_value())
|
||||||
|
return WebView::launch_web_content_process(*view, move(image_decoder_socket), move(request_server_socket));
|
||||||
|
return WebView::launch_spare_web_content_process(move(image_decoder_socket), move(request_server_socket));
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<WebContentClient>> Application::launch_web_content_process(ViewImplementation& view)
|
||||||
|
{
|
||||||
|
if (m_spare_web_content_process) {
|
||||||
|
auto web_content_client = m_spare_web_content_process.release_nonnull();
|
||||||
|
launch_spare_web_content_process();
|
||||||
|
|
||||||
|
web_content_client->assign_view({}, view);
|
||||||
|
return web_content_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
launch_spare_web_content_process();
|
||||||
|
return create_web_content_client(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::launch_spare_web_content_process()
|
||||||
|
{
|
||||||
|
if (m_has_queued_task_to_launch_spare_web_content_process)
|
||||||
|
return;
|
||||||
|
m_has_queued_task_to_launch_spare_web_content_process = true;
|
||||||
|
|
||||||
|
Core::deferred_invoke([this]() {
|
||||||
|
m_has_queued_task_to_launch_spare_web_content_process = false;
|
||||||
|
|
||||||
|
auto web_content_client = create_web_content_client({});
|
||||||
|
if (web_content_client.is_error()) {
|
||||||
|
dbgln("Unable to create spare web content client: {}", web_content_client.error());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_spare_web_content_process = web_content_client.release_value();
|
||||||
|
|
||||||
|
if (auto process = find_process(m_spare_web_content_process->pid()); process.has_value())
|
||||||
|
process->set_title("(spare)"_string);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> Application::launch_services()
|
ErrorOr<void> Application::launch_services()
|
||||||
{
|
{
|
||||||
TRY(launch_request_server());
|
TRY(launch_request_server());
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
|
|
||||||
Core::EventLoop& event_loop() { return m_event_loop; }
|
Core::EventLoop& event_loop() { return m_event_loop; }
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<WebContentClient>> launch_web_content_process(ViewImplementation&);
|
||||||
ErrorOr<void> launch_services();
|
ErrorOr<void> launch_services();
|
||||||
|
|
||||||
void add_child_process(Process&&);
|
void add_child_process(Process&&);
|
||||||
|
@ -85,6 +86,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
void initialize(Main::Arguments const& arguments, URL::URL new_tab_page_url);
|
void initialize(Main::Arguments const& arguments, URL::URL new_tab_page_url);
|
||||||
|
|
||||||
|
void launch_spare_web_content_process();
|
||||||
ErrorOr<void> launch_request_server();
|
ErrorOr<void> launch_request_server();
|
||||||
ErrorOr<void> launch_image_decoder_server();
|
ErrorOr<void> launch_image_decoder_server();
|
||||||
ErrorOr<void> launch_devtools_server();
|
ErrorOr<void> launch_devtools_server();
|
||||||
|
@ -118,6 +120,9 @@ private:
|
||||||
RefPtr<Requests::RequestClient> m_request_server_client;
|
RefPtr<Requests::RequestClient> m_request_server_client;
|
||||||
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
|
RefPtr<ImageDecoderClient::Client> m_image_decoder_client;
|
||||||
|
|
||||||
|
RefPtr<WebContentClient> m_spare_web_content_process;
|
||||||
|
bool m_has_queued_task_to_launch_spare_web_content_process { false };
|
||||||
|
|
||||||
RefPtr<Database> m_database;
|
RefPtr<Database> m_database;
|
||||||
OwnPtr<CookieJar> m_cookie_jar;
|
OwnPtr<CookieJar> m_cookie_jar;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
namespace WebView {
|
namespace WebView {
|
||||||
|
|
||||||
|
class Application;
|
||||||
class CookieJar;
|
class CookieJar;
|
||||||
class Database;
|
class Database;
|
||||||
class InspectorClient;
|
class InspectorClient;
|
||||||
|
|
|
@ -79,10 +79,11 @@ static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
template<typename... ClientArguments>
|
||||||
WebView::ViewImplementation& view,
|
static ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process_impl(
|
||||||
IPC::File image_decoder_socket,
|
IPC::File image_decoder_socket,
|
||||||
Optional<IPC::File> request_server_socket)
|
Optional<IPC::File> request_server_socket,
|
||||||
|
ClientArguments&&... client_arguments)
|
||||||
{
|
{
|
||||||
auto const& chrome_options = WebView::Application::chrome_options();
|
auto const& chrome_options = WebView::Application::chrome_options();
|
||||||
auto const& web_content_options = WebView::Application::web_content_options();
|
auto const& web_content_options = WebView::Application::web_content_options();
|
||||||
|
@ -138,7 +139,22 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
||||||
arguments.append("--image-decoder-socket"sv);
|
arguments.append("--image-decoder-socket"sv);
|
||||||
arguments.append(ByteString::number(image_decoder_socket.fd()));
|
arguments.append(ByteString::number(image_decoder_socket.fd()));
|
||||||
|
|
||||||
return launch_server_process<WebView::WebContentClient>("WebContent"sv, move(arguments), view);
|
return launch_server_process<WebView::WebContentClient>("WebContent"sv, move(arguments), forward<ClientArguments>(client_arguments)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
||||||
|
WebView::ViewImplementation& view,
|
||||||
|
IPC::File image_decoder_socket,
|
||||||
|
Optional<IPC::File> request_server_socket)
|
||||||
|
{
|
||||||
|
return launch_web_content_process_impl(move(image_decoder_socket), move(request_server_socket), view);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_spare_web_content_process(
|
||||||
|
IPC::File image_decoder_socket,
|
||||||
|
Optional<IPC::File> request_server_socket)
|
||||||
|
{
|
||||||
|
return launch_web_content_process_impl(move(image_decoder_socket), move(request_server_socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process()
|
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process()
|
||||||
|
|
|
@ -21,6 +21,10 @@ ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
|
||||||
IPC::File image_decoder_socket,
|
IPC::File image_decoder_socket,
|
||||||
Optional<IPC::File> request_server_socket = {});
|
Optional<IPC::File> request_server_socket = {});
|
||||||
|
|
||||||
|
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_spare_web_content_process(
|
||||||
|
IPC::File image_decoder_socket,
|
||||||
|
Optional<IPC::File> request_server_socket = {});
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process();
|
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process();
|
||||||
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process();
|
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process();
|
||||||
ErrorOr<NonnullRefPtr<Requests::RequestClient>> launch_request_server_process();
|
ErrorOr<NonnullRefPtr<Requests::RequestClient>> launch_request_server_process();
|
||||||
|
|
|
@ -568,11 +568,8 @@ void ViewImplementation::initialize_client(CreateNewClient create_new_client)
|
||||||
if (create_new_client == CreateNewClient::Yes) {
|
if (create_new_client == CreateNewClient::Yes) {
|
||||||
m_client_state = {};
|
m_client_state = {};
|
||||||
|
|
||||||
// FIXME: Fail to open the tab, rather than crashing the whole application if these fail.
|
// FIXME: Fail to open the tab, rather than crashing the whole application if this fails.
|
||||||
auto request_server_socket = connect_new_request_server_client().release_value_but_fixme_should_propagate_errors();
|
m_client_state.client = Application::the().launch_web_content_process(*this).release_value_but_fixme_should_propagate_errors();
|
||||||
auto image_decoder_socket = connect_new_image_decoder_client().release_value_but_fixme_should_propagate_errors();
|
|
||||||
|
|
||||||
m_client_state.client = launch_web_content_process(*this, AK::move(image_decoder_socket), AK::move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
|
|
||||||
} else {
|
} else {
|
||||||
m_client_state.client->register_view(m_client_state.page_index, *this);
|
m_client_state.client->register_view(m_client_state.page_index, *this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,12 @@ WebContentClient::WebContentClient(IPC::Transport transport, ViewImplementation&
|
||||||
m_views.set(0, &view);
|
m_views.set(0, &view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WebContentClient::WebContentClient(IPC::Transport transport)
|
||||||
|
: IPC::ConnectionToServer<WebContentClientEndpoint, WebContentServerEndpoint>(*this, move(transport))
|
||||||
|
{
|
||||||
|
s_clients.set(this);
|
||||||
|
}
|
||||||
|
|
||||||
WebContentClient::~WebContentClient()
|
WebContentClient::~WebContentClient()
|
||||||
{
|
{
|
||||||
s_clients.remove(this);
|
s_clients.remove(this);
|
||||||
|
@ -41,6 +47,12 @@ void WebContentClient::die()
|
||||||
// Intentionally empty. Restart is handled at another level.
|
// Intentionally empty. Restart is handled at another level.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WebContentClient::assign_view(Badge<Application>, ViewImplementation& view)
|
||||||
|
{
|
||||||
|
VERIFY(m_views.is_empty());
|
||||||
|
m_views.set(0, &view);
|
||||||
|
}
|
||||||
|
|
||||||
void WebContentClient::register_view(u64 page_id, ViewImplementation& view)
|
void WebContentClient::register_view(u64 page_id, ViewImplementation& view)
|
||||||
{
|
{
|
||||||
VERIFY(page_id > 0);
|
VERIFY(page_id > 0);
|
||||||
|
@ -768,6 +780,10 @@ void WebContentClient::did_get_style_sheet_source(u64 page_id, Web::CSS::StyleSh
|
||||||
|
|
||||||
Optional<ViewImplementation&> WebContentClient::view_for_page_id(u64 page_id, SourceLocation location)
|
Optional<ViewImplementation&> WebContentClient::view_for_page_id(u64 page_id, SourceLocation location)
|
||||||
{
|
{
|
||||||
|
// Don't bother logging anything for the spare WebContent process. It will only receive a load notification for about:blank.
|
||||||
|
if (m_views.is_empty())
|
||||||
|
return {};
|
||||||
|
|
||||||
if (auto view = m_views.get(page_id); view.has_value())
|
if (auto view = m_views.get(page_id); view.has_value())
|
||||||
return *view.value();
|
return *view.value();
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <LibWeb/HTML/SelectItem.h>
|
#include <LibWeb/HTML/SelectItem.h>
|
||||||
#include <LibWeb/HTML/WebViewHints.h>
|
#include <LibWeb/HTML/WebViewHints.h>
|
||||||
#include <LibWeb/Page/EventResult.h>
|
#include <LibWeb/Page/EventResult.h>
|
||||||
|
#include <LibWebView/Forward.h>
|
||||||
#include <WebContent/WebContentClientEndpoint.h>
|
#include <WebContent/WebContentClientEndpoint.h>
|
||||||
#include <WebContent/WebContentServerEndpoint.h>
|
#include <WebContent/WebContentServerEndpoint.h>
|
||||||
|
|
||||||
|
@ -38,14 +39,17 @@ public:
|
||||||
|
|
||||||
static size_t client_count() { return s_clients.size(); }
|
static size_t client_count() { return s_clients.size(); }
|
||||||
|
|
||||||
|
explicit WebContentClient(IPC::Transport);
|
||||||
WebContentClient(IPC::Transport, ViewImplementation&);
|
WebContentClient(IPC::Transport, ViewImplementation&);
|
||||||
~WebContentClient();
|
~WebContentClient();
|
||||||
|
|
||||||
|
void assign_view(Badge<Application>, ViewImplementation&);
|
||||||
void register_view(u64 page_id, ViewImplementation&);
|
void register_view(u64 page_id, ViewImplementation&);
|
||||||
void unregister_view(u64 page_id);
|
void unregister_view(u64 page_id);
|
||||||
|
|
||||||
Function<void()> on_web_content_process_crash;
|
Function<void()> on_web_content_process_crash;
|
||||||
|
|
||||||
|
pid_t pid() const { return m_process_handle.pid; }
|
||||||
void set_pid(pid_t pid) { m_process_handle.pid = pid; }
|
void set_pid(pid_t pid) { m_process_handle.pid = pid; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue