diff --git a/Ladybird/Android/src/main/AndroidManifest.xml b/Ladybird/Android/src/main/AndroidManifest.xml index 7fe1232bdd..c654cc0cb0 100644 --- a/Ladybird/Android/src/main/AndroidManifest.xml +++ b/Ladybird/Android/src/main/AndroidManifest.xml @@ -56,6 +56,11 @@ android:enabled="true" android:exported="false" android:process=":RequestServer" /> + diff --git a/Ladybird/Android/src/main/cpp/WebContentService.cpp b/Ladybird/Android/src/main/cpp/WebContentService.cpp index 4fd80d2c6c..343ba1af08 100644 --- a/Ladybird/Android/src/main/cpp/WebContentService.cpp +++ b/Ladybird/Android/src/main/cpp/WebContentService.cpp @@ -29,7 +29,18 @@ #include #include -static ErrorOr> bind_request_server_service(); +template +static ErrorOr> bind_service(void (*bind_method)(int, int)); + +static ErrorOr> bind_request_server_service() +{ + return bind_service(&bind_request_server_java); +} + +static ErrorOr> bind_web_socket_service() +{ + return bind_service(&bind_web_socket_java); +} ErrorOr service_main(int ipc_socket, int fd_passing_socket) { @@ -48,6 +59,9 @@ ErrorOr service_main(int ipc_socket, int fd_passing_socket) auto request_server_client = TRY(bind_request_server_service()); Web::ResourceLoader::initialize(TRY(WebView::RequestServerAdapter::try_create(move(request_server_client)))); + auto web_socket_client = TRY(bind_web_socket_service()); + Web::WebSockets::WebSocketClientManager::initialize(TRY(WebView::WebSocketClientManagerAdapter::try_create(move(web_socket_client)))); + bool is_layout_test_mode = false; Web::HTML::Window::set_internals_object_exposed(is_layout_test_mode); @@ -66,7 +80,8 @@ ErrorOr service_main(int ipc_socket, int fd_passing_socket) return event_loop.exec(); } -ErrorOr> bind_request_server_service() +template +static ErrorOr> bind_service(void (*bind_method)(int, int)) { int socket_fds[2] {}; TRY(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds)); @@ -81,12 +96,12 @@ ErrorOr> bind_request_server_service() 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); + (*bind_method)(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))); + 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 index 2da6a1c0c9..895fabef68 100644 --- a/Ladybird/Android/src/main/cpp/WebContentService.h +++ b/Ladybird/Android/src/main/cpp/WebContentService.h @@ -7,3 +7,4 @@ #pragma once void bind_request_server_java(int ipc_socket, int fd_passing_socket); +void bind_web_socket_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 index 111e3940f7..ce84fba167 100644 --- a/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp +++ b/Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp @@ -11,6 +11,7 @@ jobject global_instance; jclass global_class_reference; jmethodID bind_request_server_method; +jmethodID bind_web_socket_method; extern "C" JNIEXPORT void JNICALL Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject thiz) @@ -27,6 +28,11 @@ Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject t if (!method) TODO(); bind_request_server_method = method; + + method = env->GetMethodID(global_class_reference, "bindWebSocket", "(II)V"); + if (!method) + TODO(); + bind_web_socket_method = method; } void bind_request_server_java(int ipc_socket, int fd_passing_socket) @@ -34,3 +40,9 @@ 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); } + +void bind_web_socket_java(int ipc_socket, int fd_passing_socket) +{ + JavaEnvironment env(global_vm); + env.get()->CallVoidMethod(global_instance, bind_web_socket_method, ipc_socket, fd_passing_socket); +} diff --git a/Ladybird/Android/src/main/cpp/WebSocketService.cpp b/Ladybird/Android/src/main/cpp/WebSocketService.cpp new file mode 100644 index 0000000000..aad52eb5cf --- /dev/null +++ b/Ladybird/Android/src/main/cpp/WebSocketService.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021, Dex♪ + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#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; + + auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket)); + auto client = TRY(WebSocket::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/java/org/serenityos/ladybird/WebContentService.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt index 3c531baa35..705445a236 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebContentService.kt @@ -35,6 +35,21 @@ class WebContentService : LadybirdServiceBase("WebContentService") { ) } + private fun bindWebSocket(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, WebSocketService::class.java), + connector, + Context.BIND_AUTO_CREATE + ) + } + external fun nativeInit() companion object { diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebSocketService.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebSocketService.kt new file mode 100644 index 0000000000..6d3a2e894f --- /dev/null +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebSocketService.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 WebSocketService : LadybirdServiceBase("WebSocketService") { + override fun handleServiceSpecificMessage(msg: Message): Boolean { + return false + } + + companion object { + init { + System.loadLibrary("websocket") + } + } +} diff --git a/Ladybird/WebSocket/CMakeLists.txt b/Ladybird/WebSocket/CMakeLists.txt index 86066d836d..3e230a05cb 100644 --- a/Ladybird/WebSocket/CMakeLists.txt +++ b/Ladybird/WebSocket/CMakeLists.txt @@ -1,8 +1,18 @@ set(SOURCES "${SERENITY_SOURCE_DIR}/Userland/Services/WebSocket/ConnectionFromClient.cpp" - main.cpp ) -add_executable(WebSocketServer ${SOURCES}) +if (ANDROID) + add_library(websocket SHARED + ${SOURCES} + ../Android/src/main/cpp/WebSocketService.cpp + ../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp + ../Utilities.cpp + ) +else() + add_library(websocket STATIC ${SOURCES}) +endif() +add_executable(WebSocketServer main.cpp) +target_link_libraries(WebSocketServer PRIVATE websocket) set_target_properties(WebSocketServer PROPERTIES OUTPUT_NAME WebSocket) -target_link_libraries(WebSocketServer PRIVATE LibCore LibFileSystem LibIPC LibMain LibTLS LibWebSocket LibWebView) +target_link_libraries(websocket PUBLIC LibCore LibFileSystem LibIPC LibMain LibTLS LibWebSocket LibWebView) diff --git a/Ladybird/cmake/InstallRules.cmake b/Ladybird/cmake/InstallRules.cmake index 9bb811bfb3..2aa6f7c0a6 100644 --- a/Ladybird/cmake/InstallRules.cmake +++ b/Ladybird/cmake/InstallRules.cmake @@ -45,7 +45,7 @@ macro(install_service_lib service) endif() endif() endmacro() -foreach(service IN LISTS webcontent requestserver) +foreach(service IN LISTS webcontent requestserver websocket) install_service_lib(${service}) endforeach()