LibWebView+Services+UI: Move process helpers to LibWebView

This commit is contained in:
Timothy Flynn 2024-11-10 10:26:07 -05:00 committed by Tim Flynn
parent a14937c45e
commit 0ff91a5273
Notes: github-actions[bot] 2024-11-11 12:36:39 +00:00
29 changed files with 110 additions and 119 deletions

View file

@ -10,9 +10,9 @@
#include <LibImageDecoderClient/Client.h>
#include <LibRequests/RequestClient.h>
#include <LibWebView/Application.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/Utilities.h>
#include <LibWebView/WebContentClient.h>
#include <UI/HelperProcess.h>
#include <UI/Utilities.h>
#include <Utilities/Conversions.h>
#import <Application/Application.h>
@ -70,16 +70,16 @@ ApplicationBridge::ApplicationBridge(Badge<WebView::Application>, Main::Argument
- (ErrorOr<void>)launchRequestServer
{
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
m_request_server_client = TRY(launch_request_server_process(request_server_paths, s_ladybird_resource_root));
auto request_server_paths = TRY(WebView::get_paths_for_helper_process("RequestServer"sv));
m_request_server_client = TRY(WebView::launch_request_server_process(request_server_paths, WebView::s_ladybird_resource_root));
return {};
}
static ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_new_image_decoder()
{
auto image_decoder_paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
return launch_image_decoder_process(image_decoder_paths);
auto image_decoder_paths = TRY(WebView::get_paths_for_helper_process("ImageDecoder"sv));
return WebView::launch_image_decoder_process(image_decoder_paths);
}
- (ErrorOr<void>)launchImageDecoder
@ -120,19 +120,19 @@ static ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_new_image_decod
- (ErrorOr<NonnullRefPtr<WebView::WebContentClient>>)launchWebContent:(Ladybird::WebViewBridge&)web_view_bridge
{
// FIXME: Fail to open the tab, rather than crashing the whole application if this fails
auto request_server_socket = TRY(connect_new_request_server_client(*m_request_server_client));
auto image_decoder_socket = TRY(connect_new_image_decoder_client(*m_image_decoder_client));
auto request_server_socket = TRY(WebView::connect_new_request_server_client(*m_request_server_client));
auto image_decoder_socket = TRY(WebView::connect_new_image_decoder_client(*m_image_decoder_client));
auto web_content_paths = TRY(get_paths_for_helper_process("WebContent"sv));
auto web_content = TRY(launch_web_content_process(web_view_bridge, web_content_paths, move(image_decoder_socket), move(request_server_socket)));
auto web_content_paths = TRY(WebView::get_paths_for_helper_process("WebContent"sv));
auto web_content = TRY(WebView::launch_web_content_process(web_view_bridge, web_content_paths, move(image_decoder_socket), move(request_server_socket)));
return web_content;
}
- (ErrorOr<IPC::File>)launchWebWorker
{
auto web_worker_paths = TRY(get_paths_for_helper_process("WebWorker"sv));
auto worker_client = TRY(launch_web_worker_process(web_worker_paths, *m_request_server_client));
auto web_worker_paths = TRY(WebView::get_paths_for_helper_process("WebWorker"sv));
auto worker_client = TRY(WebView::launch_web_worker_process(web_worker_paths, *m_request_server_client));
return worker_client->clone_transport();
}

View file

@ -11,8 +11,6 @@
#include <LibWeb/Crypto/Crypto.h>
#include <LibWebView/Application.h>
#include <LibWebView/UserAgent.h>
#include <UI/HelperProcess.h>
#include <UI/Utilities.h>
#import <Interface/Palette.h>

View file

@ -8,7 +8,6 @@
#include <LibCore/Resource.h>
#include <LibGfx/Palette.h>
#include <LibGfx/SystemTheme.h>
#include <UI/Utilities.h>
#import <Cocoa/Cocoa.h>
#import <Interface/Palette.h>

View file

@ -11,7 +11,6 @@
#include <LibGfx/ShareableBitmap.h>
#include <LibURL/URL.h>
#include <LibWebView/ViewImplementation.h>
#include <UI/Utilities.h>
#import <Application/ApplicationDelegate.h>
#import <Interface/Inspector.h>

View file

@ -10,12 +10,12 @@
#include <LibWebView/Application.h>
#include <LibWebView/ChromeProcess.h>
#include <LibWebView/EventLoop/EventLoopImplementationMacOS.h>
#include <LibWebView/MachPortServer.h>
#include <LibWebView/URL.h>
#include <LibWebView/Utilities.h>
#include <LibWebView/ViewImplementation.h>
#include <LibWebView/WebContentClient.h>
#include <UI/DefaultSettings.h>
#include <UI/MachPortServer.h>
#include <UI/Utilities.h>
#import <Application/Application.h>
#import <Application/ApplicationDelegate.h>
@ -51,7 +51,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
Core::EventLoopManager::install(*new WebView::EventLoopManagerMacOS);
[application setupWebViewApplication:arguments newTabPageURL:Browser::default_new_tab_url];
platform_init();
WebView::platform_init();
WebView::ChromeProcess chrome_process;
@ -72,12 +72,13 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
open_urls_from_client(raw_urls, WebView::NewWindow::Yes);
};
auto mach_port_server = make<Ladybird::MachPortServer>();
set_mach_server_name(mach_port_server->server_port_name());
auto mach_port_server = make<WebView::MachPortServer>();
WebView::set_mach_server_name(mach_port_server->server_port_name());
mach_port_server->on_receive_child_mach_port = [&](auto pid, auto port) {
WebView::Application::the().set_process_mach_port(pid, move(port));
};
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
mach_port_server->on_receive_backing_stores = [](WebView::MachPortServer::BackingStoresMessage message) {
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
};

View file

@ -1,14 +1,5 @@
include(cmake/ResourceFiles.cmake)
set(LADYBIRD_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/HelperProcess.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Utilities.cpp
)
set(LADYBIRD_HEADERS
HelperProcess.h
Utilities.h
)
function(create_ladybird_bundle target_name)
set_target_properties(${target_name} PROPERTIES
OUTPUT_NAME "Ladybird"
@ -64,26 +55,13 @@ elseif(ANDROID)
add_subdirectory(Android)
else()
# TODO: Check for other GUI frameworks here when we move them in-tree
# For now, we can export a static library of common files for chromes to link to
add_library(ladybird STATIC ${LADYBIRD_SOURCES})
return()
endif()
if (NOT TARGET ladybird)
message(FATAL_ERROR "UI Framework selection must declare a ladybird target")
endif()
if (APPLE)
target_sources(ladybird PRIVATE MachPortServer.cpp)
target_link_libraries(ladybird PRIVATE LibThreading)
endif()
if (ENABLE_INSTALL_HEADERS)
target_sources(ladybird PUBLIC FILE_SET ladybird TYPE HEADERS
BASE_DIRS ${LADYBIRD_SOURCE_DIR}
FILES ${LADYBIRD_HEADERS}
)
endif()
if (TARGET ladybird_impl)
set(LADYBIRD_TARGET ladybird_impl PUBLIC)
else()
@ -104,12 +82,6 @@ function(set_helper_process_properties)
set_target_properties(${targets} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "$<TARGET_FILE_DIR:ladybird>")
else()
set_target_properties(${targets} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/${IN_BUILD_PREFIX}${CMAKE_INSTALL_LIBEXECDIR}")
if (NOT CMAKE_INSTALL_LIBEXECDIR STREQUAL "libexec")
set_source_files_properties(Utilities.cpp PROPERTIES COMPILE_DEFINITIONS LADYBIRD_LIBEXECDIR="${CMAKE_INSTALL_LIBEXECDIR}")
set_source_files_properties(Utilities.cpp TARGET_DIRECTORY ladybird PROPERTIES COMPILE_DEFINITIONS LADYBIRD_LIBEXECDIR="${CMAKE_INSTALL_LIBEXECDIR}")
set_source_files_properties(Utilities.cpp TARGET_DIRECTORY ${targets} PROPERTIES COMPILE_DEFINITIONS LADYBIRD_LIBEXECDIR="${CMAKE_INSTALL_LIBEXECDIR}")
endif()
endif()
endfunction()

View file

@ -7,16 +7,16 @@
#include <LibCore/AnonymousBuffer.h>
#include <LibCore/ArgsParser.h>
#include <LibCore/System.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/Utilities.h>
#include <UI/Headless/Application.h>
#include <UI/Headless/Fixture.h>
#include <UI/Headless/HeadlessWebView.h>
#include <UI/HelperProcess.h>
#include <UI/Utilities.h>
namespace Ladybird {
Application::Application(Badge<WebView::Application>, Main::Arguments&)
: resources_folder(s_ladybird_resource_root)
: resources_folder(WebView::s_ladybird_resource_root)
, test_concurrency(Core::System::hardware_concurrency())
, python_executable_path("python3")
@ -73,11 +73,11 @@ void Application::create_platform_options(WebView::ChromeOptions& chrome_options
ErrorOr<void> Application::launch_services()
{
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
m_request_client = TRY(launch_request_server_process(request_server_paths, resources_folder));
auto request_server_paths = TRY(WebView::get_paths_for_helper_process("RequestServer"sv));
m_request_client = TRY(WebView::launch_request_server_process(request_server_paths, resources_folder));
auto image_decoder_paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
m_image_decoder_client = TRY(launch_image_decoder_process(image_decoder_paths));
auto image_decoder_paths = TRY(WebView::get_paths_for_helper_process("ImageDecoder"sv));
m_image_decoder_client = TRY(WebView::launch_image_decoder_process(image_decoder_paths));
return {};
}

View file

@ -7,10 +7,10 @@
#include <LibGfx/Bitmap.h>
#include <LibGfx/ShareableBitmap.h>
#include <LibWeb/Crypto/Crypto.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/Utilities.h>
#include <UI/Headless/Application.h>
#include <UI/Headless/HeadlessWebView.h>
#include <UI/HelperProcess.h>
#include <UI/Utilities.h>
namespace Ladybird {
@ -32,8 +32,8 @@ HeadlessWebView::HeadlessWebView(Core::AnonymousBuffer theme, Gfx::IntSize viewp
};
on_request_worker_agent = []() {
auto web_worker_paths = MUST(get_paths_for_helper_process("WebWorker"sv));
auto worker_client = MUST(launch_web_worker_process(web_worker_paths, Application::request_client()));
auto web_worker_paths = MUST(WebView::get_paths_for_helper_process("WebWorker"sv));
auto worker_client = MUST(WebView::launch_web_worker_process(web_worker_paths, Application::request_client()));
return worker_client->clone_transport();
};
@ -143,11 +143,11 @@ NonnullOwnPtr<HeadlessWebView> HeadlessWebView::create_child(HeadlessWebView con
void HeadlessWebView::initialize_client(CreateNewClient create_new_client)
{
if (create_new_client == CreateNewClient::Yes) {
auto request_server_socket = connect_new_request_server_client(Application::request_client()).release_value_but_fixme_should_propagate_errors();
auto image_decoder_socket = connect_new_image_decoder_client(Application::image_decoder_client()).release_value_but_fixme_should_propagate_errors();
auto request_server_socket = WebView::connect_new_request_server_client(Application::request_client()).release_value_but_fixme_should_propagate_errors();
auto image_decoder_socket = WebView::connect_new_image_decoder_client(Application::image_decoder_client()).release_value_but_fixme_should_propagate_errors();
auto web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
m_client_state.client = launch_web_content_process(*this, web_content_paths, move(image_decoder_socket), move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
auto web_content_paths = WebView::get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
m_client_state.client = WebView::launch_web_content_process(*this, web_content_paths, move(image_decoder_socket), move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
} else {
m_client_state.client->register_view(m_client_state.page_index, *this);
}

View file

@ -21,10 +21,10 @@
#include <LibGfx/ImageFormats/PNGWriter.h>
#include <LibGfx/SystemTheme.h>
#include <LibURL/URL.h>
#include <LibWebView/Utilities.h>
#include <UI/Headless/Application.h>
#include <UI/Headless/HeadlessWebView.h>
#include <UI/Headless/Test.h>
#include <UI/Utilities.h>
static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Core::EventLoop& event_loop, Ladybird::HeadlessWebView& view, URL::URL const& url, int screenshot_timeout)
{
@ -61,7 +61,7 @@ static ErrorOr<NonnullRefPtr<Core::Timer>> load_page_for_screenshot_and_exit(Cor
ErrorOr<int> serenity_main(Main::Arguments arguments)
{
platform_init();
WebView::platform_init();
auto app = Ladybird::Application::create(arguments, "about:newtab"sv);
TRY(app->launch_services());

View file

@ -1,193 +0,0 @@
/*
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Enumerate.h>
#include <LibCore/Process.h>
#include <LibWebView/Application.h>
#include <UI/HelperProcess.h>
#include <UI/Utilities.h>
template<typename ClientType, typename... ClientArguments>
static ErrorOr<NonnullRefPtr<ClientType>> launch_server_process(
StringView server_name,
ReadonlySpan<ByteString> candidate_server_paths,
Vector<ByteString> arguments,
ClientArguments&&... client_arguments)
{
auto process_type = WebView::process_type_from_name(server_name);
auto const& chrome_options = WebView::Application::chrome_options();
if (chrome_options.profile_helper_process == process_type) {
arguments.prepend({
"--tool=callgrind"sv,
"--instr-atstart=no"sv,
""sv, // Placeholder for the process path.
});
}
if (chrome_options.debug_helper_process == process_type)
arguments.append("--wait-for-debugger"sv);
for (auto [i, path] : enumerate(candidate_server_paths)) {
Core::ProcessSpawnOptions options { .name = server_name, .arguments = arguments };
if (chrome_options.profile_helper_process == process_type) {
options.executable = "valgrind"sv;
options.search_for_executable_in_path = true;
arguments[2] = path;
} else {
options.executable = path;
}
auto result = WebView::Process::spawn<ClientType>(process_type, move(options), forward<ClientArguments>(client_arguments)...);
if (!result.is_error()) {
auto&& [process, client] = result.release_value();
if constexpr (requires { client->set_pid(pid_t {}); })
client->set_pid(process.pid());
WebView::Application::the().add_child_process(move(process));
if (chrome_options.profile_helper_process == process_type) {
dbgln();
dbgln("\033[1;45mLaunched {} process under callgrind!\033[0m", server_name);
dbgln("\033[100mRun `\033[4mcallgrind_control -i on\033[24m` to start instrumentation and `\033[4mcallgrind_control -i off\033[24m` stop it again.\033[0m");
dbgln();
}
return move(client);
}
if (i == candidate_server_paths.size() - 1) {
warnln("Could not launch any of {}: {}", candidate_server_paths, result.error());
return result.release_error();
}
}
VERIFY_NOT_REACHED();
}
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
WebView::ViewImplementation& view,
ReadonlySpan<ByteString> candidate_web_content_paths,
IPC::File image_decoder_socket,
Optional<IPC::File> request_server_socket)
{
auto const& web_content_options = WebView::Application::web_content_options();
Vector<ByteString> arguments {
"--command-line"sv,
web_content_options.command_line.to_byte_string(),
"--executable-path"sv,
web_content_options.executable_path.to_byte_string(),
};
if (web_content_options.config_path.has_value()) {
arguments.append("--config-path"sv);
arguments.append(web_content_options.config_path.value());
}
if (web_content_options.is_layout_test_mode == WebView::IsLayoutTestMode::Yes)
arguments.append("--layout-test-mode"sv);
if (web_content_options.log_all_js_exceptions == WebView::LogAllJSExceptions::Yes)
arguments.append("--log-all-js-exceptions"sv);
if (web_content_options.enable_idl_tracing == WebView::EnableIDLTracing::Yes)
arguments.append("--enable-idl-tracing"sv);
if (web_content_options.enable_http_cache == WebView::EnableHTTPCache::Yes)
arguments.append("--enable-http-cache"sv);
if (web_content_options.expose_internals_object == WebView::ExposeInternalsObject::Yes)
arguments.append("--expose-internals-object"sv);
if (web_content_options.force_cpu_painting == WebView::ForceCPUPainting::Yes)
arguments.append("--force-cpu-painting"sv);
if (web_content_options.force_fontconfig == WebView::ForceFontconfig::Yes)
arguments.append("--force-fontconfig"sv);
if (web_content_options.collect_garbage_on_every_allocation == WebView::CollectGarbageOnEveryAllocation::Yes)
arguments.append("--collect-garbage-on-every-allocation"sv);
if (auto server = mach_server_name(); server.has_value()) {
arguments.append("--mach-server-name"sv);
arguments.append(server.value());
}
if (request_server_socket.has_value()) {
arguments.append("--request-server-socket"sv);
arguments.append(ByteString::number(request_server_socket->fd()));
}
arguments.append("--image-decoder-socket"sv);
arguments.append(ByteString::number(image_decoder_socket.fd()));
return launch_server_process<WebView::WebContentClient>("WebContent"sv, candidate_web_content_paths, move(arguments), view);
}
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths)
{
Vector<ByteString> arguments;
if (auto server = mach_server_name(); server.has_value()) {
arguments.append("--mach-server-name"sv);
arguments.append(server.value());
}
return launch_server_process<ImageDecoderClient::Client>("ImageDecoder"sv, candidate_image_decoder_paths, arguments);
}
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, NonnullRefPtr<Requests::RequestClient> request_client)
{
Vector<ByteString> arguments;
auto socket = TRY(connect_new_request_server_client(*request_client));
arguments.append("--request-server-socket"sv);
arguments.append(ByteString::number(socket.fd()));
return launch_server_process<Web::HTML::WebWorkerClient>("WebWorker"sv, candidate_web_worker_paths, move(arguments));
}
ErrorOr<NonnullRefPtr<Requests::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root)
{
Vector<ByteString> arguments;
if (!serenity_resource_root.is_empty()) {
arguments.append("--serenity-resource-root"sv);
arguments.append(serenity_resource_root);
}
for (auto const& certificate : WebView::Application::chrome_options().certificates)
arguments.append(ByteString::formatted("--certificate={}", certificate));
if (auto server = mach_server_name(); server.has_value()) {
arguments.append("--mach-server-name"sv);
arguments.append(server.value());
}
return launch_server_process<Requests::RequestClient>("RequestServer"sv, candidate_request_server_paths, move(arguments));
}
ErrorOr<IPC::File> connect_new_request_server_client(Requests::RequestClient& client)
{
auto new_socket = client.send_sync_but_allow_failure<Messages::RequestServer::ConnectNewClient>();
if (!new_socket)
return Error::from_string_literal("Failed to connect to RequestServer");
auto socket = new_socket->take_client_socket();
TRY(socket.clear_close_on_exec());
return socket;
}
ErrorOr<IPC::File> connect_new_image_decoder_client(ImageDecoderClient::Client& client)
{
auto new_socket = client.send_sync_but_allow_failure<Messages::ImageDecoderServer::ConnectNewClients>(1);
if (!new_socket)
return Error::from_string_literal("Failed to connect to ImageDecoder");
auto sockets = new_socket->take_sockets();
if (sockets.size() != 1)
return Error::from_string_literal("Failed to connect to ImageDecoder");
auto socket = sockets.take_last();
TRY(socket.clear_close_on_exec());
return socket;
}

View file

@ -1,30 +0,0 @@
/*
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Error.h>
#include <AK/Optional.h>
#include <AK/Span.h>
#include <AK/StringView.h>
#include <LibImageDecoderClient/Client.h>
#include <LibRequests/RequestClient.h>
#include <LibWeb/Worker/WebWorkerClient.h>
#include <LibWebView/ViewImplementation.h>
#include <LibWebView/WebContentClient.h>
ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
WebView::ViewImplementation& view,
ReadonlySpan<ByteString> candidate_web_content_paths,
IPC::File image_decoder_socket,
Optional<IPC::File> request_server_socket = {});
ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths);
ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, NonnullRefPtr<Requests::RequestClient>);
ErrorOr<NonnullRefPtr<Requests::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root);
ErrorOr<IPC::File> connect_new_request_server_client(Requests::RequestClient&);
ErrorOr<IPC::File> connect_new_image_decoder_client(ImageDecoderClient::Client&);

View file

@ -1,105 +0,0 @@
/*
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Debug.h>
#include <LibCore/Platform/MachMessageTypes.h>
#include <LibCore/Platform/ProcessStatisticsMach.h>
#include <UI/MachPortServer.h>
namespace Ladybird {
MachPortServer::MachPortServer()
: m_thread(Threading::Thread::construct([this]() -> intptr_t { thread_loop(); return 0; }, "MachPortServer"sv))
, m_server_port_name(ByteString::formatted("org.ladybird.Ladybird.helper.{}", getpid()))
{
if (auto err = allocate_server_port(); err.is_error())
dbgln("Failed to allocate server port: {}", err.error());
else
start();
}
MachPortServer::~MachPortServer()
{
stop();
}
void MachPortServer::start()
{
m_thread->start();
}
void MachPortServer::stop()
{
// FIXME: We should join instead (after storing should_stop = false) when we have a way to interrupt the thread's mach_msg call
m_thread->detach();
m_should_stop.store(true, MemoryOrder::memory_order_release);
}
bool MachPortServer::is_initialized()
{
return MACH_PORT_VALID(m_server_port_recv_right.port()) && MACH_PORT_VALID(m_server_port_send_right.port());
}
ErrorOr<void> MachPortServer::allocate_server_port()
{
m_server_port_recv_right = TRY(Core::MachPort::create_with_right(Core::MachPort::PortRight::Receive));
m_server_port_send_right = TRY(m_server_port_recv_right.insert_right(Core::MachPort::MessageRight::MakeSend));
TRY(m_server_port_recv_right.register_with_bootstrap_server(m_server_port_name));
dbgln_if(MACH_PORT_DEBUG, "Success! we created and attached mach port {:x} to bootstrap server with name {}", m_server_port_recv_right.port(), m_server_port_name);
return {};
}
void MachPortServer::thread_loop()
{
while (!m_should_stop.load(MemoryOrder::memory_order_acquire)) {
Core::Platform::ReceivedMachMessage message {};
// Get the pid of the child from the audit trailer so we can associate the port w/it
mach_msg_options_t const options = MACH_RCV_MSG | MACH_RCV_TRAILER_TYPE(MACH_RCV_TRAILER_AUDIT) | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT);
// FIXME: How can we interrupt this call during application shutdown?
auto const ret = mach_msg(&message.header, options, 0, sizeof(message), m_server_port_recv_right.port(), MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);
if (ret != KERN_SUCCESS) {
dbgln("mach_msg failed: {}", mach_error_string(ret));
break;
}
if (message.header.msgh_id == Core::Platform::BACKING_STORE_IOSURFACES_MESSAGE_ID) {
auto pid = static_cast<pid_t>(message.body.parent_iosurface.trailer.msgh_audit.val[5]);
auto const& backing_stores_message = message.body.parent_iosurface;
auto front_child_port = Core::MachPort::adopt_right(backing_stores_message.front_descriptor.name, Core::MachPort::PortRight::Send);
auto back_child_port = Core::MachPort::adopt_right(backing_stores_message.back_descriptor.name, Core::MachPort::PortRight::Send);
auto const& metadata = backing_stores_message.metadata;
if (on_receive_backing_stores)
on_receive_backing_stores({ .pid = pid,
.page_id = metadata.page_id,
.front_backing_store_id = metadata.front_backing_store_id,
.back_backing_store_id = metadata.back_backing_store_id,
.front_backing_store_port = move(front_child_port),
.back_backing_store_port = move(back_child_port) });
continue;
}
if (message.header.msgh_id == Core::Platform::SELF_TASK_PORT_MESSAGE_ID) {
if (MACH_MSGH_BITS_LOCAL(message.header.msgh_bits) != MACH_MSG_TYPE_MOVE_SEND) {
dbgln("Received message with invalid local port rights {}, ignoring", MACH_MSGH_BITS_LOCAL(message.header.msgh_bits));
continue;
}
auto const& task_port_message = message.body.parent;
auto pid = static_cast<pid_t>(task_port_message.trailer.msgh_audit.val[5]);
auto child_port = Core::MachPort::adopt_right(task_port_message.port_descriptor.name, Core::MachPort::PortRight::Send);
dbgln_if(MACH_PORT_DEBUG, "Received child port {:x} from pid {}", child_port.port(), pid);
if (on_receive_child_mach_port)
on_receive_child_mach_port(pid, move(child_port));
continue;
}
dbgln("Received message with id {}, ignoring", message.header.msgh_id);
}
}
}

View file

@ -1,58 +0,0 @@
/*
* Copyright (c) 2024, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Platform.h>
#if !defined(AK_OS_MACH)
# error "This file is only for Mach kernel-based OS's"
#endif
#include <AK/Atomic.h>
#include <AK/String.h>
#include <LibCore/MachPort.h>
#include <LibThreading/Thread.h>
namespace Ladybird {
class MachPortServer {
public:
MachPortServer();
~MachPortServer();
void start();
void stop();
bool is_initialized();
Function<void(pid_t, Core::MachPort)> on_receive_child_mach_port;
struct BackingStoresMessage {
pid_t pid { -1 };
u64 page_id { 0 };
i32 front_backing_store_id { 0 };
i32 back_backing_store_id { 0 };
Core::MachPort front_backing_store_port;
Core::MachPort back_backing_store_port;
};
Function<void(BackingStoresMessage)> on_receive_backing_stores;
ByteString const& server_port_name() const { return m_server_port_name; }
private:
void thread_loop();
ErrorOr<void> allocate_server_port();
NonnullRefPtr<Threading::Thread> m_thread;
ByteString const m_server_port_name;
Core::MachPort m_server_port_recv_right;
Core::MachPort m_server_port_send_right;
Atomic<bool> m_should_stop { false };
};
}

View file

@ -5,13 +5,13 @@
*/
#include <LibCore/ArgsParser.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/URL.h>
#include <UI/HelperProcess.h>
#include <LibWebView/Utilities.h>
#include <UI/Qt/Application.h>
#include <UI/Qt/Settings.h>
#include <UI/Qt/StringUtils.h>
#include <UI/Qt/TaskManagerWindow.h>
#include <UI/Utilities.h>
#include <QFileDialog>
#include <QFileOpenEvent>
@ -56,8 +56,8 @@ bool Application::event(QEvent* event)
static ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_new_image_decoder()
{
auto paths = TRY(get_paths_for_helper_process("ImageDecoder"sv));
return launch_image_decoder_process(paths);
auto paths = TRY(WebView::get_paths_for_helper_process("ImageDecoder"sv));
return WebView::launch_image_decoder_process(paths);
}
ErrorOr<void> Application::initialize_image_decoder()

View file

@ -25,7 +25,6 @@
#include <UI/Qt/TabBar.h>
#include <UI/Qt/TaskManagerWindow.h>
#include <UI/Qt/WebContentView.h>
#include <UI/Utilities.h>
#include <QAction>
#include <QActionGroup>

View file

@ -24,12 +24,12 @@
#include <LibWeb/UIEvents/KeyCode.h>
#include <LibWeb/UIEvents/MouseButton.h>
#include <LibWebView/Application.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/Utilities.h>
#include <LibWebView/WebContentClient.h>
#include <UI/HelperProcess.h>
#include <UI/Qt/Application.h>
#include <UI/Qt/StringUtils.h>
#include <UI/Qt/WebContentView.h>
#include <UI/Utilities.h>
#include <QApplication>
#include <QCursor>
@ -129,7 +129,7 @@ WebContentView::WebContentView(QWidget* window, RefPtr<WebView::WebContentClient
on_request_worker_agent = [&]() {
auto& request_server_client = static_cast<Ladybird::Application*>(QApplication::instance())->request_server_client;
auto worker_client = MUST(launch_web_worker_process(MUST(get_paths_for_helper_process("WebWorker"sv)), *request_server_client));
auto worker_client = MUST(WebView::launch_web_worker_process(MUST(WebView::get_paths_for_helper_process("WebWorker"sv)), *request_server_client));
return worker_client->clone_transport();
};
@ -632,12 +632,12 @@ void WebContentView::initialize_client(WebView::ViewImplementation::CreateNewCli
auto& request_server_client = static_cast<Ladybird::Application*>(QApplication::instance())->request_server_client;
// FIXME: Fail to open the tab, rather than crashing the whole application if this fails
auto request_server_socket = connect_new_request_server_client(*request_server_client).release_value_but_fixme_should_propagate_errors();
auto request_server_socket = WebView::connect_new_request_server_client(*request_server_client).release_value_but_fixme_should_propagate_errors();
auto image_decoder = static_cast<Ladybird::Application*>(QApplication::instance())->image_decoder_client();
auto image_decoder_socket = connect_new_image_decoder_client(*image_decoder).release_value_but_fixme_should_propagate_errors();
auto image_decoder_socket = WebView::connect_new_image_decoder_client(*image_decoder).release_value_but_fixme_should_propagate_errors();
auto candidate_web_content_paths = get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
auto candidate_web_content_paths = WebView::get_paths_for_helper_process("WebContent"sv).release_value_but_fixme_should_propagate_errors();
auto new_client = launch_web_content_process(*this, candidate_web_content_paths, AK::move(image_decoder_socket), AK::move(request_server_socket)).release_value_but_fixme_should_propagate_errors();
m_client_state.client = new_client;

View file

@ -13,17 +13,17 @@
#include <LibWebView/Application.h>
#include <LibWebView/ChromeProcess.h>
#include <LibWebView/EventLoop/EventLoopImplementationQt.h>
#include <LibWebView/HelperProcess.h>
#include <LibWebView/ProcessManager.h>
#include <LibWebView/URL.h>
#include <UI/HelperProcess.h>
#include <LibWebView/Utilities.h>
#include <UI/Qt/Application.h>
#include <UI/Qt/BrowserWindow.h>
#include <UI/Qt/Settings.h>
#include <UI/Qt/WebContentView.h>
#include <UI/Utilities.h>
#if defined(AK_OS_MACOS)
# include <UI/MachPortServer.h>
# include <LibWebView/MachPortServer.h>
#endif
namespace Ladybird {
@ -71,7 +71,7 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
static_cast<WebView::EventLoopImplementationQt&>(Core::EventLoop::current().impl()).set_main_loop();
TRY(handle_attached_debugger());
platform_init();
WebView::platform_init();
WebView::ChromeProcess chrome_process;
@ -100,22 +100,23 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
};
#if defined(AK_OS_MACOS)
auto mach_port_server = make<Ladybird::MachPortServer>();
set_mach_server_name(mach_port_server->server_port_name());
auto mach_port_server = make<WebView::MachPortServer>();
WebView::set_mach_server_name(mach_port_server->server_port_name());
mach_port_server->on_receive_child_mach_port = [&app](auto pid, auto port) {
app->set_process_mach_port(pid, move(port));
};
mach_port_server->on_receive_backing_stores = [](Ladybird::MachPortServer::BackingStoresMessage message) {
mach_port_server->on_receive_backing_stores = [](WebView::MachPortServer::BackingStoresMessage message) {
if (auto view = WebView::WebContentClient::view_for_pid_and_page_id(message.pid, message.page_id); view.has_value())
view->did_allocate_iosurface_backing_stores(message.front_backing_store_id, move(message.front_backing_store_port), message.back_backing_store_id, move(message.back_backing_store_port));
};
#endif
copy_default_config_files(Ladybird::Settings::the()->directory());
WebView::copy_default_config_files(Ladybird::Settings::the()->directory());
// FIXME: Create an abstraction to re-spawn the RequestServer and re-hook up its client hooks to each tab on crash
auto request_server_paths = TRY(get_paths_for_helper_process("RequestServer"sv));
auto requests_client = TRY(launch_request_server_process(request_server_paths, s_ladybird_resource_root));
auto request_server_paths = TRY(WebView::get_paths_for_helper_process("RequestServer"sv));
auto requests_client = TRY(WebView::launch_request_server_process(request_server_paths, WebView::s_ladybird_resource_root));
app->request_server_client = move(requests_client);
TRY(app->initialize_image_decoder());

View file

@ -1,114 +0,0 @@
/*
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/LexicalPath.h>
#include <AK/Platform.h>
#include <LibCore/Directory.h>
#include <LibCore/Environment.h>
#include <LibCore/Resource.h>
#include <LibCore/ResourceImplementationFile.h>
#include <LibCore/System.h>
#include <LibFileSystem/FileSystem.h>
#include <UI/Utilities.h>
#define TOKENCAT(x, y) x##y
#define STRINGIFY(x) TOKENCAT(x, sv)
// This is expected to be set from the build scripts, if a packager desires
#if defined(LADYBIRD_LIBEXECDIR)
constexpr auto libexec_path = STRINGIFY(LADYBIRD_LIBEXECDIR);
#else
constexpr auto libexec_path = "libexec"sv;
#endif
ByteString s_ladybird_resource_root;
Optional<ByteString> s_mach_server_name;
Optional<ByteString const&> mach_server_name()
{
if (s_mach_server_name.has_value())
return *s_mach_server_name;
return {};
}
void set_mach_server_name(ByteString name)
{
s_mach_server_name = move(name);
}
ErrorOr<ByteString> application_directory()
{
auto current_executable_path = TRY(Core::System::current_executable_path());
return LexicalPath::dirname(current_executable_path);
}
[[gnu::used]] static LexicalPath find_prefix(LexicalPath const& application_directory);
static LexicalPath find_prefix(LexicalPath const& application_directory)
{
if (application_directory.string().ends_with(libexec_path)) {
// Strip libexec_path if it's there
return LexicalPath(application_directory.string().substring_view(0, application_directory.string().length() - libexec_path.length()));
}
// Otherwise, we are in $prefix/bin
return application_directory.parent();
}
void platform_init()
{
s_ladybird_resource_root = [] {
auto home = Core::Environment::get("XDG_CONFIG_HOME"sv)
.value_or_lazy_evaluated_optional([]() { return Core::Environment::get("HOME"sv); });
if (home.has_value()) {
auto home_lagom = ByteString::formatted("{}/.lagom", home);
if (FileSystem::is_directory(home_lagom))
return home_lagom;
}
auto app_dir = MUST(application_directory());
#ifdef AK_OS_MACOS
return LexicalPath(app_dir).parent().append("Resources"sv).string();
#else
return find_prefix(LexicalPath(app_dir)).append("share/Lagom"sv).string();
#endif
}();
Core::ResourceImplementation::install(make<Core::ResourceImplementationFile>(MUST(String::from_byte_string(s_ladybird_resource_root))));
}
void copy_default_config_files(StringView config_path)
{
MUST(Core::Directory::create(config_path, Core::Directory::CreateDirectories::Yes));
auto config_resources = MUST(Core::Resource::load_from_uri("resource://ladybird/default-config"sv));
config_resources->for_each_descendant_file([config_path](Core::Resource const& resource) -> IterationDecision {
auto file_path = ByteString::formatted("{}/{}", config_path, resource.filename());
if (Core::System::stat(file_path).is_error()) {
auto file = MUST(Core::File::open(file_path, Core::File::OpenMode::Write));
MUST(file->write_until_depleted(resource.data()));
}
return IterationDecision::Continue;
});
}
ErrorOr<Vector<ByteString>> get_paths_for_helper_process(StringView process_name)
{
auto application_path = TRY(application_directory());
Vector<ByteString> paths;
#if !defined(AK_OS_MACOS)
auto prefix = find_prefix(LexicalPath(application_path));
TRY(paths.try_append(LexicalPath::join(prefix.string(), libexec_path, process_name).string()));
TRY(paths.try_append(LexicalPath::join(prefix.string(), "bin"sv, process_name).string()));
#endif
TRY(paths.try_append(ByteString::formatted("{}/{}", application_path, process_name)));
TRY(paths.try_append(ByteString::formatted("./{}", process_name)));
// NOTE: Add platform-specific paths here
return paths;
}

View file

@ -1,22 +0,0 @@
/*
* Copyright (c) 2022, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/ByteString.h>
#include <AK/Error.h>
#include <AK/String.h>
#include <AK/Vector.h>
void platform_init();
void copy_default_config_files(StringView config_path);
ErrorOr<ByteString> application_directory();
ErrorOr<Vector<ByteString>> get_paths_for_helper_process(StringView process_name);
extern ByteString s_ladybird_resource_root;
Optional<ByteString const&> mach_server_name();
void set_mach_server_name(ByteString name);