Ladybird/Android: Create a service for ImageDecoder

This follows the pattern for the other services spawned by WebContent.
The notable quirk about this service is that it's actually spawned by
the ImageCodecPlugin rather than in main.cpp in the non-Android port.

As a result we needed to do some ifdef surgery to get all the pieces
in place. But we can now load images in the Android port again :^).
This commit is contained in:
Andrew Kaster 2023-10-31 15:27:23 -06:00 committed by Andrew Kaster
parent a54baa2c34
commit c990db0913
10 changed files with 108 additions and 8 deletions

View file

@ -61,6 +61,11 @@
android:enabled="true"
android:exported="false"
android:process=":WebSocket" />
<service
android:name=".ImageDecoderService"
android:enabled="true"
android:exported="false"
android:process=":ImageDecoder" />
</application>
</manifest>

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2023, Andrew Kaster <akaster@serenityos.org>
* Copyright (c) 2023, Lucas Chollet <lucas.chollet@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <ImageDecoder/ConnectionFromClient.h>
#include <LibCore/EventLoop.h>
#include <LibIPC/SingleServer.h>
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)
{
Core::EventLoop event_loop;
auto socket = TRY(Core::LocalSocket::adopt_fd(ipc_socket));
auto client = TRY(ImageDecoder::ConnectionFromClient::try_create(move(socket)));
client->set_fd_passing_socket(TRY(Core::LocalSocket::adopt_fd(fd_passing_socket)));
return event_loop.exec();
}

View file

@ -17,6 +17,7 @@
#include <LibCore/LocalServer.h>
#include <LibCore/System.h>
#include <LibIPC/ConnectionFromClient.h>
#include <LibImageDecoderClient/Client.h>
#include <LibJS/Bytecode/Interpreter.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/HTML/Window.h>
@ -41,7 +42,11 @@ static ErrorOr<NonnullRefPtr<Protocol::WebSocketClient>> bind_web_socket_service
return bind_service<Protocol::WebSocketClient>(&bind_web_socket_java);
}
template ErrorOr<NonnullRefPtr<ImageDecoderClient::Client>, Error>
bind_service<ImageDecoderClient::Client>(void (*)(int, int));
static ErrorOr<void> load_content_filters();
static ErrorOr<void> load_autoplay_allowlist();
ErrorOr<int> service_main(int ipc_socket, int fd_passing_socket)

View file

@ -13,3 +13,4 @@ ErrorOr<NonnullRefPtr<Client>> bind_service(void (*bind_method)(int, int));
void bind_request_server_java(int ipc_socket, int fd_passing_socket);
void bind_web_socket_java(int ipc_socket, int fd_passing_socket);
void bind_image_decoder_java(int ipc_socket, int fd_passing_socket);

View file

@ -12,6 +12,7 @@ jobject global_instance;
jclass global_class_reference;
jmethodID bind_request_server_method;
jmethodID bind_web_socket_method;
jmethodID bind_image_decoder_method;
extern "C" JNIEXPORT void JNICALL
Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject thiz)
@ -33,6 +34,11 @@ Java_org_serenityos_ladybird_WebContentService_nativeInit(JNIEnv* env, jobject t
if (!method)
TODO();
bind_web_socket_method = method;
method = env->GetMethodID(global_class_reference, "bindImageDecoder", "(II)V");
if (!method)
TODO();
bind_image_decoder_method = method;
}
void bind_request_server_java(int ipc_socket, int fd_passing_socket)
@ -46,3 +52,9 @@ void bind_web_socket_java(int ipc_socket, int fd_passing_socket)
Ladybird::JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(global_instance, bind_web_socket_method, ipc_socket, fd_passing_socket);
}
void bind_image_decoder_java(int ipc_socket, int fd_passing_socket)
{
Ladybird::JavaEnvironment env(global_vm);
env.get()->CallVoidMethod(global_instance, bind_image_decoder_method, ipc_socket, fd_passing_socket);
}

View file

@ -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 ImageDecoderService : LadybirdServiceBase("ImageDecoderService") {
override fun handleServiceSpecificMessage(msg: Message): Boolean {
return false
}
companion object {
init {
System.loadLibrary("imagedecoder")
}
}
}

View file

@ -40,7 +40,7 @@ class WebContentService : LadybirdServiceBase("WebContentService") {
val connector = LadybirdServiceConnection(ipcFd, fdPassingFd, resourceDir)
connector.onDisconnect = {
// FIXME: Notify impl that service is dead and might need restarted
Log.e(TAG, "RequestServer Died! :(")
Log.e(TAG, "WebSocket Died! :(")
}
// FIXME: Unbind this at some point maybe
bindService(
@ -50,6 +50,21 @@ class WebContentService : LadybirdServiceBase("WebContentService") {
)
}
private fun bindImageDecoder(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, "ImageDecoder Died! :(")
}
// FIXME: Unbind this at some point maybe
bindService(
Intent(this, ImageDecoderService::class.java),
connector,
Context.BIND_AUTO_CREATE
)
}
external fun nativeInit()
companion object {

View file

@ -6,7 +6,11 @@
*/
#include "ImageCodecPlugin.h"
#include "HelperProcess.h"
#ifdef AK_OS_ANDROID
# include <Ladybird/Android/src/main/cpp/WebContentService.h>
#else
# include "HelperProcess.h"
#endif
#include "Utilities.h"
#include <LibGfx/Bitmap.h>
#include <LibGfx/ImageFormats/ImageDecoder.h>
@ -19,8 +23,12 @@ ImageCodecPlugin::~ImageCodecPlugin() = default;
Optional<Web::Platform::DecodedImage> ImageCodecPlugin::decode_image(ReadonlyBytes bytes)
{
if (!m_client) {
#ifdef AK_OS_ANDROID
m_client = MUST(bind_service<ImageDecoderClient::Client>(&bind_image_decoder_java));
#else
auto candidate_image_decoder_paths = get_paths_for_helper_process("ImageDecoder"sv).release_value_but_fixme_should_propagate_errors();
m_client = launch_image_decoder_process(candidate_image_decoder_paths).release_value_but_fixme_should_propagate_errors();
#endif
m_client->on_death = [&] {
m_client = nullptr;
};

View file

@ -2,11 +2,22 @@ set(IMAGE_DECODER_SOURCE_DIR ${SERENITY_SOURCE_DIR}/Userland/Services/ImageDecod
set(IMAGE_DECODER_SOURCES
${IMAGE_DECODER_SOURCE_DIR}/ConnectionFromClient.cpp
main.cpp
)
add_executable(ImageDecoder ${IMAGE_DECODER_SOURCES})
if (ANDROID)
add_library(imagedecoder SHARED
${IMAGE_DECODER_SOURCES}
../Android/src/main/cpp/ImageDecoderService.cpp
../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp
../Utilities.cpp
)
else()
add_library(imagedecoder STATIC ${IMAGE_DECODER_SOURCES})
endif()
target_include_directories(ImageDecoder PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
target_include_directories(ImageDecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
target_link_libraries(ImageDecoder PRIVATE LibCore LibGfx LibIPC LibImageDecoderClient LibMain)
add_executable(ImageDecoder main.cpp)
target_link_libraries(ImageDecoder PRIVATE imagedecoder LibMain)
target_include_directories(imagedecoder PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
target_include_directories(imagedecoder PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
target_link_libraries(imagedecoder PRIVATE LibCore LibGfx LibIPC LibImageDecoderClient LibMain)

View file

@ -37,7 +37,7 @@ else()
add_library(webcontent ${LIB_TYPE} ${WEBCONTENT_SOURCES})
target_include_directories(webcontent PRIVATE ${SERENITY_SOURCE_DIR}/Userland/Services/)
target_include_directories(webcontent PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/..)
target_link_libraries(webcontent PRIVATE LibAudio LibCore LibFileSystem LibGfx LibIPC LibJS LibMain LibWeb LibWebSocket LibProtocol LibWebView)
target_link_libraries(webcontent PRIVATE LibAudio LibCore LibFileSystem LibGfx LibIPC LibJS LibMain LibWeb LibWebSocket LibProtocol LibWebView LibImageDecoderClient)
target_sources(webcontent PUBLIC FILE_SET ladybird TYPE HEADERS
BASE_DIRS ${SERENITY_SOURCE_DIR}
FILES ../FontPlugin.h