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()