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

Android RecreationAttempt on Activity reopen #3325

Open
SnowyCoder opened this issue Dec 26, 2023 · 5 comments · May be fixed by #3353
Open

Android RecreationAttempt on Activity reopen #3325

SnowyCoder opened this issue Dec 26, 2023 · 5 comments · May be fixed by #3353

Comments

@SnowyCoder
Copy link

When an android app calls event_loop.exit() the application exits, but if the application is opened again without closing it in the "recent apps" the EventLoop creation will fail with a RecreationAttempt error.

Steps to reproduce

Reported error

called `Result::unwrap()` on an `Err` value: RecreationAttempt

Repo explaination

The repo linked in the "Steps to reproduce" section is a modified version of the one linked in the README android section.
I just updated the dependencies and linked BrowserBack to event_loop.exit() (that sems to be the logical key invoked when the android back button is pressed).

Comment

The general problem seems to be that android_main can be called more than once without unloading and reloading the native library (ex. if we use an application with two interacting activities, say LoginActivity and GameActivity).

@daxpedda
Copy link
Member

daxpedda commented Dec 26, 2023

See #2344 (comment), which points out how this can happen on Android.

But generally speaking this is the intended behavior by Winit, you just have to figure out how to avoid having to recreate the event loop.

Let us know if this solves your problem!

@SnowyCoder
Copy link
Author

I read that conversation and it doesn't really say how to solve the issue, I've tried various approaches but haven't yet had success. Is there any example Android app that has this bug solved?

Here are my attempts:

  1. First thread creates the event loop, saves it in a const and next threads use that loop.
    Cannot work since event loops cannot be shared across threads
  2. Since that conversation talks about not creating the loop in the fake main function, create a common thread that manages the event loop and when a new invocation occurs it calls into the common thread
    Does not work since the new thread does not have an attached looper
  3. Let the first thread create the event loop and keep it alive as a "common thread" like in the second approach, reusing that event loop for the next invocations.
    Since the main thread never exits the app stops responding (I'm blocking the UI thread?)

I think that the "best" approach would be to augment the second point, spawn a new common thread that manages the event loop and manually create a looper out of it. But it involves nasty low-level JNI calls and I'm not even sure if it would really work.
If we let android recreate its event loop once it exits is, to me, the most elegant option.
(tested it commenting the RecreationAttempt line, doesn't show any sign of error).

TL;DR: I tried, but I have no idea on how to get it working without recreating the event loop or calling JNI stuff.

@SnowyCoder SnowyCoder linked a pull request Jan 3, 2024 that will close this issue
5 tasks
@MarijnS95
Copy link
Member

Per the linked comment, after previously muddling along with these issues in ndk-glue for a while, none of those design issues were addressed when android-activity was created 😩

Blindly recreating the loop when a new activity is created seems appalling. Consider activities to be analogous to Windows. Your scenario concerns "closing" one activity (I think) and then later having a new activity opened. However, it is also possible to have multiple activities opened at the same time.

Fwiw I think exiting the loop and returning out of android_main() causes your activity to be closed because of rust-mobile/android-activity#67 / rust-mobile/android-activity#81. Also notice that the callback function from Android here is called ANativeActivity_onCreate() which is not analogous to something called main(), yet pretends to be used as such.


We'll need to be more thoughtful how to handle that across the winit and android-activity bindings. You'll see the ANativeActivity_onCreate() callback in android-activity is already creating a thread to run your android_main() and the event loop in. That's likely the thread that will have to stay alive to process incoming window creation requests through ANativeActivity_onCreate(), until the process exits.

Then, we'll likely need a "New Window Created" event in winit to process this (and make the Window impl for Android a less-empty shell), and also improve the Suspended/Resumed events to operate per-surface (should be a 1:1 mapping with an activity) instead of just globally.

This means that creating a new window in winit will no longer do what you expect, and we'll have to craft some careful bindings around it.

@MarijnS95
Copy link
Member

@kchibisov kchibisov added this to the Version 0.31.0 milestone Jan 15, 2024
@mvvvv
Copy link

mvvvv commented Apr 26, 2024

I'm experiencing this issue with OpenXR on the Meta Quest. Your thread explains well why Meta discourages exit by the application and asks to systematically use the "Meta" button which pauses and allows Resume or Quit.
My problem is that not all other platforms have this button.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

5 participants