ndk: ndk-glue does not handle NativeWindow lifecycle correctly

As far as I understand, ndk-glue’s NativeActivity callbacks make it impossible or at least very hard to handle the NativeWindow lifecycle in a manner that conforms with the Android documentation. The chief offending callback is on_window_destroyed.

ANativeActivityCallbacks documentation seems to demand that NativeWindow cleanup code be executed in a synchronized manner, i.e. before the callback returns. For example, one might wish to ensure OpenGL is done drawing and destroy the associated EGLSurface.

NDK android_native_app_glue appears to follow this guideline, cf. especially how lifecycle event handling is split into pre-user-callback and post-user-callback parts (lines 89 and 146 respectively).

EDIT: for added context, compare example usage of NDK android_native_app_glue feature.

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 16 (16 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve tried digging into last year’s attempted glutin rework but it seems sufficiently different from master that it’s mostly a curiosity. 😦 I’m still not sure how exactly it allows users to keep an EGLContext alive while windows come and go. I’ll give it another read some day — I had trouble locating all the dependencies.

As for the more immediate problem, I agree. The reasonable thing is for winit to extend the lifetime of the native window until after the user handles its Suspended event. In that case, android-ndk-rs just needs to make that possible without a race or deadlock, which should require changing approximately two lines of code. 😃 I will try to put together the two PRs this weekend.

What worries me is whether various winit wrappers (including but not limited to glutin’s) are currently capable of intercepting the Suspended event and correctly destroying the implicit dependencies of the NativeWindow without forcing the user to recreate the entire graphics context, which can be quite expensive. But that should probably be discussed elsewhere.

Correct!

I think the most interesting lines are 306-308 though, showing that android_app_set_window (called from onNativeWindowDestroyed) indeed blocks and waits until the application thread processed the destroy message (android_app_post_exec_cmd indeed).

At the same time it seems unfair to pull NATIVE_WINDOW from under the application, native_window() would panic in that case.

I’ve been thinking about fixing this before, and it probably comes down to delivering this event to the application in a different way that allows us to make sure their cleanup handler has ran, surrounded by similar synchronization primitives.