mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-14 15:13:07 +00:00
Ladybird: Add WebContentService for Android port
This will let us spawn a new process for an Android Service to handle all our WebContent needs. The ServiceConnection is manged by each WebView. The lifecycle of the Service is not quite clear yet, but each bindService call will get a unique Messenger that can be used to transfer the WebContent side of the LibIPC socketpair we use in other ports.
This commit is contained in:
parent
ffc0046d74
commit
6952de73dc
Notes:
sideshowbarker
2024-07-17 08:34:29 +09:00
Author: https://github.com/ADKaster
Commit: 6952de73dc
Pull-request: https://github.com/SerenityOS/serenity/pull/20978
Reviewed-by: https://github.com/bugaevc
9 changed files with 334 additions and 40 deletions
|
@ -4,9 +4,10 @@
|
|||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/Painter.h>
|
||||
#include <LibWebView/ViewImplementation.h>
|
||||
#include <Userland/Libraries/LibGfx/Bitmap.h>
|
||||
#include <Userland/Libraries/LibGfx/Painter.h>
|
||||
#include <Userland/Libraries/LibWeb/Crypto/Crypto.h>
|
||||
#include <Userland/Libraries/LibWebView/ViewImplementation.h>
|
||||
#include <android/bitmap.h>
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
@ -23,13 +24,75 @@ Gfx::BitmapFormat to_gfx_bitmap_format(i32 f)
|
|||
}
|
||||
}
|
||||
|
||||
class JavaEnvironment {
|
||||
public:
|
||||
JavaEnvironment(JavaVM* vm)
|
||||
: m_vm(vm)
|
||||
{
|
||||
auto ret = m_vm->GetEnv(reinterpret_cast<void**>(&m_env), JNI_VERSION_1_6);
|
||||
if (ret == JNI_EDETACHED) {
|
||||
ret = m_vm->AttachCurrentThread(&m_env, nullptr);
|
||||
VERIFY(ret == JNI_OK);
|
||||
m_did_attach_thread = true;
|
||||
} else if (ret == JNI_EVERSION) {
|
||||
VERIFY_NOT_REACHED();
|
||||
} else {
|
||||
VERIFY(ret == JNI_OK);
|
||||
}
|
||||
|
||||
VERIFY(m_env != nullptr);
|
||||
}
|
||||
|
||||
~JavaEnvironment()
|
||||
{
|
||||
if (m_did_attach_thread)
|
||||
m_vm->DetachCurrentThread();
|
||||
}
|
||||
|
||||
JNIEnv* get() const { return m_env; }
|
||||
|
||||
private:
|
||||
JavaVM* m_vm = nullptr;
|
||||
JNIEnv* m_env = nullptr;
|
||||
bool m_did_attach_thread = false;
|
||||
};
|
||||
|
||||
class WebViewImplementationNative : public WebView::ViewImplementation {
|
||||
public:
|
||||
WebViewImplementationNative(jobject thiz)
|
||||
: m_java_instance(thiz)
|
||||
{
|
||||
// NOTE: m_java_instance's global ref is controlled by the JNI bindings
|
||||
create_client(WebView::EnableCallgrindProfiling::No);
|
||||
}
|
||||
|
||||
virtual Gfx::IntRect viewport_rect() const override { return m_viewport_rect; }
|
||||
virtual Gfx::IntPoint to_content_position(Gfx::IntPoint p) const override { return p; }
|
||||
virtual Gfx::IntPoint to_widget_position(Gfx::IntPoint p) const override { return p; }
|
||||
virtual void update_zoom() override { }
|
||||
|
||||
NonnullRefPtr<WebView::WebContentClient> bind_web_content_client();
|
||||
|
||||
virtual void create_client(WebView::EnableCallgrindProfiling) override
|
||||
{
|
||||
m_client_state = {};
|
||||
|
||||
auto new_client = bind_web_content_client();
|
||||
|
||||
m_client_state.client = new_client;
|
||||
m_client_state.client->on_web_content_process_crash = [] {
|
||||
__android_log_print(ANDROID_LOG_ERROR, "Ladybird", "WebContent crashed!");
|
||||
// FIXME: launch a new client
|
||||
};
|
||||
|
||||
m_client_state.client_handle = MUST(Web::Crypto::generate_random_uuid());
|
||||
client().async_set_window_handle(m_client_state.client_handle);
|
||||
|
||||
client().async_set_device_pixels_per_css_pixel(m_device_pixel_ratio);
|
||||
|
||||
// FIXME: update_palette, update system fonts
|
||||
}
|
||||
|
||||
void paint_into_bitmap(void* android_bitmap_raw, AndroidBitmapInfo const& info)
|
||||
{
|
||||
// Software bitmaps only for now!
|
||||
|
@ -64,40 +127,89 @@ public:
|
|||
|
||||
static jclass global_class_reference;
|
||||
static jfieldID instance_pointer_field;
|
||||
static jmethodID bind_webcontent_method;
|
||||
static JavaVM* global_vm;
|
||||
|
||||
jobject java_instance() const { return m_java_instance; }
|
||||
|
||||
private:
|
||||
jobject m_java_instance = nullptr;
|
||||
Gfx::IntRect m_viewport_rect;
|
||||
};
|
||||
jclass WebViewImplementationNative::global_class_reference;
|
||||
jfieldID WebViewImplementationNative::instance_pointer_field;
|
||||
jmethodID WebViewImplementationNative::bind_webcontent_method;
|
||||
JavaVM* WebViewImplementationNative::global_vm;
|
||||
|
||||
NonnullRefPtr<WebView::WebContentClient> WebViewImplementationNative::bind_web_content_client()
|
||||
{
|
||||
JavaEnvironment env(WebViewImplementationNative::global_vm);
|
||||
|
||||
int socket_fds[2] {};
|
||||
MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, socket_fds));
|
||||
|
||||
int ui_fd = socket_fds[0];
|
||||
int wc_fd = socket_fds[1];
|
||||
|
||||
int fd_passing_socket_fds[2] {};
|
||||
MUST(Core::System::socketpair(AF_LOCAL, SOCK_STREAM, 0, fd_passing_socket_fds));
|
||||
|
||||
int ui_fd_passing_fd = fd_passing_socket_fds[0];
|
||||
int wc_fd_passing_fd = fd_passing_socket_fds[1];
|
||||
|
||||
// NOTE: The java object takes ownership of the socket fds
|
||||
env.get()->CallVoidMethod(m_java_instance, bind_webcontent_method, wc_fd, wc_fd_passing_fd);
|
||||
|
||||
auto socket = MUST(Core::LocalSocket::adopt_fd(ui_fd));
|
||||
MUST(socket->set_blocking(true));
|
||||
|
||||
auto new_client = make_ref_counted<WebView::WebContentClient>(move(socket), *this);
|
||||
new_client->set_fd_passing_socket(MUST(Core::LocalSocket::adopt_fd(ui_fd_passing_fd)));
|
||||
|
||||
return new_client;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_serenityos_ladybird_WebViewImplementation_00024Companion_nativeClassInit(JNIEnv* env, jobject /* thiz */)
|
||||
{
|
||||
auto ret = env->GetJavaVM(&WebViewImplementationNative::global_vm);
|
||||
if (ret != 0)
|
||||
TODO();
|
||||
|
||||
auto local_class = env->FindClass("org/serenityos/ladybird/WebViewImplementation");
|
||||
if (!local_class)
|
||||
TODO();
|
||||
WebViewImplementationNative::global_class_reference = reinterpret_cast<jclass>(env->NewGlobalRef(local_class));
|
||||
env->DeleteLocalRef(local_class);
|
||||
|
||||
auto field = env->GetFieldID(WebViewImplementationNative::global_class_reference, "nativeInstance", "J");
|
||||
if (!field)
|
||||
TODO();
|
||||
WebViewImplementationNative::instance_pointer_field = field;
|
||||
|
||||
auto method = env->GetMethodID(WebViewImplementationNative::global_class_reference, "bindWebContentService", "(II)V");
|
||||
if (!method)
|
||||
TODO();
|
||||
WebViewImplementationNative::bind_webcontent_method = method;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT jlong JNICALL
|
||||
Java_org_serenityos_ladybird_WebViewImplementation_nativeObjectInit(JNIEnv*, jobject /* thiz */)
|
||||
Java_org_serenityos_ladybird_WebViewImplementation_nativeObjectInit(JNIEnv* env, jobject thiz)
|
||||
{
|
||||
auto instance = reinterpret_cast<jlong>(new WebViewImplementationNative);
|
||||
auto ref = env->NewGlobalRef(thiz);
|
||||
auto instance = reinterpret_cast<jlong>(new WebViewImplementationNative(ref));
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "Ladybird", "New WebViewImplementationNative at %p", reinterpret_cast<void*>(instance));
|
||||
return instance;
|
||||
}
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_org_serenityos_ladybird_WebViewImplementation_nativeObjectDispose(JNIEnv*, jobject /* thiz */, jlong instance)
|
||||
Java_org_serenityos_ladybird_WebViewImplementation_nativeObjectDispose(JNIEnv* env, jobject /* thiz */, jlong instance)
|
||||
{
|
||||
delete reinterpret_cast<WebViewImplementationNative*>(instance);
|
||||
auto* impl = reinterpret_cast<WebViewImplementationNative*>(instance);
|
||||
env->DeleteGlobalRef(impl->java_instance());
|
||||
delete impl;
|
||||
__android_log_print(ANDROID_LOG_DEBUG, "Ladybird", "Destroyed WebViewImplementationNative at %p", reinterpret_cast<void*>(instance));
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue