Skip to content

Marshal SetSustainedPerformanceMode onto the Android UI thread - #240

Merged
winnerspiros merged 1 commit into
masterfrom
copilot/fix-apk-crash-issue-one-more-time
Apr 22, 2026
Merged

Marshal SetSustainedPerformanceMode onto the Android UI thread#240
winnerspiros merged 1 commit into
masterfrom
copilot/fix-apk-crash-issue-one-more-time

Conversation

Copilot AI commented Apr 22, 2026

Copy link
Copy Markdown

OsuGameAndroid.LoadComplete invoked Window.SetSustainedPerformanceMode(true) from the load thread. ViewRootImpl.checkThread() threw CalledFromWrongThreadException after window private flags had already been partially mutated, leaving the active VkSurfaceKHR pointing at freed driver state — the next frame crashed inside qglinternal::vkCmdBeginRendering (vulkan.adreno.so + 0x4, fault_addr=0x28), followed by an input-dispatch ANR.

Changes

  • osu.Android/OsuGameAndroid.cs — wrap the SetSustainedPerformanceMode call in gameActivity.RunOnUiThread(...), matching the pattern already used by every other Window/Window.Attributes mutator in this file (applyPerformanceOptimizations, applyDeXImmersiveMode, applyDisplayMode, RequestUnbufferedDispatch). Outer try/catch guards the dispatch itself; inner try/catch preserves the existing best-effort semantics.
gameActivity.RunOnUiThread(() =>
{
    try { gameActivity.Window?.SetSustainedPerformanceMode(true); }
    catch (Exception e) { Debug.WriteLine($"[osu!] Failed to enable sustained performance mode: {e.Message}"); }
});

Notes

  • No osu-framework changes required; the offending call lives entirely in this repo.
  • The pre-existing Vulkan surface-init guard in the framework submodule is unrelated and remains in place for cold-start surface readiness.

The call in OsuGameAndroid.LoadComplete ran on the load thread, which made
ViewRootImpl.checkThread() throw CalledFromWrongThreadException after the
window state had already been partially mutated. On Adreno this invalidated
the active VkSurfaceKHR and crashed the driver inside vkCmdBeginRendering
on the next frame (SIGSEGV at vulkan.adreno.so +0x4, fault_addr=0x28).

Wrap the call in gameActivity.RunOnUiThread(...) like every other Window
mutator in this file already is.

Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/f3d3c197-120b-4c7d-b2ef-fca9776d19d2

Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
@winnerspiros
winnerspiros marked this pull request as ready for review April 22, 2026 15:01
Copilot AI review requested due to automatic review settings April 22, 2026 15:01
@winnerspiros
winnerspiros merged commit f50f127 into master Apr 22, 2026
14 of 16 checks passed
@gitar-bot

gitar-bot Bot commented Apr 22, 2026

Copy link
Copy Markdown

Important

You are using the Gitar free plan. Upgrade to unlock code review, CI analysis, auto-apply, custom automations, and more.

Gitar

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Fixes an Android threading violation where Window.SetSustainedPerformanceMode(true) was being invoked off the UI thread during OsuGameAndroid.LoadComplete(), leading to CalledFromWrongThreadException and (on some devices) destabilising the active Vulkan surface.

Changes:

  • Dispatch SetSustainedPerformanceMode(true) via gameActivity.RunOnUiThread(...).
  • Add structured try/catch handling to preserve best-effort behaviour while avoiding unhandled exceptions.
  • Document the underlying Android ViewRootImpl.checkThread() constraint and the observed Vulkan crash chain.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants