Skip to content

Android: the save on the way to the background looks unreachable (SDL doesn't queue SDL_EVENT_WILL_ENTER_BACKGROUND) #767

Open

Description

@ky1vstar

ui_run in runtime/nvn/vulkan/device.c (line 2150 at d5344d7, added in 202916d) saves the pipeline cache and the settings when the app goes to the background:

while (SDL_WaitEventTimeout(&e, 16)) {
    ...
#ifdef __ANDROID__
    if (e.type == SDL_EVENT_WILL_ENTER_BACKGROUND && g_vk.dev) {
        vk_pipeline_cache_save();
        settings_save();
    }
#endif

From reading SDL, that event never comes out of the queue, so the block is dead code.

Why

SDL_SendAppEvent (src/events/SDL_events.c) does not queue the six app lifecycle events (TERMINATING, LOW_MEMORY, WILL_ENTER_BACKGROUND, DID_ENTER_BACKGROUND, WILL_ENTER_FOREGROUND, DID_ENTER_FOREGROUND). It only calls the event watchers:

// We won't actually queue this event, it needs to be handled in this call stack by an event watcher
SDL_CallEventWatchers(&event);

The function is the same in 3.4.16, which android/deps/build_deps.sh builds, and in 3.4.18. On Android the path is Android_PumpEvents -> Android_OnPause -> SDL_OnApplicationWillEnterBackground -> SDL_SendAppEvent.

The Android build installs no watcher or filter: the only SDL_AddEventWatch in the runtime is the iOS one in runtime/nvn/metal.m (background_watch), which exists for this same reason.

What is lost

When the system ends the app in the background:

  • options changed with the menu still open (the menu saves on close) - the case the comment there names;
  • pipelines compiled since the last save: the cache is otherwise written at the end of the shader preparation (renderer_prepare_end) and at exit (backend_quit).

Not checked on a device

I have no Android device set up, so this is from the source only. A log line inside the block would settle it: send the app to the background and the line should be missing from lasrecomp.log.

Fix

The same two calls from an event watcher, installed where the window is made:

static bool SDLCALL background_watch(void *ud, SDL_Event *e) {
    if (e->type == SDL_EVENT_WILL_ENTER_BACKGROUND && g_vk.dev) {
        vk_pipeline_cache_save();
        settings_save();
    }
    return true;
}
...
SDL_AddEventWatch(background_watch, NULL);

On Android the watcher runs on the thread that pumps events, inside SDL_WaitEventTimeout (SDL_WaitEventTimeoutNS calls Android_PumpEvents directly), so it is the same thread as the block it replaces.

Sharing it with iOS

The review of #238 suggested one watcher under PLAT_TOUCH for both ports (settings, rumble, audio, the hang watch's pause), with a hook for the backend. I have left that out of the iOS follow-ups: it changes the Android path, which I can't test. If you'd like it shared, the iOS half is background_watch in metal.m; I can do that part once the Android side is confirmed on a device.

(Written with GitHub Copilot.)

Activity

  1. peiikai commented on Nov 13, 2026

    @peiikai
    Owner

    Thanks, confirmed from the source: SDL_SendAppEvent in SDL 3.4.16 only calls the event watchers for the lifecycle events, so the Android block in ui_run never runs. We'll move it into an event watcher as you describe and check it on a device with a log line. We'll leave sharing the watcher with iOS for after that.

  2. peiikai commented on Nov 13, 2026

    @peiikai
    Owner

    The fix is in #769: the save now runs from an event watcher, with a log line ([app] background: saved pipeline cache and settings) so any Android log will show it working. We'll keep the iOS watcher in metal.m as it is, so there's no need to share the two. Thanks again for the report.

  3. peiikai commented on Nov 13, 2026

    @peiikai
    Owner

    Fixed in beta_6 by #769 (a98996b). It will be in the next release.

  4. added
    status: fixed pending releaseFixed in the next beta's branch; closes when that release ships
    and removed
    status: investigatingWe're working on it: the ball is in our court
    on Nov 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    status: fixed pending releaseFixed in the next beta's branch; closes when that release ships

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions