Skip to content

Latest commit

 

History

History
62 lines (44 loc) · 2.68 KB

File metadata and controls

62 lines (44 loc) · 2.68 KB

Android Crash Fix — Perry v0.4.26–v0.4.29

Summary

Android UI apps crashed with SIGSEGV at getLevelInfo+44 when accessing module-level arrays from UI pump tick callbacks. The root cause was the perry-native thread's arena being freed after main() returned.

Root Cause

On Android, Perry's init chain runs on a background thread ("perry-native"):

Kotlin PerryActivity.startNative()
  → Thread { PerryBridge.nativeMain() }
    → main()              // compiled TypeScript entry point
      → _perry_init_labels_ts()   // initializes thresholds[], levels[]
      → App({ ... })              // sets up UI + timer pump
    → main() returns
    → thread exits              ← ARENA DROPPED HERE

After main() returns, the perry-native thread exits. Rust's thread-local storage cleanup runs the arena's Drop, which frees all memory blocks — including module-level arrays (thresholds, levels) that were allocated during init.

The UI thread's 8ms timer pump then calls getLevelInfo(), which dereferences the now-freed array pointers → SIGSEGV.

This never happened on macOS/iOS because App() blocks forever in the event loop — the thread never exits, so the arena is never dropped.

Fix

crates/perry-ui-android/src/lib.rs: After main() returns, park the thread forever instead of letting it exit:

main();
// Park thread — arena holds module-level objects needed by UI thread
loop { std::thread::park(); }

Additional Fixes in v0.4.26–v0.4.29

Version Fix
v0.4.26 Skip strip_duplicate_objects_from_lib on Android — js_nanbox_* symbols were stripped from UI lib while standalone runtime was skipped
v0.4.27 JNI_GetCreatedJavaVMs stub — jni-sys extern ref unsatisfied on Android (no libjvm.so, libnativehelper only at API 31+)
v0.4.28 Module-level arrays with Unknown/Any type loaded as F64 instead of I64 — now arrays/closures/maps/sets always use I64
v0.4.29 Thread-local arena freed after main() returned + -Bsymbolic linker flag to prevent ELF symbol interposition

How to Rebuild for Android

# 1. Ensure perry v0.4.29+ is installed
perry --version  # should show 0.4.29

# 2. Cross-compile the Android UI library (one-time)
ANDROID_NDK_HOME=$HOME/Library/Android/sdk/ndk/28.0.12433566 \
  cargo build --release -p perry-ui-android --target aarch64-linux-android

# 3. Compile your app
ANDROID_NDK_HOME=$HOME/Library/Android/sdk/ndk/28.0.12433566 \
  perry src/main.ts --target android -o android-build/app/src/main/jniLibs/arm64-v8a/libperry_app.so

# 4. Clean Gradle build (important — clears cached .so)
cd android-build && ./gradlew clean assembleDebug