expo / expo

An open-source framework for making universal native apps with React. Expo runs on Android, iOS, and the web.
https://docs.expo.dev
MIT License
33.71k stars 5.4k forks source link

requestIdleCallback crashes with bridgeless mode on RN 0.75.3 #31564

Open oblador opened 1 month ago

oblador commented 1 month ago

Minimal reproducible example

https://github.com/oblador/expo-requestidlecallback-issue

What platform(s) does this occur on?

Android

Where did you reproduce the issue?

in a development build

Summary

On latest stable react-native (0.75.3) and expo (51.0.32) with new architecture enabled on Android, calling requestIdleCallback() causes the app to crash. This doesn't happen when removing expo or disabling new architecture.

I understand that 51 is built with 0.74 in mind, but it has been publicly stated that it is compatible with 0.75. Also 0.74 does not have requestIdleCallback implemented on bridgeless mode.

Error message:

std::shared_ptr<T> facebook::jsi::Object::getHostObject(Runtime &) const [T = facebook::react::RuntimeSchedulerBinding]: assertion "isHostObject<T>(runtime)" failed

Potentially related: #31559

Environment

  expo-env-info 1.2.0 environment info:
    System:
      OS: macOS 15.0
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 20.11.0 - ~/.asdf/installs/nodejs/20.11.0/bin/node
      Yarn: 3.6.4 - ~/.asdf/installs/nodejs/20.11.0/bin/yarn
      npm: 10.2.4 - ~/.asdf/plugins/nodejs/shims/npm
      Watchman: 2023.03.27.00 - /opt/homebrew/bin/watchman
    Managers:
      CocoaPods: 1.12.1 - /Users/joel/.asdf/shims/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 24.0, iOS 18.0, macOS 15.0, tvOS 18.0, visionOS 2.0, watchOS 11.0
      Android SDK:
        API Levels: 28, 30, 31, 32, 33, 34
        Build Tools: 29.0.2, 30.0.2, 30.0.3, 31.0.0, 32.0.0, 33.0.0, 33.0.1, 34.0.0
        System Images: android-32 | Google APIs ARM 64 v8a, android-33 | Google Play ARM 64 v8a, android-34 | Google APIs ARM 64 v8a
    IDEs:
      Android Studio: 2024.1 AI-241.18034.62.2411.12071903
      Xcode: 16.0/16A242d - /usr/bin/xcodebuild
    npmPackages:
      expo: ^51.0.0 => 51.0.32
      react: 18.3.1 => 18.3.1
      react-native: 0.75.3 => 0.75.3
    Expo Workflow: bare

Expo Doctor Diagnostics

npx expo-doctor@latest
✔ Check Expo config for common issues
✔ Check package.json for common issues
✔ Check for app config fields that may not be synced in a non-CNG project
✔ Check dependencies for packages that should not be installed directly
✔ Check for common project setup issues
✔ Check for issues with metro config
✔ Check if the project meets version requirements for submission to app stores
✔ Check npm/ yarn versions
✖ Check Expo config (app.json/ app.config.js) schema
✔ Check for legacy global CLI installed locally
✖ Check that packages match versions required by installed Expo SDK
✔ Check that native modules do not use incompatible support packages
✔ Check native tooling versions
✔ Check that native modules use compatible support package versions for installed Expo SDK

Detailed check results:

Error: Problem validating fields in /Users/joel/Code/RequestIdleCallbackIssue/app.json. Learn more: https://docs.expo.dev/workflow/configuration/
 • should NOT have additional property 'displayName'.

The following packages should be updated for best compatibility with the installed expo version:
  react@18.3.1 - expected version: 18.2.0
  react-native@0.75.3 - expected version: 0.74.5
  @types/react@18.3.7 - expected version: ~18.2.79
  typescript@5.0.4 - expected version: ~5.3.3
Your project may not work correctly until you install the expected versions of the packages.
Found outdated dependencies
BenIrving commented 2 weeks ago

This appears to crash due to this assert fn call failing

template <typename T>
inline std::shared_ptr<T> Object::getHostObject(Runtime& runtime) const {
  assert(isHostObject<T>(runtime));
  return std::static_pointer_cast<T>(runtime.getHostObject(*this));
}

This is at the top of the end of the call stack initiated by RuntimeSchedulerBinding::getBinding(runtime) inside requestIdleCallback here

If we comment out the assert call, everything appears to work okay. We correctly get the binding and can access the runtimeScheduler and the crash goes away.

@brentvatne could expo be somehow interfering with this runtime scheduler? This is blocking our release of rn75 which is supposedly compatible with sdk 51

expo-bot commented 1 week ago

Thank you for filing this issue! This comment acknowledges we believe this may be a bug and there’s enough information to investigate it. However, we can’t promise any sort of timeline for resolution. We prioritize issues based on severity, breadth of impact, and alignment with our roadmap. If you’d like to help move it more quickly, you can continue to investigate it more deeply and/or you can open a pull request that fixes the cause.

Kudo commented 6 days ago

update for my investigation today: the main difference is whether soloader is enabled and i think that's an issue from react-native core. it could be resolved by 0.76 given all so libs are merged into single libreactnative.so

one workaround is to load libfabricjni.so first

--- a/android/app/src/main/java/com/requestidlecallbackissue/MainApplication.kt
+++ b/android/app/src/main/java/com/requestidlecallbackissue/MainApplication.kt
@@ -39,6 +39,11 @@ class MainApplication : Application(), ReactApplication {
     super.onCreate()
     SoLoader.init(this, false)
     if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
+      // Workaround to `facebook::react::RuntimeSchedulerBinding::getBinding` dynamic_cast error
+      // because of the symbol exists in multiple places.
+      // libfabricjni.so is the correct lib and we try to load it first.
+      System.loadLibrary("fabricjni")
+
       // If you opted-in for the New Architecture, we load the native entry point for this app.
       load()
     }

will update more details and also try whether 0.76 resolved the issue tomorrow

Kudo commented 6 days ago

i can confirm the issue also happens on rnc-cli 0.75 with enabled soloader and all this problem would be resolved from 0.76.

Root cause in details.

Summary

since 0.76 will resolve the problem by the effort of merging solibs, i have no idea whether the workaround could be a formal solution. let me discuss this problem with meta how we resolve the problem on 0.75.