diff --git a/Ladybird/Android/src/main/AndroidManifest.xml b/Ladybird/Android/src/main/AndroidManifest.xml index c48a1e683a6..7fe1232bdd7 100644 --- a/Ladybird/Android/src/main/AndroidManifest.xml +++ b/Ladybird/Android/src/main/AndroidManifest.xml @@ -12,6 +12,8 @@ android:smallScreens="true" /> + + - + + - + android:process=":WebContent" /> + diff --git a/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h b/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h index 1879f9a201d..a30ab0f09e2 100644 --- a/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h +++ b/Ladybird/Android/src/main/cpp/LadybirdServiceBase.h @@ -7,5 +7,8 @@ #pragma once #include +#include ErrorOr service_main(int ipc_socket, int fd_passing_socket); + +extern JavaVM* global_vm; diff --git a/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp b/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp index 3a7c12bc73f..cbd1d7d4a05 100644 --- a/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp +++ b/Ladybird/Android/src/main/cpp/LadybirdServiceBaseJNI.cpp @@ -10,6 +10,8 @@ #include #include +JavaVM* global_vm; + extern "C" JNIEXPORT void JNICALL Java_org_serenityos_ladybird_LadybirdServiceBase_nativeThreadLoop(JNIEnv*, jobject /* thiz */, jint ipc_socket, jint fd_passing_socket) { @@ -31,6 +33,8 @@ Java_org_serenityos_ladybird_LadybirdServiceBase_initNativeCode(JNIEnv* env, job return; } + env->GetJavaVM(&global_vm); + char const* raw_resource_dir = env->GetStringUTFChars(resource_dir, nullptr); s_serenity_resource_root = raw_resource_dir; env->ReleaseStringUTFChars(resource_dir, raw_resource_dir); diff --git a/Ladybird/Android/src/main/cpp/RequestServerService.cpp b/Ladybird/Android/src/main/cpp/RequestServerService.cpp new file mode 100644 index 00000000000..3856e2670e9 --- /dev/null +++ b/Ladybird/Android/src/main/cpp/RequestServerService.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018-2020, Andreas Kling + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// FIXME: Share b/w RequestServer and WebSocket +ErrorOr find_certificates(StringView serenity_resource_root) +{ + auto cert_path = TRY(String::formatted("{}/res/ladybird/cacert.pem", serenity_resource_root)); + if (!FileSystem::exists(cert_path)) { + auto app_dir = LexicalPath::dirname(TRY(Core::System::current_executable_path()).to_deprecated_string()); + + cert_path = TRY(String::formatted("{}/cacert.pem", LexicalPath(app_dir).parent())); + if (!FileSystem::exists(cert_path)) + return Error::from_string_view("Don't know how to load certs!"sv); + } + return cert_path; +} + +ErrorOr service_main(int ipc_socket, int fd_passing_socket) +{ + // Ensure the certificates are read out here. + DefaultRootCACertificates::set_default_certificate_path(TRY(find_certificates(s_serenity_resource_root))); + [[maybe_unused]] auto& certs = DefaultRootCACertificates::the(); + + Core::EventLoop event_loop; + + // FIXME: Don't leak these :V + [[maybe_unused]] auto* gemini = new RequestServer::GeminiProtocol; + [[maybe_unused]] auto* http = new RequestServer::HttpProtocol; + [[maybe_unused]] auto* https = new RequestServer::HttpsProtocol; + + auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); + auto client = TRY(RequestServer::ConnectionFromClient::try_create(move(socket))); + client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket))); + + return event_loop.exec(); +} diff --git a/Ladybird/Android/src/main/cpp/WebContentService.cpp b/Ladybird/Android/src/main/cpp/WebContentService.cpp index 919c707f6af..4fd80d2c6c3 100644 --- a/Ladybird/Android/src/main/cpp/WebContentService.cpp +++ b/Ladybird/Android/src/main/cpp/WebContentService.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include "WebContentService.h" #include "LadybirdServiceBase.h" #include #include @@ -28,15 +29,7 @@ #include #include -class NullResourceConnector : public Web::ResourceLoaderConnector { - virtual void prefetch_dns(AK::URL const&) override { } - virtual void preconnect(AK::URL const&) override { } - - virtual RefPtr start_request(DeprecatedString const&, AK::URL const&, HashMap const&, ReadonlyBytes, Core::ProxyData const&) override - { - return nullptr; - } -}; +static ErrorOr> bind_request_server_service(); ErrorOr service_main(int ipc_socket, int fd_passing_socket) { @@ -52,7 +45,8 @@ ErrorOr service_main(int ipc_socket, int fd_passing_socket) Web::FrameLoader::set_default_favicon_path(DeprecatedString::formatted("{}/res/icons/16x16/app-browser.png", s_serenity_resource_root)); - Web::ResourceLoader::initialize(make_ref_counted()); + auto request_server_client = TRY(bind_request_server_service()); + Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client)))); bool is_layout_test_mode = false; @@ -71,3 +65,29 @@ ErrorOr service_main(int ipc_socket, int fd_passing_socket) return event_loop.exec(); } + +ErrorOr> bind_request_server_service() +{ + int socket_fds[2] {}; + TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); + + int ui_fd = socket_fds[0]; + int server_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 server_fd_passing_fd = fd_passing_socket_fds[1]; + + // NOTE: The java object takes ownership of the socket fds + bind_request_server_java(server_fd, server_fd_passing_fd); + + auto socket = TRY(Core::LocalSocket::adopt_fd(ui_fd)); + TRY(socket->set_blocking(true)); + + auto new_client = TRY(try_make_ref_counted(move(socket))); + new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd))); + + return new_client; +} diff --git a/Ladybird/Android/src/main/cpp/WebContentService.h b/Ladybird/Android/src/main/cpp/WebContentService.h new file mode 100644 index 00000000000..2da6a1c0c93 --- /dev/null +++ b/Ladybird/Android/src/main/cpp/WebContentService.h @@ -0,0 +1,9 @@ +/* + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +void bind_request_server_java(int ipc_socket, int fd_passing_socket); diff --git a/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp b/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp new file mode 100644 index 00000000000..111e3940f78 --- /dev/null +++ b/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "JNIHelpers.h" +#include "LadybirdServiceBase.h" +#include + +jobject global_instance; +jclass global_class_reference; +jmethodID bind_request_server_method; + +extern "C" JNIEXPORT void JNICALL +Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject thiz) +{ + global_instance = env->NewGlobalRef(thiz); + + auto local_class = env->FindClass("org/serenityos/ladybird/WebContentService"); + if (!local_class) + TODO(); + global_class_reference = reinterpret_cast(env->NewGlobalRef(local_class)); + env->DeleteLocalRef(local_class); + + auto method = env->GetMethodID(global_class_reference, "bindRequestServer", "(II)V"); + if (!method) + TODO(); + bind_request_server_method = method; +} + +void bind_request_server_java(int ipc_socket, int fd_passing_socket) +{ + JavaEnvironment env(global_vm); + env.get()->CallVoidMethod(global_instance, bind_request_server_method, ipc_socket, fd_passing_socket); +} diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt index de5eeb5debf..84c57622640 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt @@ -9,6 +9,7 @@ package org.serenityos.ladybird import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import org.serenityos.ladybird.databinding.ActivityMainBinding +import java.net.URL import kotlin.io.path.Path class LadybirdActivity : AppCompatActivity() { @@ -37,7 +38,7 @@ class LadybirdActivity : AppCompatActivity() { super.onStart() // FIXME: This is not the right place to load the homepage :^) - val initialURL = Path(resourceDir, "res/html/misc/welcome.html").toUri().toURL() + val initialURL = URL("https://ladybird.dev") view.loadURL(initialURL) } diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt index 15d28c66392..f3f9d27a9d6 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdServiceBase.kt @@ -23,7 +23,7 @@ const val MSG_TRANSFER_SOCKETS = 2 abstract class LadybirdServiceBase(protected val TAG: String) : Service() { private val threadPool = Executors.newCachedThreadPool() - private lateinit var resourceDir: String + protected lateinit var resourceDir: String override fun onCreate() { super.onCreate() diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/RequestServerService.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/RequestServerService.kt new file mode 100644 index 00000000000..c1941a38b88 --- /dev/null +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/RequestServerService.kt @@ -0,0 +1,21 @@ +/** + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +package org.serenityos.ladybird + +import android.os.Message + +class RequestServerService : LadybirdServiceBase("RequestServerService") { + override fun handleServiceSpecificMessage(msg: Message): Boolean { + return false + } + + companion object { + init { + System.loadLibrary("requestserver") + } + } +} diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt index 5b7c9fd670c..3c531baa35c 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt @@ -6,13 +6,37 @@ package org.serenityos.ladybird +import android.content.Context +import android.content.Intent import android.os.Message +import android.util.Log class WebContentService : LadybirdServiceBase("WebContentService") { override fun handleServiceSpecificMessage(msg: Message): Boolean { return false } + init { + nativeInit(); + } + + private fun bindRequestServer(ipcFd: Int, fdPassingFd: Int) + { + val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir) + connector.onDisconnect = { + // FIXME: Notify impl that service is dead and might need restarted + Log.e(TAG, "RequestServer Died! :(") + } + // FIXME: Unbind this at some point maybe + bindService( + Intent(this, RequestServerService::class.java), + connector, + Context.BIND_AUTO_CREATE + ) + } + + external fun nativeInit() + companion object { init { System.loadLibrary("webcontent") diff --git a/Ladybird/RequestServer/CMakeLists.txt b/Ladybird/RequestServer/CMakeLists.txt index fab905c34c3..3b6f4e94e53 100644 --- a/Ladybird/RequestServer/CMakeLists.txt +++ b/Ladybird/RequestServer/CMakeLists.txt @@ -1,5 +1,9 @@ set(REQUESTSERVER_SOURCE_DIR ${SERENITY_SOURCE_DIR}/Userland/Services/RequestServer) +set(CMAKE_AUTOMOC OFF) +set(CMAKE_AUTORCC OFF) +set(CMAKE_AUTOUIC OFF) + set(REQUESTSERVER_SOURCES ${REQUESTSERVER_SOURCE_DIR}/ConnectionFromClient.cpp ${REQUESTSERVER_SOURCE_DIR}/ConnectionCache.cpp @@ -11,17 +15,28 @@ set(REQUESTSERVER_SOURCES ${REQUESTSERVER_SOURCE_DIR}/HttpsRequest.cpp ${REQUESTSERVER_SOURCE_DIR}/HttpsProtocol.cpp ${REQUESTSERVER_SOURCE_DIR}/Protocol.cpp - main.cpp ) -add_executable(RequestServer ${REQUESTSERVER_SOURCES}) +if (ANDROID) + add_library(requestserver SHARED + ${REQUESTSERVER_SOURCES} + ../Android/src/main/cpp/RequestServerService.cpp + ../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp + ../Utilities.cpp + ) +else() + add_library(requestserver STATIC ${REQUESTSERVER_SOURCES}) +endif() -target_include_directories(RequestServer PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/) -target_include_directories(RequestServer PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) -target_link_libraries(RequestServer PRIVATE LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView) +add_executable(RequestServer main.cpp) +target_link_libraries(RequestServer PRIVATE requestserver) + +target_include_directories(requestserver PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/) +target_include_directories(requestserver PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..) +target_link_libraries(requestserver PUBLIC LibCore LibMain LibCrypto LibFileSystem LibGemini LibHTTP LibIPC LibMain LibTLS LibWebView) if (${CMAKE_SYSTEM_NAME} MATCHES "SunOS") # Solaris has socket and networking related functions in two extra libraries - target_link_libraries(RequestServer PRIVATE nsl socket) + target_link_libraries(requestserver PUBLIC nsl socket) endif() if (HAIKU) # Haiku has networking related functions in the network library diff --git a/Ladybird/WebContent/CMakeLists.txt b/Ladybird/WebContent/CMakeLists.txt index 20c131dd72e..bc12a8ee108 100644 --- a/Ladybird/WebContent/CMakeLists.txt +++ b/Ladybird/WebContent/CMakeLists.txt @@ -55,6 +55,7 @@ else() if (ANDROID) target_sources(webcontent PRIVATE ../Android/src/main/cpp/WebContentService.cpp + ../Android/src/main/cpp/WebContentServiceJNI.cpp ../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp ) target_link_libraries(webcontent PRIVATE android) diff --git a/Ladybird/cmake/AndroidExtras.cmake b/Ladybird/cmake/AndroidExtras.cmake index cc137bd6ea1..672ccc98ad7 100644 --- a/Ladybird/cmake/AndroidExtras.cmake +++ b/Ladybird/cmake/AndroidExtras.cmake @@ -33,7 +33,12 @@ add_custom_target(copy-content-filters "${SERENITY_SOURCE_DIR}/Base/home/anon/.config/BrowserContentFilters.txt" "asset-bundle/res/ladybird/BrowserContentFilters.txt" ) -add_dependencies(archive-assets copy-autoplay-allowlist copy-content-filters) +add_custom_target(copy-certs + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${Lagom_BINARY_DIR}/cacert.pem" + "asset-bundle/res/ladybird/cacert.pem" +) +add_dependencies(archive-assets copy-autoplay-allowlist copy-content-filters copy-certs) add_custom_target(copy-assets COMMAND ${CMAKE_COMMAND} -E copy_if_different ladybird-assets.tar.gz "${CMAKE_SOURCE_DIR}/Android/src/main/assets/") add_dependencies(copy-assets archive-assets) add_dependencies(ladybird copy-assets) diff --git a/Ladybird/cmake/InstallRules.cmake b/Ladybird/cmake/InstallRules.cmake index c428b17fbca..9bb811bfb38 100644 --- a/Ladybird/cmake/InstallRules.cmake +++ b/Ladybird/cmake/InstallRules.cmake @@ -36,13 +36,18 @@ list(REMOVE_DUPLICATES all_required_lagom_libraries) # Remove ladybird shlib if it exists list(REMOVE_ITEM all_required_lagom_libraries ladybird) -# Install webcontent impl library if it exists -if (TARGET webcontent) - get_target_property(target_type webcontent TYPE) - if ("${target_type}" STREQUAL STATIC_LIBRARY) - list(APPEND all_required_lagom_libraries webcontent) - endif() -endif() +# Install service impl libraries if they exist +macro(install_service_lib service) + if (TARGET ${service}) + get_target_property(target_type ${service} TYPE) + if ("${target_type}" STREQUAL STATIC_LIBRARY) + list(APPEND all_required_lagom_libraries ${service}) + endif() + endif() +endmacro() +foreach(service IN LISTS webcontent requestserver) + install_service_lib(${service}) +endforeach() install(TARGETS ${all_required_lagom_libraries} EXPORT ladybirdTargets