HelperProcess.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. /*
  2. * Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include "HelperProcess.h"
  7. #include "Utilities.h"
  8. #include <LibCore/Environment.h>
  9. #include <LibWebView/ProcessManager.h>
  10. ErrorOr<NonnullRefPtr<WebView::WebContentClient>> launch_web_content_process(
  11. WebView::ViewImplementation& view,
  12. ReadonlySpan<ByteString> candidate_web_content_paths,
  13. Ladybird::WebContentOptions const& web_content_options)
  14. {
  15. int socket_fds[2] {};
  16. TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
  17. int ui_fd = socket_fds[0];
  18. int wc_fd = socket_fds[1];
  19. int fd_passing_socket_fds[2] {};
  20. TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
  21. int ui_fd_passing_fd = fd_passing_socket_fds[0];
  22. int wc_fd_passing_fd = fd_passing_socket_fds[1];
  23. auto child_pid = TRY(Core::System::fork());
  24. if (child_pid == 0) {
  25. TRY(Core::System::close(ui_fd_passing_fd));
  26. TRY(Core::System::close(ui_fd));
  27. auto takeover_string = TRY(String::formatted("WebContent:{}", wc_fd));
  28. TRY(Core::Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Core::Environment::Overwrite::Yes));
  29. auto webcontent_fd_passing_socket_string = TRY(String::number(wc_fd_passing_fd));
  30. ErrorOr<void> result;
  31. for (auto const& path : candidate_web_content_paths) {
  32. constexpr auto callgrind_prefix_length = 3;
  33. if (Core::System::access(path, X_OK).is_error())
  34. continue;
  35. auto arguments = Vector {
  36. "valgrind"sv,
  37. "--tool=callgrind"sv,
  38. "--instr-atstart=no"sv,
  39. path.view(),
  40. "--command-line"sv,
  41. web_content_options.command_line,
  42. "--executable-path"sv,
  43. web_content_options.executable_path,
  44. "--webcontent-fd-passing-socket"sv,
  45. webcontent_fd_passing_socket_string
  46. };
  47. if (web_content_options.enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::No)
  48. arguments.remove(0, callgrind_prefix_length);
  49. if (web_content_options.is_layout_test_mode == Ladybird::IsLayoutTestMode::Yes)
  50. arguments.append("--layout-test-mode"sv);
  51. if (web_content_options.use_lagom_networking == Ladybird::UseLagomNetworking::Yes)
  52. arguments.append("--use-lagom-networking"sv);
  53. if (web_content_options.enable_gpu_painting == Ladybird::EnableGPUPainting::Yes)
  54. arguments.append("--use-gpu-painting"sv);
  55. if (web_content_options.wait_for_debugger == Ladybird::WaitForDebugger::Yes)
  56. arguments.append("--wait-for-debugger"sv);
  57. if (web_content_options.log_all_js_exceptions == Ladybird::LogAllJSExceptions::Yes)
  58. arguments.append("--log-all-js-exceptions"sv);
  59. if (auto server = mach_server_name(); server.has_value()) {
  60. arguments.append("--mach-server-name"sv);
  61. arguments.append(server.value());
  62. }
  63. Vector<ByteString> certificate_args;
  64. for (auto const& certificate : web_content_options.certificates) {
  65. certificate_args.append(ByteString::formatted("--certificate={}", certificate));
  66. arguments.append(certificate_args.last().view());
  67. }
  68. result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes);
  69. if (!result.is_error())
  70. break;
  71. }
  72. if (result.is_error())
  73. warnln("Could not launch any of {}: {}", candidate_web_content_paths, result.error());
  74. VERIFY_NOT_REACHED();
  75. }
  76. TRY(Core::System::close(wc_fd_passing_fd));
  77. TRY(Core::System::close(wc_fd));
  78. auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd));
  79. TRY(socket->set_blocking(true));
  80. auto new_client = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WebView::WebContentClient(move(socket), view)));
  81. new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
  82. if (web_content_options.enable_callgrind_profiling == Ladybird::EnableCallgrindProfiling::Yes) {
  83. dbgln();
  84. dbgln("\033[1;45mLaunched WebContent process under callgrind!\033[0m");
  85. 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");
  86. dbgln();
  87. }
  88. return new_client;
  89. }
  90. template<typename Client>
  91. ErrorOr<NonnullRefPtr<Client>> launch_generic_server_process(ReadonlySpan<ByteString> candidate_server_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates, StringView server_name)
  92. {
  93. int socket_fds[2] {};
  94. TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
  95. int ui_fd = socket_fds[0];
  96. int server_fd = socket_fds[1];
  97. int fd_passing_socket_fds[2] {};
  98. TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
  99. int ui_fd_passing_fd = fd_passing_socket_fds[0];
  100. int server_fd_passing_fd = fd_passing_socket_fds[1];
  101. auto child_pid = TRY(Core::System::fork());
  102. if (child_pid == 0) {
  103. TRY(Core::System::close(ui_fd));
  104. TRY(Core::System::close(ui_fd_passing_fd));
  105. auto takeover_string = TRY(String::formatted("{}:{}", server_name, server_fd));
  106. TRY(Core::Environment::set("SOCKET_TAKEOVER"sv, takeover_string, Core::Environment::Overwrite::Yes));
  107. auto fd_passing_socket_string = TRY(String::number(server_fd_passing_fd));
  108. ErrorOr<void> result;
  109. for (auto const& path : candidate_server_paths) {
  110. if (Core::System::access(path, X_OK).is_error())
  111. continue;
  112. auto arguments = Vector<StringView, 5> {
  113. path.view(),
  114. "--fd-passing-socket"sv,
  115. fd_passing_socket_string,
  116. };
  117. if (!serenity_resource_root.is_empty()) {
  118. arguments.append("--serenity-resource-root"sv);
  119. arguments.append(serenity_resource_root);
  120. }
  121. Vector<ByteString> certificate_args;
  122. for (auto const& certificate : certificates) {
  123. certificate_args.append(ByteString::formatted("--certificate={}", certificate));
  124. arguments.append(certificate_args.last().view());
  125. }
  126. result = Core::System::exec(arguments[0], arguments.span(), Core::System::SearchInPath::Yes);
  127. if (!result.is_error())
  128. break;
  129. }
  130. if (result.is_error())
  131. warnln("Could not launch any of {}: {}", candidate_server_paths, result.error());
  132. VERIFY_NOT_REACHED();
  133. }
  134. TRY(Core::System::close(server_fd));
  135. TRY(Core::System::close(server_fd_passing_fd));
  136. auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd));
  137. TRY(socket->set_blocking(true));
  138. auto new_client = TRY(try_make_ref_counted<Client>(move(socket)));
  139. new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
  140. WebView::ProcessManager::the().add_process(WebView::process_type_from_name(server_name), child_pid);
  141. return new_client;
  142. }
  143. ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>> launch_image_decoder_process(ReadonlySpan<ByteString> candidate_image_decoder_paths)
  144. {
  145. return launch_generic_server_process<ImageDecoderClient::Client>(candidate_image_decoder_paths, ""sv, {}, "ImageDecoder"sv);
  146. }
  147. ErrorOr<NonnullRefPtr<Web::HTML::WebWorkerClient>> launch_web_worker_process(ReadonlySpan<ByteString> candidate_web_worker_paths, Vector<ByteString> const& certificates)
  148. {
  149. return launch_generic_server_process<Web::HTML::WebWorkerClient>(candidate_web_worker_paths, ""sv, certificates, "WebWorker"sv);
  150. }
  151. ErrorOr<NonnullRefPtr<Protocol::RequestClient>> launch_request_server_process(ReadonlySpan<ByteString> candidate_request_server_paths, StringView serenity_resource_root, Vector<ByteString> const& certificates)
  152. {
  153. return launch_generic_server_process<Protocol::RequestClient>(candidate_request_server_paths, serenity_resource_root, certificates, "RequestServer"sv);
  154. }