Skip to content
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
7 changes: 6 additions & 1 deletion android-activity/src/game_activity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
16 changes: 11 additions & 5 deletions android-activity/src/native_activity/glue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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
Copy link
Member

Choose a reason for hiding this comment

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

I guess all of these (maybe with an exception for input events) should probably be checking for != NativeThreadState::Stopped so that callbacks effectively buffer during initialization and allow the app to start handling events or else exit and have this transition to Stopped.

The protocol for notifying the app about a window is supposed to be synchronous and it would be a significant change to have these start being async until the thread is initialized and 'running'.

Copy link
Member Author

Choose a reason for hiding this comment

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

Unsure about that. Android so far seems to service all callbacks into Activity from the same "thread", i.e. the one that also calls onCreate. After all, before onCreate returns we haven't assigned any callbacks yet to ANativeActivity::callbacks, so it "must" wait.

That function only returns when the state moved on from Init, so I don't think any other function should be waiting for this:

// Don't specifically wait for `Running` just in case `android_main` returns
// immediately and the state is set to `Stopped`
while guard.thread_state == NativeThreadState::Init {
guard = jvm_glue.cond.wait(guard).unwrap();
}

Copy link
Member

Choose a reason for hiding this comment

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

Aah, yep that makes sense.

&& guard.window != guard.pending_window
{
guard = self.cond.wait(guard).unwrap();
}
guard.pending_window = None;
Expand All @@ -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();
}
}
Expand All @@ -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;
Expand Down Expand Up @@ -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(
Expand Down
5 changes: 3 additions & 2 deletions android-activity/src/native_activity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Loading