Make Android startup crashes diagnosable: keep native symbols + in-process crash dumper to user-accessible file - #229
Merged
Conversation
…tones Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/6792646b-591b-4936-be8f-3b37c75f326f Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
…er-accessible file Agent-Logs-Url: https://github.com/winnerspiros/osu/sessions/32bf9963-5972-40a3-829b-d3f16f69ad4f Co-authored-by: winnerspiros <1675249+winnerspiros@users.noreply.github.com>
Copilot created this pull request from a session on behalf of
winnerspiros
April 22, 2026 06:08
View session
winnerspiros
marked this pull request as ready for review
April 22, 2026 06:08
There was a problem hiding this comment.
Pull request overview
This PR improves Android native-crash diagnosability by keeping native symbols in release builds and adding an in-process native crash handler that writes a symbolicated backtrace (plus registers/signal info) to both logcat and a user-accessible file.
Changes:
- Install a native signal handler early in
OsuGameActivity.OnCreate()to capture SIGSEGV/SIGBUS/SIGILL/SIGFPE/SIGABRT and dump crash details. - Add new native crash handler implementation (
crash_handler.{cpp,h}) and expose it via P/Invoke (OboeAudioBridge.nInstallCrashHandler). - Adjust native build flags to avoid stripping (
-s) and explicitly linklibdlfordladdr().
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| osu.Android/OsuGameActivity.cs | Installs the native crash handler early and best-effort. |
| osu.Android/Native/crash_handler.h | Declares nInstallCrashHandler() native entry point. |
| osu.Android/Native/crash_handler.cpp | Implements signal handler, register dump, unwinding, dladdr symbol resolution, and file/logcat output. |
| osu.Android/Native/OboeAudioBridge.cs | Adds P/Invoke declaration for nInstallCrashHandler. |
| osu.Android/Native/CMakeLists.txt | Stops stripping native symbols and links crash handler + dl. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+173
to
+178
| writeHex64(st->fd, (uint64_t)off, 1); | ||
| writeStr(st->fd, ")"); | ||
| } else if (info.dli_fbase) { | ||
| uintptr_t off = pc - (uintptr_t)info.dli_fbase; | ||
| writeStr(st->fd, " (lib+0x"); | ||
| writeHex64(st->fd, (uint64_t)off, 1); |
Comment on lines
+306
to
+309
| if (g_inHandler) { | ||
| signal(sig, SIG_DFL); | ||
| raise(sig); | ||
| return; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
v148 still crashes ~5s into startup on
SDLThreadwithsignal 11 / pc=0x0, and the only artifact available is the unsymbolicated 2-frame summary from a Play Store crash viewer. Five prior PRs guessed at fixes against this same opaque tombstone; none stuck. This PR fixes the diagnostics gap so the next occurrence pinpoints the actual call site.Tombstone re-read (registers, no symbols)
pc=0+x21=0xb400…(Scudo heap tag) ⇒ indirect call through a NULL function-pointer slot on a heap object.lr=0x74b7012738lies in a system-library mapping range (libvulkan / libsdl3 / libaaudio) — notlibosu_native.so.SDLThreadaligns with Veldrid Vulkan instance/device/swapchain creation (Vulkan is the Android default on this fork).Most likely cause:
vkGet{Instance,Device}ProcAddrreturningNULLfor an extension entry point that gets called blindly. That's framework/Veldrid/driver territory — confirming it requires a real backtrace.Changes
Stop stripping
libosu_native.so— drop-sfromCMAKE_SHARED_LINKER_FLAGS_RELEASE.--gc-sectionsstill removes unreferenced code; only the symbol table is retained, sodladdr(and any third-party tombstone viewer) can resolve PCs to function names. Cost: a few hundred KB on-device; no impact on APK download size with LZ4 assembly compression.New
osu.Android/Native/crash_handler.{cpp,h}— async-signal-safe handler forSIGSEGV/SIGBUS/SIGILL/SIGFPE/SIGABRT:sigaltstack(survives stack overflow)._Unwind_Backtrace, resolves frames viadladdr(lib + sym + offset).osu!crash) and<external-files-dir>/native_crash.log— reachable from Android's Files app on unrooted devices.write/open/close/_Unwind_Backtrace/dladdr/__android_log_write; no malloc, no stdio, no locale. Re-entrancy guarded.Wiring —
CMakeLists.txtbuildscrash_handler.cppand explicitly linkslibdl.OboeAudioBridge.csexposesnInstallCrashHandler(UTF-8 string P/Invoke).OsuGameActivity.OnCreatecalls it as the first action afterbase.OnCreate, fully wrapped so a failure here cannot itself contribute to a startup crash:What the next crash will produce
Android/data/sh.ppy.osulazer/files/native_crash.log(also in logcat underosu!crash):That is sufficient to either land a one-line fix in this repo or, if confirmed to be in Veldrid/framework as suspected, point at the exact call site to patch in
winnerspiros/osu-framework.Deliberately not done
No further speculative startup-path edits. With five prior PRs unable to fix the crash from an opaque tombstone, additional guessing is lower-value than a symbolicated backtrace.