mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
Ladybird/Android: Bind a RequestServerService for networking needs
Add a RequestServerService class that uses the LadybirdServiceBase class added previously. Bind to it from the WebContentService's service_main() during startup.
This commit is contained in:
parent
da8f450335
commit
a243bc465f
Notes:
sideshowbarker
2024-07-17 21:11:12 +09:00
Author: https://github.com/ADKaster Commit: https://github.com/SerenityOS/serenity/commit/a243bc465f Pull-request: https://github.com/SerenityOS/serenity/pull/21100
15 changed files with 236 additions and 30 deletions
|
@ -12,6 +12,8 @@
|
|||
android:smallScreens="true" />
|
||||
|
||||
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
|
@ -28,27 +30,32 @@
|
|||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.Ladybird"
|
||||
tools:targetApi="33">
|
||||
|
||||
<activity
|
||||
android:name=".LadybirdActivity"
|
||||
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
android:screenOrientation="unspecified">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.extract_android_style"
|
||||
android:value="minimal" />
|
||||
</activity>
|
||||
|
||||
<service
|
||||
android:name=".WebContentService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":WebContent"/>
|
||||
android:process=":WebContent" />
|
||||
<service
|
||||
android:name=".RequestServerService"
|
||||
android:enabled="true"
|
||||
android:exported="false"
|
||||
android:process=":RequestServer" />
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
|
@ -7,5 +7,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Error.h>
|
||||
#include <jni.h>
|
||||
|
||||
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket);
|
||||
|
||||
extern JavaVM* global_vm;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include <Ladybird/Utilities.h>
|
||||
#include <jni.h>
|
||||
|
||||
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);
|
||||
|
|
55
Ladybird/Android/src/main/cpp/RequestServerService.cpp
Normal file
55
Ladybird/Android/src/main/cpp/RequestServerService.cpp
Normal file
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <Ladybird/Utilities.h>
|
||||
#include <LibCore/ArgsParser.h>
|
||||
#include <LibCore/EventLoop.h>
|
||||
#include <LibCore/LocalServer.h>
|
||||
#include <LibCore/System.h>
|
||||
#include <LibFileSystem/FileSystem.h>
|
||||
#include <LibIPC/SingleServer.h>
|
||||
#include <LibTLS/Certificate.h>
|
||||
#include <RequestServer/ConnectionFromClient.h>
|
||||
#include <RequestServer/GeminiProtocol.h>
|
||||
#include <RequestServer/HttpProtocol.h>
|
||||
#include <RequestServer/HttpsProtocol.h>
|
||||
|
||||
// FIXME: Share b/w RequestServer and WebSocket
|
||||
ErrorOr<String> 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<int> 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();
|
||||
}
|
|
@ -4,6 +4,7 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "WebContentService.h"
|
||||
#include "LadybirdServiceBase.h"
|
||||
#include <AK/LexicalPath.h>
|
||||
#include <Ladybird/FontPlugin.h>
|
||||
|
@ -28,15 +29,7 @@
|
|||
#include <WebContent/ConnectionFromClient.h>
|
||||
#include <WebContent/PageHost.h>
|
||||
|
||||
class NullResourceConnector : public Web::ResourceLoaderConnector {
|
||||
virtual void prefetch_dns(AK::URL const&) override { }
|
||||
virtual void preconnect(AK::URL const&) override { }
|
||||
|
||||
virtual RefPtr<Web::ResourceLoaderConnectorRequest> start_request(DeprecatedString const&, AK::URL const&, HashMap<DeprecatedString, DeprecatedString> const&, ReadonlyBytes, Core::ProxyData const&) override
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
static ErrorOr<NonnullRefPtr<Protocol::RequestClient>> bind_request_server_service();
|
||||
|
||||
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
|
||||
{
|
||||
|
@ -52,7 +45,8 @@ ErrorOr<int> 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<NullResourceConnector>());
|
||||
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<int> service_main(int ipc_socket, int fd_passing_socket)
|
|||
|
||||
return event_loop.exec();
|
||||
}
|
||||
|
||||
ErrorOr<NonnullRefPtr<Protocol::RequestClient>> 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<Protocol::RequestClient>(move(socket)));
|
||||
new_client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
|
||||
|
||||
return new_client;
|
||||
}
|
||||
|
|
9
Ladybird/Android/src/main/cpp/WebContentService.h
Normal file
9
Ladybird/Android/src/main/cpp/WebContentService.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
void bind_request_server_java(int ipc_socket, int fd_passing_socket);
|
36
Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp
Normal file
36
Ladybird/Android/src/main/cpp/WebContentServiceJNI.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include "JNIHelpers.h"
|
||||
#include "LadybirdServiceBase.h"
|
||||
#include <jni.h>
|
||||
|
||||
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<jclass>(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);
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
|
||||
*
|
||||
* 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")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue