diff --git a/android-activity/src/game_activity/mod.rs b/android-activity/src/game_activity/mod.rs index 70b6941..8873a32 100644 --- a/android-activity/src/game_activity/mod.rs +++ b/android-activity/src/game_activity/mod.rs @@ -295,6 +295,11 @@ impl AndroidAppInner { unsafe { let native_app = &self.native_app; + assert_eq!( + ndk_sys::ALooper_forThread(), + (*native_app.as_ptr()).looper, + "Application tried to poll events from non-main thread" + ); let mut fd: i32 = 0; let mut events: i32 = 0; @@ -590,7 +595,7 @@ impl AndroidAppInner { let mut guard = self.input_receiver.lock().unwrap(); // Make sure we don't hand out more than one receiver at a time because - // turning the reciever into an interator will perform a swap_buffers + // turning the receiver into an iterator will perform a swap_buffers // for the buffered input events which shouldn't happen while we're in // the middle of iterating events if let Some(receiver) = &*guard { diff --git a/android-activity/src/native_activity/glue.rs b/android-activity/src/native_activity/glue.rs index dab3e29..82672a5 100644 --- a/android-activity/src/native_activity/glue.rs +++ b/android-activity/src/native_activity/glue.rs @@ -447,7 +447,9 @@ impl WaitableNativeActivityState { guard.pending_input_queue = input_queue; guard.write_cmd(AppCmd::InputQueueChanged); - while guard.input_queue != guard.pending_input_queue { + while guard.thread_state == NativeThreadState::Running + && guard.input_queue != guard.pending_input_queue + { guard = self.cond.wait(guard).unwrap(); } guard.pending_input_queue = ptr::null_mut(); @@ -468,7 +470,9 @@ impl WaitableNativeActivityState { if guard.pending_window.is_some() { guard.write_cmd(AppCmd::InitWindow); } - while guard.window != guard.pending_window { + while guard.thread_state == NativeThreadState::Running + && guard.window != guard.pending_window + { guard = self.cond.wait(guard).unwrap(); } guard.pending_window = None; @@ -492,7 +496,7 @@ impl WaitableNativeActivityState { }; guard.write_cmd(cmd); - while guard.activity_state != state { + while guard.thread_state == NativeThreadState::Running && guard.activity_state != state { guard = self.cond.wait(guard).unwrap(); } } @@ -505,7 +509,7 @@ impl WaitableNativeActivityState { // this to be None debug_assert!(!guard.app_has_saved_state, "SaveState request clash"); guard.write_cmd(AppCmd::SaveState); - while !guard.app_has_saved_state { + while guard.thread_state == NativeThreadState::Running && !guard.app_has_saved_state { guard = self.cond.wait(guard).unwrap(); } guard.app_has_saved_state = false; @@ -560,7 +564,9 @@ impl WaitableNativeActivityState { pub fn notify_main_thread_stopped_running(&self) { let mut guard = self.mutex.lock().unwrap(); guard.thread_state = NativeThreadState::Stopped; - self.cond.notify_one(); + // Notify all waiters to unblock any Android callbacks that would otherwise be waiting + // indefinitely for the now-stopped (!) main thread. + self.cond.notify_all(); } pub unsafe fn pre_exec_cmd( diff --git a/android-activity/src/native_activity/mod.rs b/android-activity/src/native_activity/mod.rs index 88a9fe8..0346b98 100644 --- a/android-activity/src/native_activity/mod.rs +++ b/android-activity/src/native_activity/mod.rs @@ -201,8 +201,9 @@ impl AndroidAppInner { }; trace!("Calling ALooper_pollAll, timeout = {timeout_milliseconds}"); - assert!( - !ndk_sys::ALooper_forThread().is_null(), + assert_eq!( + ndk_sys::ALooper_forThread(), + self.looper.ptr, "Application tried to poll events from non-main thread" ); let id = ndk_sys::ALooper_pollAll(