Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ndk-glue: Move native activity behind lock and remove it in onDestroy #160

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions ndk-examples/examples/looper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,5 @@ fn main() {
}

// Stop the activity
#[allow(deprecated)]
ndk_glue::native_activity().finish()
ndk_glue::native_activity().unwrap().finish()
}
5 changes: 5 additions & 0 deletions ndk-glue/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Unreleased

- **Breaking:** `NativeActivity` is now behind a lock, and will be removed as soon as `onDestroy`
is called. Due to the async nature of events, make sure to hold on to the lock received from
`native_activity()` _beforehand_ if you wish to use it during handling of `Event::Destroy`. The
lock should be released to allow `onDestroy` to return.

# 0.7.0 (2022-07-24)

- **Breaking:** Provide a `LockReadGuard` newtype around `NativeWindow`/`InputQueue` to hide the underlying lock implementation. (#288)
Expand Down
24 changes: 15 additions & 9 deletions ndk-glue/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,20 @@ pub fn android_log(level: Level, tag: &CStr, msg: &CStr) {
}
}

static NATIVE_ACTIVITY: Lazy<RwLock<Option<NativeActivity>>> = Lazy::new(Default::default);
static NATIVE_WINDOW: Lazy<RwLock<Option<NativeWindow>>> = Lazy::new(Default::default);
static INPUT_QUEUE: Lazy<RwLock<Option<InputQueue>>> = Lazy::new(Default::default);
static CONTENT_RECT: Lazy<RwLock<Rect>> = Lazy::new(Default::default);
static LOOPER: Lazy<Mutex<Option<ForeignLooper>>> = Lazy::new(Default::default);

static mut NATIVE_ACTIVITY: Option<NativeActivity> = None;

/// This function accesses a `static` variable internally and must only be used if you are sure
/// there is exactly one version of `ndk_glue` in your dependency tree.
/// there is exactly one version of [`ndk_glue`][crate] in your dependency tree.
///
/// If you need access to the `JavaVM` through [`NativeActivity::vm()`] or Activity `Context`
/// through [`NativeActivity::activity()`], please use the [`ndk_context`] crate and its
/// [`ndk_context::android_context()`] getter to acquire the `JavaVM` and `Context` instead.
pub fn native_activity() -> &'static NativeActivity {
unsafe { NATIVE_ACTIVITY.as_ref().unwrap() }
pub fn native_activity() -> Option<LockReadGuard<NativeActivity>> {
LockReadGuard::from_wrapped_option(NATIVE_ACTIVITY.read())
}

pub struct LockReadGuard<T: ?Sized + 'static>(MappedRwLockReadGuard<'static, T>);
Expand Down Expand Up @@ -182,6 +181,11 @@ pub enum Event {
SaveInstanceState,
Pause,
Stop,
/// The native activity will be stopped and destroyed after this event.
/// Due to the async nature of these events, make sure to hold on to the
/// lock received from [`native_activity()`] _beforehand_ if you wish to use
/// it during handling of [`Event::Destroy`]. The lock should be released to
/// allow `onDestroy` to return.
Destroy,
ConfigChanged,
LowMemory,
Expand Down Expand Up @@ -249,7 +253,7 @@ pub unsafe fn init(

let activity = NativeActivity::from_ptr(activity);
ndk_context::initialize_android_context(activity.vm().cast(), activity.activity().cast());
NATIVE_ACTIVITY.replace(activity);
NATIVE_ACTIVITY.write().replace(activity);

let mut logpipe: [RawFd; 2] = Default::default();
libc::pipe(logpipe.as_mut_ptr());
Expand Down Expand Up @@ -334,6 +338,9 @@ unsafe extern "C" fn on_stop(activity: *mut ANativeActivity) {
unsafe extern "C" fn on_destroy(activity: *mut ANativeActivity) {
wake(activity, Event::Destroy);
ndk_context::release_android_context();
let mut native_activity_guard = NATIVE_ACTIVITY.write();
let native_activity = native_activity_guard.take().unwrap();
assert_eq!(native_activity.ptr().as_ptr(), activity);
Comment on lines +341 to +343
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NativeActivity doesn't have a drop handler (that would previously call .finish() in the original revision of this PR) so nothing funky is going to happen, just that users will now get None out of fn native_activity().

}

unsafe extern "C" fn on_configuration_changed(activity: *mut ANativeActivity) {
Expand Down Expand Up @@ -407,10 +414,9 @@ unsafe extern "C" fn on_input_queue_destroyed(
) {
wake(activity, Event::InputQueueDestroyed);
let mut input_queue_guard = INPUT_QUEUE.write();
assert_eq!(input_queue_guard.as_ref().unwrap().ptr().as_ptr(), queue);
let input_queue = InputQueue::from_ptr(NonNull::new(queue).unwrap());
let input_queue = input_queue_guard.take().unwrap();
assert_eq!(input_queue.ptr().as_ptr(), queue);
input_queue.detach_looper();
input_queue_guard.take();
}

unsafe extern "C" fn on_content_rect_changed(activity: *mut ANativeActivity, rect: *const ARect) {
Expand Down