2023-02-02 10:00:30 +00:00
/*
* Copyright ( c ) 2023 , Andrew Kaster < akaster @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "HelperProcess.h"
2023-12-01 17:18:40 +00:00
ErrorOr < NonnullRefPtr < WebView : : WebContentClient > > launch_web_content_process (
WebView : : ViewImplementation & view ,
2023-08-01 17:56:10 +00:00
ReadonlySpan < String > candidate_web_content_paths ,
2023-12-01 17:18:40 +00:00
Ladybird : : WebContentOptions const & web_content_options )
2023-02-02 10:00:30 +00:00
{
2023-08-01 17:56:10 +00:00
int socket_fds [ 2 ] { } ;
TRY ( Core : : System : : socketpair ( AF_LOCAL , SOCK_STREAM , 0 , socket_fds ) ) ;
int ui_fd = socket_fds [ 0 ] ;
int wc_fd = socket_fds [ 1 ] ;
int fd_passing_socket_fds [ 2 ] { } ;
TRY ( Core : : System : : socketpair ( AF_LOCAL , SOCK_STREAM , 0 , fd_passing_socket_fds ) ) ;
int ui_fd_passing_fd = fd_passing_socket_fds [ 0 ] ;
int wc_fd_passing_fd = fd_passing_socket_fds [ 1 ] ;
if ( auto child_pid = TRY ( Core : : System : : fork ( ) ) ; child_pid = = 0 ) {
TRY ( Core : : System : : close ( ui_fd_passing_fd ) ) ;
TRY ( Core : : System : : close ( ui_fd ) ) ;
auto takeover_string = TRY ( String : : formatted ( " WebContent:{} " , wc_fd ) ) ;
TRY ( Core : : System : : setenv ( " SOCKET_TAKEOVER " sv , takeover_string , true ) ) ;
auto webcontent_fd_passing_socket_string = TRY ( String : : number ( wc_fd_passing_fd ) ) ;
ErrorOr < void > result ;
for ( auto const & path : candidate_web_content_paths ) {
constexpr auto callgrind_prefix_length = 3 ;
if ( Core : : System : : access ( path , X_OK ) . is_error ( ) )
continue ;
auto arguments = Vector {
" valgrind " sv ,
" --tool=callgrind " sv ,
" --instr-atstart=no " sv ,
path . bytes_as_string_view ( ) ,
2024-01-16 17:55:40 +00:00
" --command-line " sv ,
web_content_options . command_line ,
" --executable-path " sv ,
web_content_options . executable_path ,
2023-08-01 17:56:10 +00:00
" --webcontent-fd-passing-socket " sv ,
webcontent_fd_passing_socket_string
} ;
2023-12-01 17:18:40 +00:00
if ( web_content_options . enable_callgrind_profiling = = Ladybird : : EnableCallgrindProfiling : : No )
2023-08-01 17:56:10 +00:00
arguments . remove ( 0 , callgrind_prefix_length ) ;
2023-12-01 17:18:40 +00:00
if ( web_content_options . is_layout_test_mode = = Ladybird : : IsLayoutTestMode : : Yes )
2023-08-01 17:56:10 +00:00
arguments . append ( " --layout-test-mode " sv ) ;
2023-12-01 17:18:40 +00:00
if ( web_content_options . use_lagom_networking = = Ladybird : : UseLagomNetworking : : Yes )
2023-08-01 20:39:19 +00:00
arguments . append ( " --use-lagom-networking " sv ) ;
2023-12-01 17:18:40 +00:00
if ( web_content_options . enable_gpu_painting = = Ladybird : : EnableGPUPainting : : Yes )
2023-10-27 15:28:18 +00:00
arguments . append ( " --use-gpu-painting " sv ) ;
2023-12-20 16:52:17 +00:00
if ( web_content_options . wait_for_debugger = = Ladybird : : WaitForDebugger : : Yes )
arguments . append ( " --wait-for-debugger " sv ) ;
2023-08-01 17:56:10 +00:00
result = Core : : System : : exec ( arguments [ 0 ] , arguments . span ( ) , Core : : System : : SearchInPath : : Yes ) ;
if ( ! result . is_error ( ) )
break ;
}
if ( result . is_error ( ) )
warnln ( " Could not launch any of {}: {} " , candidate_web_content_paths , result . error ( ) ) ;
VERIFY_NOT_REACHED ( ) ;
}
TRY ( Core : : System : : close ( wc_fd_passing_fd ) ) ;
TRY ( Core : : System : : close ( wc_fd ) ) ;
auto socket = TRY ( Core : : LocalSocket : : adopt_fd ( ui_fd ) ) ;
TRY ( socket - > set_blocking ( true ) ) ;
auto new_client = TRY ( adopt_nonnull_ref_or_enomem ( new ( nothrow ) WebView : : WebContentClient ( move ( socket ) , view ) ) ) ;
new_client - > set_fd_passing_socket ( TRY ( Core : : LocalSocket : : adopt_fd ( ui_fd_passing_fd ) ) ) ;
2023-12-01 17:18:40 +00:00
if ( web_content_options . enable_callgrind_profiling = = Ladybird : : EnableCallgrindProfiling : : Yes ) {
2023-08-01 17:56:10 +00:00
dbgln ( ) ;
dbgln ( " \033 [1;45mLaunched WebContent process under callgrind! \033 [0m " ) ;
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 new_client ;
2023-02-02 10:00:30 +00:00
}
2023-08-01 20:39:19 +00:00
2023-08-03 00:13:23 +00:00
template < typename Client >
ErrorOr < NonnullRefPtr < Client > > launch_generic_server_process ( ReadonlySpan < String > candidate_server_paths , StringView serenity_resource_root , StringView server_name )
2023-08-01 20:39:19 +00:00
{
int socket_fds [ 2 ] { } ;
TRY ( Core : : System : : socketpair ( AF_LOCAL , SOCK_STREAM , 0 , socket_fds ) ) ;
int ui_fd = socket_fds [ 0 ] ;
2023-08-03 00:13:23 +00:00
int server_fd = socket_fds [ 1 ] ;
2023-08-01 20:39:19 +00:00
int fd_passing_socket_fds [ 2 ] { } ;
TRY ( Core : : System : : socketpair ( AF_LOCAL , SOCK_STREAM , 0 , fd_passing_socket_fds ) ) ;
int ui_fd_passing_fd = fd_passing_socket_fds [ 0 ] ;
2023-08-03 00:13:23 +00:00
int server_fd_passing_fd = fd_passing_socket_fds [ 1 ] ;
2023-08-01 20:39:19 +00:00
if ( auto child_pid = TRY ( Core : : System : : fork ( ) ) ; child_pid = = 0 ) {
TRY ( Core : : System : : close ( ui_fd ) ) ;
TRY ( Core : : System : : close ( ui_fd_passing_fd ) ) ;
2023-08-03 00:13:23 +00:00
auto takeover_string = TRY ( String : : formatted ( " {}:{} " , server_name , server_fd ) ) ;
2023-08-01 20:39:19 +00:00
TRY ( Core : : System : : setenv ( " SOCKET_TAKEOVER " sv , takeover_string , true ) ) ;
2023-08-03 00:13:23 +00:00
auto fd_passing_socket_string = TRY ( String : : number ( server_fd_passing_fd ) ) ;
2023-08-01 20:39:19 +00:00
ErrorOr < void > result ;
2023-08-03 00:13:23 +00:00
for ( auto const & path : candidate_server_paths ) {
2023-08-01 20:39:19 +00:00
if ( Core : : System : : access ( path , X_OK ) . is_error ( ) )
continue ;
2023-08-03 00:13:23 +00:00
auto arguments = Vector < StringView , 5 > {
2023-08-01 20:39:19 +00:00
path . bytes_as_string_view ( ) ,
" --fd-passing-socket " sv ,
fd_passing_socket_string ,
2023-08-02 23:21:17 +00:00
" --serenity-resource-root " sv ,
serenity_resource_root ,
2023-08-01 20:39:19 +00:00
} ;
result = Core : : System : : exec ( arguments [ 0 ] , arguments . span ( ) , Core : : System : : SearchInPath : : Yes ) ;
if ( ! result . is_error ( ) )
break ;
}
if ( result . is_error ( ) )
2023-08-03 00:13:23 +00:00
warnln ( " Could not launch any of {}: {} " , candidate_server_paths , result . error ( ) ) ;
2023-08-01 20:39:19 +00:00
VERIFY_NOT_REACHED ( ) ;
}
2023-08-03 00:13:23 +00:00
TRY ( Core : : System : : close ( server_fd ) ) ;
TRY ( Core : : System : : close ( server_fd_passing_fd ) ) ;
2023-08-01 20:39:19 +00:00
auto socket = TRY ( Core : : LocalSocket : : adopt_fd ( ui_fd ) ) ;
TRY ( socket - > set_blocking ( true ) ) ;
2023-08-03 00:13:23 +00:00
auto new_client = TRY ( try_make_ref_counted < Client > ( move ( socket ) ) ) ;
2023-08-01 20:39:19 +00:00
new_client - > set_fd_passing_socket ( TRY ( Core : : LocalSocket : : adopt_fd ( ui_fd_passing_fd ) ) ) ;
return new_client ;
}
2023-08-03 00:13:23 +00:00
2023-09-08 10:30:50 +00:00
ErrorOr < NonnullRefPtr < ImageDecoderClient : : Client > > launch_image_decoder_process ( ReadonlySpan < String > candidate_image_decoder_paths )
{
return launch_generic_server_process < ImageDecoderClient : : Client > ( candidate_image_decoder_paths , " " sv , " ImageDecoder " sv ) ;
}
2024-01-06 20:13:59 +00:00
ErrorOr < NonnullRefPtr < Web : : HTML : : WebWorkerClient > > launch_web_worker_process ( ReadonlySpan < String > candidate_web_worker_paths )
{
return launch_generic_server_process < Web : : HTML : : WebWorkerClient > ( candidate_web_worker_paths , " " sv , " WebWorker " sv ) ;
}
2023-08-03 00:13:23 +00:00
ErrorOr < NonnullRefPtr < Protocol : : RequestClient > > launch_request_server_process ( ReadonlySpan < String > candidate_request_server_paths , StringView serenity_resource_root )
{
return launch_generic_server_process < Protocol : : RequestClient > ( candidate_request_server_paths , serenity_resource_root , " RequestServer " sv ) ;
}
ErrorOr < NonnullRefPtr < Protocol : : WebSocketClient > > launch_web_socket_process ( ReadonlySpan < String > candidate_web_socket_paths , StringView serenity_resource_root )
{
return launch_generic_server_process < Protocol : : WebSocketClient > ( candidate_web_socket_paths , serenity_resource_root , " WebSocket " sv ) ;
}