Skip to content

Resolve the loaded native crash handler and contain startup failures - #297

Merged
melekr merged 9 commits into
masterfrom
android/native_startup
Aug 21, 2026
Merged

Resolve the loaded native crash handler and contain startup failures#297
melekr merged 9 commits into
masterfrom
android/native_startup

Conversation

@melekr

@melekr melekr commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Improve Android native crash-handler startup for Unity applications where Backtrace native library is loaded directly from an APK or an Android App Bundle ABI split.

The SDK now resolves the native library selected by Android's linker, while retaining extracted-library, installed split, and base-APK fallbacks.

This PR also incorporates the runtime attribute-containment changes from #300 and strengthens native initialization, JNI cleanup, ANR handling, shutdown, child-process environment construction, and crash-handler failure handling.

Docs

saucelabs/sauce-docs#3640

Problem

The previous Unity implementation constructed the crash-handler library path from the base APK, nativeLibraryDir, and a device-preferred ABI.

That can produce an incorrect path when:

  • Android loads native libraries directly from an APK
  • an Android App Bundle stores the library in an ABI configuration split
  • a 32-bit Unity process runs on a 64-bit-capable device
  • nativeLibraryDir or Unity activity metadata is unavailable
  • inherited child-process environment variables already contain SDK-reserved keys.

The native bridge also had several lifecycle and interop risks:

  • native void exports were declared as returning bool
  • JNI local references were retained longer than necessary
  • a native bridge could return false after partially initializing native state
  • optional native attribute failures could escape into the Unity application or interrupt later attribute updates
  • ANR and shutdown failures could prevent later cleanup stages.

What changed

Native-library resolution

  • Resolve the loaded libbacktrace-native.so path through Android's native linker.
  • Treat a structurally valid linker-selected path as authoritative.
  • Fall back to an existing extracted native library.
  • Resolve installed ABI configuration splits from ApplicationInfo metadata.
  • Fall back to the historical base-APK path when required.
  • Compare split candidates globally and reject ambiguous matches.
  • Avoid opening or parsing APK archive contents.
  • Keep optional linker, filesystem, and package-metadata discovery nonfatal.

Running-process ABI

  • Resolve the ABI of the running Unity process rather than using the device's first preferred ABI.
  • Use the same process ABI for native-library selection and the device.abi report attribute.
  • Preserve the existing unsupported 32-bit x86 native-capture policy.
  • Continue managed reporting when native capture is unavailable.

Native initialization and JNI

  • Correct P/Invoke return types, Boolean marshalling, and calling conventions.
  • Delete JNI local references deterministically.
  • Attempt all JNI cleanup operations even if one deletion fails.
  • Roll back partial native state when:
    • the native bridge completes and returns false;
    • managed post-initialization setup fails;
    • JNI cleanup fails after native activation.
  • Keep rollback failures and rollback diagnostics nonfatal.
  • Preserve the original initialization outcome when rollback also fails.

Dynamic native attributes

  • Retain attributes in the managed client before optional native propagation.
  • Prevent native attribute failures from escaping into the Unity game.
  • Continue processing later SetAttributes(...) entries after one native write fails.
  • Keep native capture enabled after an isolated attribute failure.
  • Emit sanitized diagnostics without logging attribute keys, values, exception messages, paths, or submission URLs.

ANR and shutdown lifecycle

  • Contain JVM attach, detach, attribute, and dump failures in the ANR worker.
  • Retry transient attachment failures.
  • Restore error.type=Crash after every ANR dump attempt.
  • Run native disable and Java watcher cleanup stages independently.
  • Clear watcher references during shutdown.
  • Keep shutdown failures nonfatal.

Crash-handler child process

  • Reject missing or blank native-library paths.
  • Contain native-library loading and native-dispatch failures.
  • Exit nonzero when the child cannot process a crash.
  • Avoid logging handler arguments, submission URLs, application attributes, attachment paths, or resolved native-library paths.

Child-process environment

  • Preserve unrelated inherited environment variables.
  • Replace SDK-reserved variables rather than emitting duplicate keys:
    • CLASSPATH
    • BACKTRACE_UNITY_CRASH_HANDLER
    • LD_LIBRARY_PATH
    • ANDROID_DATA

CI and packaging

  • Build Android players on the supported baseline and newer Unity versions.
  • Build an ARM64 IL2CPP App Bundle under Unity 6.
  • Verify that the App Bundle contains:
    • libil2cpp.so;
    • libbacktrace-native.so;
    • the Java BacktraceCrashHandler class in a base-module DEX file.
  • Validate the packaged macOS framework layout.
  • Expand lifecycle, resolver, ABI, JNI, attribute, ANR, shutdown, and child-process tests.

Compatibility

  • No public API removals.
  • No required consumer code changes.
  • No serialized configuration migration.
  • Traditional APK installations remain supported.
  • Android App Bundle and split-APK installations are supported.
  • Managed Unity reporting remains available when optional native setup fails.
  • Dynamic attributes remain available to managed reports when optional native propagation fails.
  • The minimum supported Android API and existing 32-bit x86 policy are unchanged.

C.I

  • Unity 2021.3 EditMode
  • Unity 2021.3 PlayMode
  • Unity 2022.3 EditMode
  • Unity 2022.3 PlayMode
  • Unity 6000.3 EditMode
  • Unity 6000.3 PlayMode
  • Unity 2019.4 Android player build
  • Unity 2022.3 Android player build
  • Unity 6000.3 ARM64 IL2CPP App Bundle build

@melekr melekr self-assigned this Aug 18, 2026
@melekr melekr changed the title Android/native startup Android native startup Aug 18, 2026
@melekr melekr changed the title Android native startup Resolve Unity native crash handler from the loaded library Aug 18, 2026
melekr added 4 commits August 18, 2026 17:30
* fix(android): report the ABI of the running process as device.abi

* feat(android): select the extracted-library directory by process ABI

* test(android): pin the native interop signatures in in-editor CI

* fix(android): query the linker first and contain metadata and ANR failures

* ci: build Android players on Unity 2022.3 and 6000.3

* ci: provide the synthetic build project with a registered scene
* fix(android): make native library fallback resolution fail-safe

- Treat filesystem, parent-directory, and system-library-path discovery as optional enrichment so failures cannot block linker or installed-package resolution.

- Require an exact process-ABI directory match when the ABI is known and reject ambiguous candidates deterministically.

* fix(android): roll back incomplete native initialization

- Track native backend activation before JNI cleanup and disable the backend when attribute setup or cleanup fails after initialization.
- Attempt every local-reference deletion, preserve the original setup failure, and contain rollback diagnostics.

* fix(android): contain ANR JNI lifecycle failures

- Contain watchdog attach, detach, dump, and attribute failures without escaping the worker thread.

- Retry transient attachment failures and always restore error.type to Crash after a hang-report attempt.

* fix(android): make native shutdown failure-safe

- Clear native and watcher state before cleanup, then run every shutdown stage independently.

- Keep native-disable, watcher-stop, watcher-dispose, and diagnostic failures nonfatal.

* ci(android): validate IL2CPP app bundle packaging

- Compile the SDK from Assets in every Android build lane while importing only the Editor, Runtime, and Android package content.
- Add a Unity 6 ARM64 IL2CPP App Bundle build, verify the required native libraries are packaged, and identify the platform and Unity version in job names.
* fix(native): handle dynamic attribute update failures

* fix(android): continue after linker path lookup failures

* feat(android): update NativeClient NativeAttributeLifecycle

* fix(android): roll back partial native initialization

- mark native bridge completion before JNI cleanup
- roll back partial native state when initialization returns false
- contain rollback and diagnostic failures
- cover pre-bridge rejection and false-result rollback

* test(android): exercise OOM attribute continuation in editor

- add an instance-scoped native attribute writer for deterministic tests
- compile the Android client test path in ordinary Editor lanes without JNI
- verify OnOOM attempts the timestamp after the first native write fails
- assert sanitized failure diagnostics

* ci(android): verify Java crash handler in app bundles

- inspect every base DEX entry in the generated App Bundle
- require the BacktraceCrashHandler class descriptor
- report missing DEX files and missing handler packaging clearly
- Remove empty EditMode lanes that have no corresponding test assembly.
- Validate NUnit results and require the critical Android lifecycle tests.
- Cover missing, malformed, empty, failed, and incomplete test results.
@melekr melekr changed the title Resolve Unity native crash handler from the loaded library Resolve the loaded native crash handler and contain startup failures Aug 20, 2026
@melekr
melekr requested a review from KishanPRao August 21, 2026 19:05
@melekr
melekr marked this pull request as ready for review August 21, 2026 19:05
@melekr
melekr merged commit 6e5a4aa into master Aug 21, 2026
14 checks passed
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.

1 participant