Upgrade jni to 0.21.1 (#32216)

JNI methods in `jniapi` now have explicit lifetime
annotations to adapt it to the new `jni` version.

Signed-off-by: Mukilan Thiyagarajan <mukilan@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Mukilan Thiyagarajan <mukilan@igalia.com>
This commit is contained in:
Delan Azabani 2024-05-20 21:46:09 +08:00 committed by GitHub
parent 53c0726ef4
commit 8d2d955bbb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 247 additions and 213 deletions

18
Cargo.lock generated
View file

@ -101,7 +101,7 @@ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
"cc", "cc",
"cesu8", "cesu8",
"jni 0.21.1", "jni",
"jni-sys", "jni-sys",
"libc", "libc",
"log", "log",
@ -3119,20 +3119,6 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "jni"
version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24967112a1e4301ca5342ea339763613a37592b8a6ce6cf2e4494537c7a42faf"
dependencies = [
"cesu8",
"combine",
"jni-sys",
"log",
"thiserror",
"walkdir",
]
[[package]] [[package]]
name = "jni" name = "jni"
version = "0.21.1" version = "0.21.1"
@ -5727,7 +5713,7 @@ dependencies = [
"getopts", "getopts",
"gl_generator", "gl_generator",
"ipc-channel", "ipc-channel",
"jni 0.18.0", "jni",
"libc", "libc",
"libloading 0.8.3", "libloading 0.8.3",
"libservo", "libservo",

View file

@ -17,7 +17,7 @@ bench = false
android_logger = "0.13" android_logger = "0.13"
getopts = { workspace = true } getopts = { workspace = true }
ipc-channel = { workspace = true } ipc-channel = { workspace = true }
jni = "0.18.0" jni = "0.21.1"
libc = { workspace = true } libc = { workspace = true }
libloading = "0.8" libloading = "0.8"
libservo = { path = "../../components/servo" } libservo = { path = "../../components/servo" }

View file

@ -13,8 +13,8 @@ use std::sync::Arc;
use std::thread; use std::thread;
use android_logger::{self, Config, FilterBuilder}; use android_logger::{self, Config, FilterBuilder};
use jni::objects::{GlobalRef, JClass, JObject, JString, JValue}; use jni::objects::{GlobalRef, JClass, JObject, JString, JValue, JValueOwned};
use jni::sys::{jboolean, jfloat, jint, jstring, JNI_TRUE}; use jni::sys::{jboolean, jfloat, jint, jobject, jstring, JNI_TRUE};
use jni::{JNIEnv, JavaVM}; use jni::{JNIEnv, JavaVM};
use libc::{dup2, pipe, read}; use libc::{dup2, pipe, read};
use log::{debug, error, info, warn}; use log::{debug, error, info, warn};
@ -29,7 +29,7 @@ struct HostCallbacks {
} }
extern "C" { extern "C" {
fn ANativeWindow_fromSurface(env: *mut jni::sys::JNIEnv, surface: JObject) -> *mut c_void; fn ANativeWindow_fromSurface(env: *mut jni::sys::JNIEnv, surface: jobject) -> *mut c_void;
} }
#[no_mangle] #[no_mangle]
@ -41,7 +41,7 @@ pub extern "C" fn android_main() {
// this currently. // this currently.
} }
fn call<F>(env: &JNIEnv, f: F) fn call<F>(env: &mut JNIEnv, f: F)
where where
F: Fn(&mut ServoGlue) -> Result<(), &str>, F: Fn(&mut ServoGlue) -> Result<(), &str>,
{ {
@ -56,27 +56,28 @@ where
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_version( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_version<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_class: JClass, _class: JClass<'local>,
) -> jstring { ) -> JString<'local> {
let v = simpleservo::servo_version(); let v = simpleservo::servo_version();
new_string(&env, &v).unwrap_or_else(|null| null) env.new_string(&v)
.unwrap_or_else(|_str| JObject::null().into())
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_init( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_init<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
_activity: JObject, _activity: JObject<'local>,
opts: JObject, opts: JObject<'local>,
callbacks_obj: JObject, callbacks_obj: JObject<'local>,
surface: JObject, surface: JObject<'local>,
) { ) {
let (opts, log, log_str, _gst_debug_str) = match get_options(&env, opts, surface) { let (opts, log, log_str, _gst_debug_str) = match get_options(&mut env, &opts, &surface) {
Ok((opts, log, log_str, gst_debug_str)) => (opts, log, log_str, gst_debug_str), Ok((opts, log, log_str, gst_debug_str)) => (opts, log, log_str, gst_debug_str),
Err(err) => { Err(err) => {
throw(&env, &err); throw(&mut env, &err);
return; return;
}, },
}; };
@ -122,7 +123,10 @@ pub extern "C" fn Java_org_mozilla_servoview_JNIServo_init(
let callbacks_ref = match env.new_global_ref(callbacks_obj) { let callbacks_ref = match env.new_global_ref(callbacks_obj) {
Ok(r) => r, Ok(r) => r,
Err(_) => { Err(_) => {
throw(&env, "Failed to get global reference of callback argument"); throw(
&mut env,
"Failed to get global reference of callback argument",
);
return; return;
}, },
}; };
@ -133,270 +137,301 @@ pub extern "C" fn Java_org_mozilla_servoview_JNIServo_init(
if let Err(err) = gl_glue::egl::init() if let Err(err) = gl_glue::egl::init()
.and_then(|egl_init| simpleservo::init(opts, egl_init.gl_wrapper, wakeup, callbacks)) .and_then(|egl_init| simpleservo::init(opts, egl_init.gl_wrapper, wakeup, callbacks))
{ {
throw(&env, err) throw(&mut env, err)
}; };
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_setBatchMode( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_setBatchMode<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
batch: jboolean, batch: jboolean,
) { ) {
debug!("setBatchMode"); debug!("setBatchMode");
call(&env, |s| s.set_batch_mode(batch == JNI_TRUE)); call(&mut env, |s| s.set_batch_mode(batch == JNI_TRUE));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_requestShutdown(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_requestShutdown<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("requestShutdown"); debug!("requestShutdown");
call(&env, |s| s.request_shutdown()); call(&mut env, |s| s.request_shutdown());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_deinit(_env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_deinit<'local>(
_env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("deinit"); debug!("deinit");
simpleservo::deinit(); simpleservo::deinit();
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_resize( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_resize<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
coordinates: JObject, coordinates: JObject<'local>,
) { ) {
let coords = jni_coords_to_rust_coords(&env, coordinates); let coords = jni_coords_to_rust_coords(&mut env, &coordinates);
debug!("resize {:#?}", coords); debug!("resize {:#?}", coords);
match coords { match coords {
Ok(coords) => call(&env, |s| s.resize(coords.clone())), Ok(coords) => call(&mut env, |s| s.resize(coords.clone())),
Err(error) => throw(&env, &error), Err(error) => throw(&mut env, &error),
} }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_performUpdates(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_performUpdates<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("performUpdates"); debug!("performUpdates");
call(&env, |s| s.perform_updates()); call(&mut env, |s| s.perform_updates());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_loadUri( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_loadUri<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_class: JClass, _class: JClass<'local>,
url: JString, url: JString<'local>,
) { ) {
debug!("loadUri"); debug!("loadUri");
match env.get_string(url) { match env.get_string(&url) {
Ok(url) => { Ok(url) => {
let url: String = url.into(); let url: String = url.into();
call(&env, |s| s.load_uri(&url)); call(&mut env, |s| s.load_uri(&url));
}, },
Err(_) => { Err(_) => {
throw(&env, "Failed to convert Java string"); throw(&mut env, "Failed to convert Java string");
}, },
}; };
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_reload(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_reload<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("reload"); debug!("reload");
call(&env, |s| s.reload()); call(&mut env, |s| s.reload());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_stop(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_stop<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("stop"); debug!("stop");
call(&env, |s| s.stop()); call(&mut env, |s| s.stop());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_refresh(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_refresh<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("refresh"); debug!("refresh");
call(&env, |s| s.refresh()); call(&mut env, |s| s.refresh());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_goBack(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_goBack<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("goBack"); debug!("goBack");
call(&env, |s| s.go_back()); call(&mut env, |s| s.go_back());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_goForward(env: JNIEnv, _class: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_goForward<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
) {
debug!("goForward"); debug!("goForward");
call(&env, |s| s.go_forward()); call(&mut env, |s| s.go_forward());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_scrollStart( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_scrollStart<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
dx: jint, dx: jint,
dy: jint, dy: jint,
x: jint, x: jint,
y: jint, y: jint,
) { ) {
debug!("scrollStart"); debug!("scrollStart");
call(&env, |s| { call(&mut env, |s| {
s.scroll_start(dx as f32, dy as f32, x as i32, y as i32) s.scroll_start(dx as f32, dy as f32, x as i32, y as i32)
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_scrollEnd( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_scrollEnd<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
dx: jint, dx: jint,
dy: jint, dy: jint,
x: jint, x: jint,
y: jint, y: jint,
) { ) {
debug!("scrollEnd"); debug!("scrollEnd");
call(&env, |s| { call(&mut env, |s| {
s.scroll_end(dx as f32, dy as f32, x as i32, y as i32) s.scroll_end(dx as f32, dy as f32, x as i32, y as i32)
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_scroll( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_scroll<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
dx: jint, dx: jint,
dy: jint, dy: jint,
x: jint, x: jint,
y: jint, y: jint,
) { ) {
debug!("scroll"); debug!("scroll");
call(&env, |s| s.scroll(dx as f32, dy as f32, x as i32, y as i32)); call(&mut env, |s| {
s.scroll(dx as f32, dy as f32, x as i32, y as i32)
});
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchDown( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchDown<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
x: jfloat, x: jfloat,
y: jfloat, y: jfloat,
pointer_id: jint, pointer_id: jint,
) { ) {
debug!("touchDown"); debug!("touchDown");
call(&env, |s| s.touch_down(x, y, pointer_id as i32)); call(&mut env, |s| s.touch_down(x, y, pointer_id as i32));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchUp( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchUp<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
x: jfloat, x: jfloat,
y: jfloat, y: jfloat,
pointer_id: jint, pointer_id: jint,
) { ) {
debug!("touchUp"); debug!("touchUp");
call(&env, |s| s.touch_up(x, y, pointer_id as i32)); call(&mut env, |s| s.touch_up(x, y, pointer_id as i32));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchMove( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchMove<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
x: jfloat, x: jfloat,
y: jfloat, y: jfloat,
pointer_id: jint, pointer_id: jint,
) { ) {
debug!("touchMove"); debug!("touchMove");
call(&env, |s| s.touch_move(x, y, pointer_id as i32)); call(&mut env, |s| s.touch_move(x, y, pointer_id as i32));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchCancel( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_touchCancel<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
x: jfloat, x: jfloat,
y: jfloat, y: jfloat,
pointer_id: jint, pointer_id: jint,
) { ) {
debug!("touchCancel"); debug!("touchCancel");
call(&env, |s| s.touch_cancel(x, y, pointer_id as i32)); call(&mut env, |s| s.touch_cancel(x, y, pointer_id as i32));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pinchZoomStart( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pinchZoomStart<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
factor: jfloat, factor: jfloat,
x: jint, x: jint,
y: jint, y: jint,
) { ) {
debug!("pinchZoomStart"); debug!("pinchZoomStart");
call(&env, |s| { call(&mut env, |s| {
s.pinchzoom_start(factor as f32, x as u32, y as u32) s.pinchzoom_start(factor as f32, x as u32, y as u32)
}); });
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pinchZoom( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pinchZoom<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
factor: jfloat, factor: jfloat,
x: jint, x: jint,
y: jint, y: jint,
) { ) {
debug!("pinchZoom"); debug!("pinchZoom");
call(&env, |s| s.pinchzoom(factor as f32, x as u32, y as u32)); call(&mut env, |s| s.pinchzoom(factor as f32, x as u32, y as u32));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pinchZoomEnd( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pinchZoomEnd<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
factor: jfloat, factor: jfloat,
x: jint, x: jint,
y: jint, y: jint,
) { ) {
debug!("pinchZoomEnd"); debug!("pinchZoomEnd");
call(&env, |s| s.pinchzoom_end(factor as f32, x as u32, y as u32)); call(&mut env, |s| {
s.pinchzoom_end(factor as f32, x as u32, y as u32)
});
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_click( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_click<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
x: jfloat, x: jfloat,
y: jfloat, y: jfloat,
) { ) {
debug!("click"); debug!("click");
call(&env, |s| s.click(x as f32, y as f32)); call(&mut env, |s| s.click(x as f32, y as f32));
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pauseCompositor(env: JNIEnv, _: JClass) { pub extern "C" fn Java_org_mozilla_servoview_JNIServo_pauseCompositor<'local>(
mut env: JNIEnv,
_: JClass<'local>,
) {
debug!("pauseCompositor"); debug!("pauseCompositor");
call(&env, |s| s.pause_compositor()); call(&mut env, |s| s.pause_compositor());
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_resumeCompositor( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_resumeCompositor<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
surface: JObject, surface: JObject<'local>,
coordinates: JObject, coordinates: JObject<'local>,
) { ) {
debug!("resumeCompositor"); debug!("resumeCompositor");
let widget = unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface) }; let widget = unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
let coords = jni_coords_to_rust_coords(&env, coordinates); let coords = jni_coords_to_rust_coords(&mut env, &coordinates);
match coords { match coords {
Ok(coords) => call(&env, |s| s.resume_compositor(widget, coords.clone())), Ok(coords) => call(&mut env, |s| s.resume_compositor(widget, coords.clone())),
Err(error) => throw(&env, &error), Err(error) => throw(&mut env, &error),
} }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn Java_org_mozilla_servoview_JNIServo_mediaSessionAction( pub extern "C" fn Java_org_mozilla_servoview_JNIServo_mediaSessionAction<'local>(
env: JNIEnv, mut env: JNIEnv<'local>,
_: JClass, _: JClass<'local>,
action: jint, action: jint,
) { ) {
debug!("mediaSessionAction"); debug!("mediaSessionAction");
call(&env, |s| s.media_session_action((action as i32).into())); call(&mut env, |s| s.media_session_action((action as i32).into()));
} }
pub struct WakeupCallback { pub struct WakeupCallback {
@ -420,7 +455,7 @@ impl EventLoopWaker for WakeupCallback {
} }
fn wake(&self) { fn wake(&self) {
debug!("wakeup"); debug!("wakeup");
let env = self.jvm.attach_current_thread().unwrap(); let mut env = self.jvm.attach_current_thread().unwrap();
env.call_method(self.callback.as_obj(), "wakeup", "()V", &[]) env.call_method(self.callback.as_obj(), "wakeup", "()V", &[])
.unwrap(); .unwrap();
} }
@ -436,17 +471,15 @@ impl HostCallbacks {
impl HostTrait for HostCallbacks { impl HostTrait for HostCallbacks {
fn prompt_alert(&self, message: String, _trusted: bool) { fn prompt_alert(&self, message: String, _trusted: bool) {
debug!("prompt_alert"); debug!("prompt_alert");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let s = match new_string(&env, &message) { let Ok(string) = new_string_as_jvalue(&mut env, &message) else {
Ok(s) => s, return;
Err(_) => return,
}; };
let s = JValue::from(JObject::from(s));
env.call_method( env.call_method(
self.callbacks.as_obj(), self.callbacks.as_obj(),
"onAlert", "onAlert",
"(Ljava/lang/String;)V", "(Ljava/lang/String;)V",
&[s], &[(&string).into()],
) )
.unwrap(); .unwrap();
} }
@ -468,56 +501,52 @@ impl HostTrait for HostCallbacks {
fn on_load_started(&self) { fn on_load_started(&self) {
debug!("on_load_started"); debug!("on_load_started");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
env.call_method(self.callbacks.as_obj(), "onLoadStarted", "()V", &[]) env.call_method(self.callbacks.as_obj(), "onLoadStarted", "()V", &[])
.unwrap(); .unwrap();
} }
fn on_load_ended(&self) { fn on_load_ended(&self) {
debug!("on_load_ended"); debug!("on_load_ended");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
env.call_method(self.callbacks.as_obj(), "onLoadEnded", "()V", &[]) env.call_method(self.callbacks.as_obj(), "onLoadEnded", "()V", &[])
.unwrap(); .unwrap();
} }
fn on_shutdown_complete(&self) { fn on_shutdown_complete(&self) {
debug!("on_shutdown_complete"); debug!("on_shutdown_complete");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
env.call_method(self.callbacks.as_obj(), "onShutdownComplete", "()V", &[]) env.call_method(self.callbacks.as_obj(), "onShutdownComplete", "()V", &[])
.unwrap(); .unwrap();
} }
fn on_title_changed(&self, title: Option<String>) { fn on_title_changed(&self, title: Option<String>) {
debug!("on_title_changed"); debug!("on_title_changed");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let title = title.unwrap_or_else(String::new); let title = title.unwrap_or_else(String::new);
let s = match new_string(&env, &title) { let Ok(title_string) = new_string_as_jvalue(&mut env, &title) else {
Ok(s) => s, return;
Err(_) => return,
}; };
let s = JValue::from(JObject::from(s));
env.call_method( env.call_method(
self.callbacks.as_obj(), self.callbacks.as_obj(),
"onTitleChanged", "onTitleChanged",
"(Ljava/lang/String;)V", "(Ljava/lang/String;)V",
&[s], &[(&title_string).into()],
) )
.unwrap(); .unwrap();
} }
fn on_allow_navigation(&self, url: String) -> bool { fn on_allow_navigation(&self, url: String) -> bool {
debug!("on_allow_navigation"); debug!("on_allow_navigation");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let s = match new_string(&env, &url) { let Ok(url_string) = new_string_as_jvalue(&mut env, &url) else {
Ok(s) => s, return false;
Err(_) => return false,
}; };
let s = JValue::from(JObject::from(s));
let allow = env.call_method( let allow = env.call_method(
self.callbacks.as_obj(), self.callbacks.as_obj(),
"onAllowNavigation", "onAllowNavigation",
"(Ljava/lang/String;)Z", "(Ljava/lang/String;)Z",
&[s], &[(&url_string).into()],
); );
match allow { match allow {
Ok(allow) => return allow.z().unwrap(), Ok(allow) => return allow.z().unwrap(),
@ -527,24 +556,22 @@ impl HostTrait for HostCallbacks {
fn on_url_changed(&self, url: String) { fn on_url_changed(&self, url: String) {
debug!("on_url_changed"); debug!("on_url_changed");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let s = match new_string(&env, &url) { let Ok(url_string) = new_string_as_jvalue(&mut env, &url) else {
Ok(s) => s, return;
Err(_) => return,
}; };
let s = JValue::Object(JObject::from(s));
env.call_method( env.call_method(
self.callbacks.as_obj(), self.callbacks.as_obj(),
"onUrlChanged", "onUrlChanged",
"(Ljava/lang/String;)V", "(Ljava/lang/String;)V",
&[s], &[(&url_string).into()],
) )
.unwrap(); .unwrap();
} }
fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) { fn on_history_changed(&self, can_go_back: bool, can_go_forward: bool) {
debug!("on_history_changed"); debug!("on_history_changed");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let can_go_back = JValue::Bool(can_go_back as jboolean); let can_go_back = JValue::Bool(can_go_back as jboolean);
let can_go_forward = JValue::Bool(can_go_forward as jboolean); let can_go_forward = JValue::Bool(can_go_forward as jboolean);
env.call_method( env.call_method(
@ -558,7 +585,7 @@ impl HostTrait for HostCallbacks {
fn on_animating_changed(&self, animating: bool) { fn on_animating_changed(&self, animating: bool) {
debug!("on_animating_changed"); debug!("on_animating_changed");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let animating = JValue::Bool(animating as jboolean); let animating = JValue::Bool(animating as jboolean);
env.call_method( env.call_method(
self.callbacks.as_obj(), self.callbacks.as_obj(),
@ -587,36 +614,31 @@ impl HostTrait for HostCallbacks {
fn on_media_session_metadata(&self, title: String, artist: String, album: String) { fn on_media_session_metadata(&self, title: String, artist: String, album: String) {
info!("on_media_session_metadata"); info!("on_media_session_metadata");
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let title = match new_string(&env, &title) { let Ok(title) = new_string_as_jvalue(&mut env, &title) else {
Ok(s) => s, return;
Err(_) => return,
}; };
let title = JValue::Object(JObject::from(title));
let artist = match new_string(&env, &artist) { let Ok(artist) = new_string_as_jvalue(&mut env, &artist) else {
Ok(s) => s, return;
Err(_) => return,
}; };
let artist = JValue::Object(JObject::from(artist));
let album = match new_string(&env, &album) { let Ok(album) = new_string_as_jvalue(&mut env, &album) else {
Ok(s) => s, return;
Err(_) => return,
}; };
let album = JValue::Object(JObject::from(album));
env.call_method( env.call_method(
self.callbacks.as_obj(), self.callbacks.as_obj(),
"onMediaSessionMetadata", "onMediaSessionMetadata",
"(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
&[title, artist, album], &[(&title).into(), (&artist).into(), (&album).into()],
) )
.unwrap(); .unwrap();
} }
fn on_media_session_playback_state_change(&self, state: MediaSessionPlaybackState) { fn on_media_session_playback_state_change(&self, state: MediaSessionPlaybackState) {
info!("on_media_session_playback_state_change {:?}", state); info!("on_media_session_playback_state_change {:?}", state);
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let state = state as i32; let state = state as i32;
let state = JValue::Int(state as jint); let state = JValue::Int(state as jint);
env.call_method( env.call_method(
@ -638,7 +660,7 @@ impl HostTrait for HostCallbacks {
"on_media_session_playback_state_change ({:?}, {:?}, {:?})", "on_media_session_playback_state_change ({:?}, {:?}, {:?})",
duration, position, playback_rate duration, position, playback_rate
); );
let env = self.jvm.get_env().unwrap(); let mut env = self.jvm.get_env().unwrap();
let duration = JValue::Float(duration as jfloat); let duration = JValue::Float(duration as jfloat);
let position = JValue::Float(position as jfloat); let position = JValue::Float(position as jfloat);
let playback_rate = JValue::Float(playback_rate as jfloat); let playback_rate = JValue::Float(playback_rate as jfloat);
@ -753,7 +775,7 @@ fn redirect_stdout_to_logcat() {
}); });
} }
fn throw(env: &JNIEnv, err: &str) { fn throw(env: &mut JNIEnv, err: &str) {
if let Err(e) = env.throw(("java/lang/Exception", err)) { if let Err(e) = env.throw(("java/lang/Exception", err)) {
warn!( warn!(
"Failed to throw Java exception: `{}`. Exception was: `{}`", "Failed to throw Java exception: `{}`. Exception was: `{}`",
@ -762,17 +784,34 @@ fn throw(env: &JNIEnv, err: &str) {
} }
} }
fn new_string(env: &JNIEnv, s: &str) -> Result<jstring, jstring> { fn new_string(env: &mut JNIEnv, s: &str) -> Result<jstring, &'static str> {
match env.new_string(s) { match env.new_string(s) {
Ok(s) => Ok(s.into_inner()), Ok(s) => Ok(s.into_raw()),
Err(_) => { Err(_) => {
throw(&env, "Couldn't create java string"); throw(env, "Couldn't create Java string");
Err(JObject::null().into_inner()) Err("Couldn't create Java String")
}, },
} }
} }
fn jni_coords_to_rust_coords(env: &JNIEnv, obj: JObject) -> Result<Coordinates, String> { fn new_string_as_jvalue<'local>(
env: &mut JNIEnv<'local>,
input_string: &str,
) -> Result<JValueOwned<'local>, &'static str> {
let jstring = match env.new_string(input_string) {
Ok(jstring) => jstring,
Err(_) => {
throw(env, "Couldn't create Java string");
return Err("Couldn't create Java string");
},
};
Ok(JValueOwned::from(jstring))
}
fn jni_coords_to_rust_coords<'local>(
env: &mut JNIEnv<'local>,
obj: &JObject<'local>,
) -> Result<Coordinates, String> {
let x = get_non_null_field(env, obj, "x", "I")? let x = get_non_null_field(env, obj, "x", "I")?
.i() .i()
.map_err(|_| "x not an int")? as i32; .map_err(|_| "x not an int")? as i32;
@ -794,55 +833,64 @@ fn jni_coords_to_rust_coords(env: &JNIEnv, obj: JObject) -> Result<Coordinates,
Ok(Coordinates::new(x, y, width, height, fb_width, fb_height)) Ok(Coordinates::new(x, y, width, height, fb_width, fb_height))
} }
fn get_field<'a>( fn get_field<'local>(
env: &'a JNIEnv, env: &mut JNIEnv<'local>,
obj: JObject<'a>, obj: &JObject<'local>,
field: &str, field: &str,
type_: &str, type_: &str,
) -> Result<Option<JValue<'a>>, String> { ) -> Result<Option<JValueOwned<'local>>, String> {
if env.get_field_id(obj, field, type_).is_err() { let Ok(class) = env.get_object_class(obj) else {
return Err("Can't get object class".to_owned());
};
if env.get_field_id(class, field, type_).is_err() {
return Err(format!("Can't find `{}` field", field)); return Err(format!("Can't find `{}` field", field));
} }
env.get_field(obj, field, type_) env.get_field(obj, field, type_)
.map(|value| Some(value)) .map(|value| Some(value))
.or_else(|_| Err(format!("Can't find `{}` field", field))) .or_else(|_| Err(format!("Can't find `{}` field", field)))
} }
fn get_non_null_field<'a>( fn get_non_null_field<'local>(
env: &'a JNIEnv, env: &mut JNIEnv<'local>,
obj: JObject<'a>, obj: &JObject<'local>,
field: &str, field: &str,
type_: &str, type_: &str,
) -> Result<JValue<'a>, String> { ) -> Result<JValueOwned<'local>, String> {
match get_field(env, obj, field, type_)? { match get_field(env, obj, field, type_)? {
None => Err(format!("Field {} is null", field)), None => Err(format!("Field {} is null", field)),
Some(f) => Ok(f), Some(f) => Ok(f),
} }
} }
fn get_string(env: &JNIEnv, obj: JObject, field: &str) -> Result<Option<String>, String> { fn get_field_as_string<'local>(
env: &mut JNIEnv<'local>,
obj: &JObject<'local>,
field: &str,
) -> Result<Option<String>, String> {
let string = {
let value = get_field(env, obj, field, "Ljava/lang/String;")?; let value = get_field(env, obj, field, "Ljava/lang/String;")?;
match value { let Some(value) = value else {
Some(value) => { return Ok(None);
let string = value };
value
.l() .l()
.map_err(|_| format!("field `{}` is not an Object", field))? .map_err(|_| format!("field `{}` is not an Object", field))?
.into(); };
Ok(env.get_string(string).map(|s| s.into()).ok())
}, Ok(env.get_string((&string).into()).map(|s| s.into()).ok())
None => Ok(None),
}
} }
fn get_options( fn get_options<'local>(
env: &JNIEnv, env: &mut JNIEnv<'local>,
opts: JObject, opts: &JObject<'local>,
surface: JObject, surface: &JObject<'local>,
) -> Result<(InitOptions, bool, Option<String>, Option<String>), String> { ) -> Result<(InitOptions, bool, Option<String>, Option<String>), String> {
let args = get_string(env, opts, "args")?; let args = get_field_as_string(env, opts, "args")?;
let url = get_string(env, opts, "url")?; let url = get_field_as_string(env, opts, "url")?;
let log_str = get_string(env, opts, "logStr")?; let log_str = get_field_as_string(env, opts, "logStr")?;
let gst_debug_str = get_string(env, opts, "gstDebugStr")?; let gst_debug_str = get_field_as_string(env, opts, "gstDebugStr")?;
let density = get_non_null_field(env, opts, "density", "F")? let density = get_non_null_field(env, opts, "density", "F")?
.f() .f()
.map_err(|_| "densitiy not a float")? as f32; .map_err(|_| "densitiy not a float")? as f32;
@ -857,7 +905,7 @@ fn get_options(
)? )?
.l() .l()
.map_err(|_| "coordinates is not an object")?; .map_err(|_| "coordinates is not an object")?;
let coordinates = jni_coords_to_rust_coords(&env, coordinates)?; let coordinates = jni_coords_to_rust_coords(env, &coordinates)?;
let args = match args { let args = match args {
Some(args) => serde_json::from_str(&args) Some(args) => serde_json::from_str(&args)
@ -865,7 +913,8 @@ fn get_options(
None => None, None => None,
}; };
let native_window = unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface) }; let native_window =
unsafe { ANativeWindow_fromSurface(env.get_native_interface(), surface.as_raw()) };
// FIXME: enable JIT compilation on 32-bit Android after the startup crash issue (#31134) is fixed. // FIXME: enable JIT compilation on 32-bit Android after the startup crash issue (#31134) is fixed.
let prefs = if cfg!(target_pointer_width = "32") { let prefs = if cfg!(target_pointer_width = "32") {

View file

@ -37,7 +37,6 @@ packages = [
"toml", "toml",
# Duplicated by winit. # Duplicated by winit.
"jni",
"windows-sys", "windows-sys",
"windows-targets", "windows-targets",
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",