Skip to content

Commit d6ccefa

Browse files
notgullrib
andcommitted
Add catch unwind wrappers to extern "C" functions
Co-authored-by: Robert Bragg <robert@sixbynine.org>
1 parent e0c96ad commit d6ccefa

3 files changed

Lines changed: 257 additions & 188 deletions

File tree

android-activity/src/game_activity/mod.rs

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ndk::asset::AssetManager;
2323
use ndk::configuration::Configuration;
2424
use ndk::native_window::NativeWindow;
2525

26-
use crate::util::android_log;
26+
use crate::util::{abort_on_panic, android_log};
2727
use crate::{
2828
util, AndroidApp, ConfigurationRef, InputStatus, MainEvent, PollEvent, Rect, WindowManagerFlags,
2929
};
@@ -604,55 +604,57 @@ extern "Rust" {
604604
// by android_native_app_glue.
605605
#[no_mangle]
606606
pub unsafe extern "C" fn _rust_glue_entry(app: *mut ffi::android_app) {
607-
// Maybe make this stdout/stderr redirection an optional / opt-in feature?...
608-
let mut logpipe: [RawFd; 2] = Default::default();
609-
libc::pipe(logpipe.as_mut_ptr());
610-
libc::dup2(logpipe[1], libc::STDOUT_FILENO);
611-
libc::dup2(logpipe[1], libc::STDERR_FILENO);
612-
thread::spawn(move || {
613-
let tag = CStr::from_bytes_with_nul(b"RustStdoutStderr\0").unwrap();
614-
let file = File::from_raw_fd(logpipe[0]);
615-
let mut reader = BufReader::new(file);
616-
let mut buffer = String::new();
617-
loop {
618-
buffer.clear();
619-
if let Ok(len) = reader.read_line(&mut buffer) {
620-
if len == 0 {
621-
break;
622-
} else if let Ok(msg) = CString::new(buffer.clone()) {
623-
android_log(Level::Info, tag, &msg);
607+
abort_on_panic(|| {
608+
// Maybe make this stdout/stderr redirection an optional / opt-in feature?...
609+
let mut logpipe: [RawFd; 2] = Default::default();
610+
libc::pipe(logpipe.as_mut_ptr());
611+
libc::dup2(logpipe[1], libc::STDOUT_FILENO);
612+
libc::dup2(logpipe[1], libc::STDERR_FILENO);
613+
thread::spawn(move || {
614+
let tag = CStr::from_bytes_with_nul(b"RustStdoutStderr\0").unwrap();
615+
let file = File::from_raw_fd(logpipe[0]);
616+
let mut reader = BufReader::new(file);
617+
let mut buffer = String::new();
618+
loop {
619+
buffer.clear();
620+
if let Ok(len) = reader.read_line(&mut buffer) {
621+
if len == 0 {
622+
break;
623+
} else if let Ok(msg) = CString::new(buffer.clone()) {
624+
android_log(Level::Info, tag, &msg);
625+
}
624626
}
625627
}
626-
}
627-
});
628+
});
628629

629-
let jvm: *mut JavaVM = (*(*app).activity).vm;
630-
let activity: jobject = (*(*app).activity).javaGameActivity;
631-
ndk_context::initialize_android_context(jvm.cast(), activity.cast());
630+
let jvm: *mut JavaVM = (*(*app).activity).vm;
631+
let activity: jobject = (*(*app).activity).javaGameActivity;
632+
ndk_context::initialize_android_context(jvm.cast(), activity.cast());
632633

633-
let app = AndroidApp::from_ptr(NonNull::new(app).unwrap());
634+
let app = AndroidApp::from_ptr(NonNull::new(app).unwrap());
634635

635-
// Since this is a newly spawned thread then the JVM hasn't been attached
636-
// to the thread yet. Attach before calling the applications main function
637-
// so they can safely make JNI calls
638-
let mut jenv_out: *mut core::ffi::c_void = std::ptr::null_mut();
639-
if let Some(attach_current_thread) = (*(*jvm)).AttachCurrentThread {
640-
attach_current_thread(jvm, &mut jenv_out, std::ptr::null_mut());
641-
}
636+
// Since this is a newly spawned thread then the JVM hasn't been attached
637+
// to the thread yet. Attach before calling the applications main function
638+
// so they can safely make JNI calls
639+
let mut jenv_out: *mut core::ffi::c_void = std::ptr::null_mut();
640+
if let Some(attach_current_thread) = (*(*jvm)).AttachCurrentThread {
641+
attach_current_thread(jvm, &mut jenv_out, std::ptr::null_mut());
642+
}
642643

643-
// XXX: If we were in control of the Java Activity subclass then
644-
// we could potentially run the android_main function via a Java native method
645-
// springboard (e.g. call an Activity subclass method that calls a jni native
646-
// method that then just calls android_main()) that would make sure there was
647-
// a Java frame at the base of our call stack which would then be recognised
648-
// when calling FindClass to lookup a suitable classLoader, instead of
649-
// defaulting to the system loader. Without this then it's difficult for native
650-
// code to look up non-standard Java classes.
651-
android_main(app);
652-
653-
if let Some(detach_current_thread) = (*(*jvm)).DetachCurrentThread {
654-
detach_current_thread(jvm);
655-
}
644+
// XXX: If we were in control of the Java Activity subclass then
645+
// we could potentially run the android_main function via a Java native method
646+
// springboard (e.g. call an Activity subclass method that calls a jni native
647+
// method that then just calls android_main()) that would make sure there was
648+
// a Java frame at the base of our call stack which would then be recognised
649+
// when calling FindClass to lookup a suitable classLoader, instead of
650+
// defaulting to the system loader. Without this then it's difficult for native
651+
// code to look up non-standard Java classes.
652+
android_main(app);
653+
654+
if let Some(detach_current_thread) = (*(*jvm)).DetachCurrentThread {
655+
detach_current_thread(jvm);
656+
}
656657

657-
ndk_context::release_android_context();
658+
ndk_context::release_android_context();
659+
})
658660
}

0 commit comments

Comments
 (0)