Skip to content

fix: graceful degradation when native libraries are unavailable (Android)#1067

Open
radko93 wants to merge 1 commit intosoftware-mansion:mainfrom
radko93:fix/graceful-degradation-missing-native-libs
Open

fix: graceful degradation when native libraries are unavailable (Android)#1067
radko93 wants to merge 1 commit intosoftware-mansion:mainfrom
radko93:fix/graceful-degradation-missing-native-libs

Conversation

@radko93
Copy link
Copy Markdown
Contributor

@radko93 radko93 commented Apr 9, 2026

Description

On 32-bit Android devices (or devices with 64-bit CPUs running 32-bit userspace), the arm64-v8a native .so files are not found. ETInstaller.init throws RuntimeException wrapping UnsatisfiedLinkError, crashing the app at startup with no consumer-side escape hatch.

This PR adds a fallback TurboModule (ETInstallerUnavailable) whose install() returns false. RnExecutorchPackage returns it only when the native library fails to load, so JS sees a real linked module but JSI bindings are never injected. This preserves the existing linking-error Proxy for genuinely mislinked installs on supported devices.

Unsupported ABI: real module exists → install() returns false → globals not set → isAvailable is false
Supported but mislinked: module is null → existing Proxy throws linking error (unchanged)

No public API break; preserves existing mislink failure behavior. isAvailable is a new additive export.

Introduces a breaking change?

  • No

Type of change

  • Bug fix (change which fixes an issue)

Tested on

  • Android

Testing instructions

  1. Build and run on a 32-bit Android device (e.g. Galaxy A13, Moto G Play 2023)
  2. App should start without crashing
  3. isAvailable should be false
  4. Verify on a supported 64-bit device that everything works as before

Related issues

Fixes #1065

…oid)

On 32-bit Android devices (or devices with 64-bit CPUs running 32-bit
userspace), the arm64-v8a native .so files are not found and ETInstaller
throws RuntimeException wrapping UnsatisfiedLinkError, crashing the app
at startup.

Add ETInstallerUnavailable, a fallback TurboModule whose install()
returns false. RnExecutorchPackage returns it when the native library
fails to load, so JS sees a real linked module but globals are never
injected. This preserves the existing linking-error Proxy for genuinely
mislinked installs on supported devices.

Export isAvailable (based on loadExecutorchModule global presence) so
consumers can check runtime support.

No public API break; preserves existing mislink failure behavior.

Fixes software-mansion#1065
@msluszniak
Copy link
Copy Markdown
Member

Ok, it took us some time to find a suitable device to test these changes, but we will be testing in a while :))

@msluszniak
Copy link
Copy Markdown
Member

Hmm, I turned out that it will be a challenge for us. The motorola that we had is from 2016 with android 7 😅. For now, we don't have any device that has 32-bit arch to test it :/

@radko93
Copy link
Copy Markdown
Contributor Author

radko93 commented Apr 9, 2026

@msluszniak we don't have a device like that either. But a similar solution made crashes disappear at scale. There are also some devices that are 64bit but apparently run or on 32 bit. Try to Google, especially Samsung A13

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

Labels

bug fix PRs that are fixing bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App crashes on 32-bit Android devices — UnsatisfiedLinkError when native .so is missing

2 participants