facebook / react-native

A framework for building native applications using React
https://reactnative.dev
MIT License
118.55k stars 24.28k forks source link

[0.60.3] App crash on startup when enabling Hermes (enableHermes: true) #25601

Closed bhaskarGyan closed 5 years ago

bhaskarGyan commented 5 years ago

App is crashing when I enable Hermes in android/app/build.gradle. App is working fine with react-native 0.60.3 with enableHermes: false

Error:

07-12 08:06:59.097 20330-20330/com.reactnativememoryprofile E/SoLoader: couldn't find DSO to load: libjscexecutor.so 07-12 08:06:59.123 20330-20345/com.reactnativememoryprofile E/SoLoader: couldn't find DSO to load: libhermes.so 07-12 08:06:59.124 20330-20345/com.reactnativememoryprofile E/AndroidRuntime: FATAL EXCEPTION: create_react_context Process: com.reactnativememoryprofile, PID: 20330 java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libhermes.so at com.facebook.soloader.SoLoader.doLoadLibraryBySoName(SoLoader.java:738) at com.facebook.soloader.SoLoader.loadLibraryBySoName(SoLoader.java:591) at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:529) at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:484) at com.facebook.hermes.reactexecutor.HermesExecutor.<clinit>(HermesExecutor.java:20) at com.facebook.hermes.reactexecutor.HermesExecutorFactory.create(HermesExecutorFactory.java:27) at com.facebook.react.ReactInstanceManager$5.run(ReactInstanceManager.java:949) at java.lang.Thread.run(Thread.java:818)

React Native version: System: OS: macOS 10.14.5 CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz Memory: 373.31 MB / 16.00 GB Shell: 3.2.57 - /bin/bash Binaries: Node: 10.15.1 - /usr/local/bin/node Yarn: 1.13.0 - /usr/local/bin/yarn npm: 6.4.1 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 12.2, macOS 10.14, tvOS 12.2, watchOS 5.2 Android SDK: API Levels: 23, 24, 25, 26, 27, 28 Build Tools: 21.1.2, 23.0.1, 25.0.0, 25.0.1, 25.0.2, 26.0.2, 26.0.3, 27.0.3, 28.0.0, 28.0.2, 28.0.3, 29.0.0 System Images: android-23 | Intel x86 Atom, android-23 | Google APIs Intel x86 Atom, android-23 | Google APIs Intel x86 Atom_64, android-27 | Android TV Intel x86 Atom, android-27 | Intel x86 Atom, android-27 | Intel x86 Atom_64, android-27 | Google APIs Intel x86 Atom, android-27 | Google Play Intel x86 Atom, android-28 | Intel x86 Atom, android-28 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom_64, android-28 | Google Play Intel x86 Atom, android-28 | Google Play Intel x86 Atom_64 Android NDK: 20.0.5594570 IDEs: Android Studio: 3.4 AI-183.6156.11.34.5522156 Xcode: 10.2/10E125 - /usr/bin/xcodebuild npmPackages: react: 16.8.6 => 16.8.6 react-native: ^0.60.3 => 0.60.3 npmGlobalPackages: react-native-cli: 2.0.1 react-native-create-library: 3.1.2 react-native-git-upgrade: 0.2.7 m-c02xf2cejg5h:reactNativeMemoryProfi

Steps To Reproduce

  1. Follow the steps mentioned in hermes
  2. react-native run-android --variant release

Describe what you expected to happen: App should not crash

Snack, code example, or link to a repository:

https://github.com/bhaskarGyan/react-native-memory-profile/tree/bug/rn-0.60.3_hermes

HarshitMadhav commented 5 years ago

@affanhashone but I am using react-native init and I am already using the latest version 0.60.4 for react native. I haven't upgraded react-native version as I am already on latest version of react-native

affanhashone commented 5 years ago

@HarshitMadhav yup, still the build will fail. with latest version till they launch the new version of hermes react native. work around is : to installl a herme-engine as dev dependency, and add hermesCommand: "../node_modules/hermes-engine/%OS-BIN%/hermes" to project.ext.react array

also modify the react.gradle in android folder from the master branch.

HarshitMadhav commented 5 years ago

@affanhashone yes you are right my build failed actually. You mean I will have to install Hermes engine as devdependency from this https://www.npmjs.com/package/hermes-engine? and then add hermesCommand?

affanhashone commented 5 years ago

@HarshitMadhav Yes but install 0.1.0 version not 0.1.1(though you can try

HarshitMadhav commented 5 years ago

@affanhashone I dont know why but I added it as simple dependency instead of devdependency my build is successful and app size is also reduced by more then 9 mb.

HarshitMadhav commented 5 years ago

@affanhashone I tried this new build but its crashing saying com.facebook.jni.CppException: Wrong bytecode version. Expected 59 but got 60

affanhashone commented 5 years ago

https://github.com/facebook/react-native/issues/25572 go through this

HarshitMadhav commented 5 years ago

gone through it but didnt helped me. I am trying after adding hermes engine as dev dependency.

affanhashone commented 5 years ago

https://gist.github.com/zenz/efd1f68ee4099abf77550ac7984df2fd try to update with this react.gradle

HarshitMadhav commented 5 years ago

No, it didnt work either adding it as dev devpendency. Thank you for the help and staying with me. I think I should wait before actually implementing hermes engine.

affanhashone commented 5 years ago

replace yours with this : https://github.com/facebook/react-native/blob/master/react.gradle

HarshitMadhav commented 5 years ago

okay wait I am trying this new solution of yours.

affanhashone commented 5 years ago

@HarshitMadhav Did you Fix it ?

tunegov commented 5 years ago

Just resolved that issue on my side. The problem was when I assemble with buildType "releaseStaging". I added : releaseStagingImplementation files(hermesPath + "hermes-release.aar") near to debugImplementation files(hermesPath + "hermes-debug.aar") releaseImplementation files(hermesPath + "hermes-release.aar")

jinzunyue commented 5 years ago

I solved this by four steps.

  1. copy some code from offical template project.ext.react = [ entryFile: "index.js", enableHermes: false, // clean and rebuild if changing ]

def jscFlavor = 'org.webkit:android-jsc:+'

def enableHermes = project.ext.react.get("enableHermes", false);

if (enableHermes) { def hermesPath = "../../node_modules/hermesvm/android/"; debugImplementation files(hermesPath + "hermes-debug.aar") releaseImplementation files(hermesPath + "hermes-release.aar") } else { implementation jscFlavor }

  1. npm install hermesvm
  2. change enableHermes: false to enableHermes: true
  3. clean project and rebuild,then success

I alse have a question.When set 'enableHermes' to false,that means i don't want to use hermes,i also got the problem.That confused me a lot.

HarshitMadhav commented 5 years ago

@affanhashone no it didnt worked! Got the error cannnot process cant find path for it

affanhashone commented 5 years ago

@HarshitMadhav paste your code here

HarshitMadhav commented 5 years ago

@affanhashone did the same

project.ext.react = [
entryFile: "index.js",
enableHermes: true, // clean and rebuild if changing
hermesCommand: "../node_modules/hermes-engine/%OS-BIN%/hermes"
]
def enableHermes = project.ext.react.get("enableHermes", true);

and also ran clean and rebuild commands and then I generated release apk but it failed with cannot find path in both case adding hermes as dev dependency and adding as a dependency.

lihxhit commented 5 years ago

I, following the guide set enableHermes to true but cant see any global variable named HermesInternal.

did you solve it?

r0b0t3d commented 5 years ago

My working solution (using RN 0.60.4)

  1. Copy react.gradle to android > app
  2. In build.gradle, change
    apply from: "../../node_modules/react-native/react.gradle"

    to

    apply from: "./react.gradle"

    and

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermesvm/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }

    to

    if (enableHermes) {
        def hermesPath = "../../node_modules/hermes-engine/android/";  //  <-- change this
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
  3. Install hermes-engine (0.1.1)
    yarn add -D hermes-engine
  4. Run project in release mode
    react-native run-android --variant release

@HarshitMadhav I got the same error as you were

com.facebook.jni.CppException: Wrong bytecode version. Expected 59 but got 60

In your case, I think you should check step 2 to change hermesPath

HarshitMadhav commented 5 years ago

@r0b0t3d Thanks ! I will try it and let you know.

chubillkelvin commented 5 years ago

@r0b0t3d I tried your method. My app builds normally right now, but when it encounters any screen with a FlatList component, my app crashes automatically.

The error is still

2019-08-07 14:33:11.708 29229-29375/? A/libc: /tmp/hermes/hermes/include/hermes/VM/HandleRootOwner.h:413: hermes::vm::PinnedHermesValue *hermes::vm::GCScope::newHandle(hermes::vm::HermesValue): assertion "getHandleCountDbg() < handlesLimit_ && "Too many handles allocated in GCScope"" failed
r0b0t3d commented 5 years ago

@RageBill In my project, screens with FlatList are working well. Have not encountered your error. FYI, I upgraded from 0.59.10 -> 0.60.4

rizal-azalli commented 5 years ago

My working solution (using RN 0.60.4)

  1. Copy react.gradle to android > app

I got an error if i'm using the react.gradle react-native repo. I change it to used this one

The error probably because the react.gradle from react-native repo is not set for the windows os.

// Set up the call to the compose-source-maps script
                            workingDir(reactRoot)
                            if (Os.isFamily(Os.FAMILY_WINDOWS)) {
                                commandLine("cmd", "/c", *nodeExecutableAndArgs, composeSourceMapsPath, jsPackagerSourceMapFile, jsCompilerSourceMapFile, "-o", jsOutputSourceMapFile)
                            } else {
                                commandLine(*nodeExecutableAndArgs, composeSourceMapsPath, jsPackagerSourceMapFile, jsCompilerSourceMapFile, "-o", jsOutputSourceMapFile)
                            }
narobertson42 commented 5 years ago

I've been able to follow these steps to get split APKs and universal APKs launching correctly for staging and release builds. I have not been able to get it working for .aab bundles. I build the bundle and when I install the application, it results in a hanging white screen on startup. Has anybody come across a similar issue?

SourceCipher commented 5 years ago

If you enable hermes - you will get 2x error couldn't find DSO to load: libhermes.so If you disable hermes - you will get only once couldn't find DSO to load: libhermes.so

So in conclusion you cant disable that nonsense and your app will crash no matter what. Seems like we will have to wait for a year or so until they come up with the proper documentation on how to upgrade to RN 6

rudyryk commented 5 years ago

@SourceCipher And the issue is CLOSED. Boom.

hwde commented 5 years ago

Hmmm, it could be happen by magic, but the error went away ... now I can at least build a .aab for PlayStore which doesn't crash. RN is 60.5 ... and the only thing I am aware that I've changed is in android/build.gradle from 3.4.2 downgrade to 3.4.1:

classpath("com.android.tools.build:gradle:3.4.1")

I assume Android Studio asked me to upgrade it a couple of days ago ... but maybe it is just a magic.

Sam-Martin commented 5 years ago

If like @SourceCipher you're having issues disabling hermes, check out the solution in this thread to add url("$rootDir/../node_modules/jsc-android/dist")

rensamatar commented 5 years ago
maven {
    // Android JSC is installed from npm
    url("$rootDir/../node_modules/jsc-android/dist")
}
gpawlik commented 5 years ago

The solution with installing hermes-engine works, but the issue can also be fixed by adapting the hermesCommand option to the path where hermesvm actually got installed.

In my case instead of a default node_modules/react-native/node_modules/hermesvm it has been installed in node_modules/hermesvm, so adapting the options in following way was enough:

project.ext.react = [
        ...some options...
        enableHermes: true,
        hermesCommand: "../../node_modules/hermesvm/%OS-BIN%/hermes"
]
...
if (enableHermes) {
        def hermesPath = "../../node_modules/hermesvm/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        ...
wynch commented 5 years ago

Thanks @mjmasn for the custom react.gradle to better handle variant builds.

Is there a PR to fix the file to better handle the release -vs- debug build bug related to hermes ? (in my case, I had a missing debugger file for a non-debug build... stacktrace started like this :

java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libhermes-executor-debug.so caused by: dlopen failed: cannot locate symbol "_ZTIN8facebook6hermes8debugger13EventObserverE" referenced by "/data/app/fr.myapp.alpha-1/lib/x86/libhermes-inspector.so"...

SourceCipher commented 5 years ago

Tried the above configurations many times and the app crashes with the same error no matter what. Its a shame as after upgrading to RN 6 it seemed like everything was up to date, no errors nothing all clean and shiny, all compiled and launched but crashing on startup.

I have tried @gpawlik solution and even pointing to both hermes-engine and hermesvm but the same issue.

I kind of want to try and build the new project and start applying my current project settings to see when it crashes, but I rather spend my 12h doing something better ..

EDITED: I just tried creating new react native 6+ project with enabled hermes engine or disabled. Both cases worked fine. I copied every single setting, package, upgraded everything to their versions point to point and still getting the same issue. I give up

varunon9 commented 5 years ago

Using RN 0.60.5 (Ubuntu)- In debug mode (react-native run-android) I was getting following error-

AndroidRuntime: java.lang.UnsatisfiedLinkError: couldn't find DSO to load: libhermes-executor-debug.so

I was using classpath 'com.android.tools.build:gradle:3.4.2' in build.gradle and downgrading it to classpath 'com.android.tools.build:gradle:3.4.1' worked for me. But it's still failing in release mode react-native run-android --variant=release with following error-

* What went wrong:
Execution failed for task ':app:bundleReleaseJsAndAssets'.
> Process 'command '../../node_modules/hermesvm/linux64-bin/hermes'' finished with non-zero exit value 135

I created a brand new react native project using react-native init <ProjectName> and then enabled hermes. It worked for debug mode but got failed for release mode with same error as above :cry:

SourceCipher commented 5 years ago

I just managed to upgrade my entire project to react native "0.60.5". I was so fed up trying to change various settings which never worked so I did everything from scratch.

Basically you have to create the new project using react-native init <ProjectName> and start installing all the libraries you are using and adding their settings. For example, I used facebook login apk and some of the firebase libraries. I installed 1 by 1 and added their corresponding settings. After tweaking couple of things, everything built up and works fine!

By default hermes is disabled and dont even try to enable it :)

hamidfzm commented 5 years ago

Herms is still not working on release variant in react native "0.60.5" on react-native init project. Debug variant is fine.

Devlin556 commented 5 years ago

If you have additional build types those will need to be added too, e.g.

    integrationImplementation files(hermesPath + "hermes-release.aar")
    stagingImplementation files(hermesPath + "hermes-release.aar")

Because we have a few build types, and apart from debug they should all be in release mode, I also had to add some react.gradle fixes. We have a custom react.gradle so this wasn't too much trouble. Basically changing targetName.toLowerCase().contains("release") to !targetName.toLowerCase().contains("debug").

if (!targetName.toLowerCase().contains("debug")) {
    // Can't use ?: since that will also substitute valid empty lists
    hermesFlags = config.hermesFlagsRelease
    if (hermesFlags == null) hermesFlags = ["-O", "-output-source-map"]
} else {
    hermesFlags = config.hermesFlagsDebug
    if (hermesFlags == null) hermesFlags = []
}

and

// Delete the VM related libraries that this build doesn't need.
// The application can manage this manually by setting 'enableVmCleanup: false'
//
// This should really be done by packaging all Hermes releated libs into
// two separate HermesDebug and HermesRelease AARs, but until then we'll
// kludge it by deleting the .so files out of the /transforms/ directory.
def isRelease = !targetName.toLowerCase().contains("debug")

Also added a quick fix for #25609

ant.move(
    file: jsBundleFile,
    tofile: "${jsBundleFile}_temp"
);
commandLine(getHermesCommand(), "-emit-binary", "-out", jsBundleFile, "${jsBundleFile}_temp", *hermesFlags)

Hi! How does implement function work with custom buildTypes? I added implementation for my custom build types e.g: integration (implementIntegration), development (developmentIntegration), but after building, it crashes with error couldn't find DSO to load: libhermes.so. Otherwise cases like releaseIntegration or debugIntegration works fine with hermes. Where is my mistake?

Code

buildTypes {
        debug {
            minifyEnabled enableProguardInReleaseBuilds
            signingConfig signingConfigs.debug
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            applicationIdSuffix ".local"
        }
        development {
            applicationIdSuffix ".dev"
            minifyEnabled enableProguardInReleaseBuilds
            signingConfig signingConfigs.debug
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            matchingFallbacks = ['release', 'debug']
        }
        integration{
            applicationIdSuffix ".staging"
            minifyEnabled enableProguardInReleaseBuilds
            signingConfig signingConfigs.debug
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
            matchingFallbacks = ['release']
        }
        release {
            signingConfig signingConfigs.debug
            minifyEnabled enableProguardInReleaseBuilds
            proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
        }
    }
if (enableHermes) {
      def hermesPath = "../../node_modules/hermesvm/android/";
      debugImplementation files(hermesPath + "hermes-debug.aar")
      developmentImplementation files(hermesPath + "hermes-release.aar")
      integrationImplementation files(hermesPath + "hermes-release.aar")
      releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
      implementation jscFlavor
    }
mjmasn commented 5 years ago

@Devlin556 did you copy react.gradle from node_modules/react-native/react.gradle to android/app/react.gradle?

When you've done that, make the two changes shown above - both involve changing targetName.toLowerCase().contains("release") to !targetName.toLowerCase().contains("debug")

Probably worth running (cd android && ./gradlew clean) afterwards too before trying to build again.

BTW I haven't tried RN 0.61 yet but in my few hours experience with Hermes, my impression was that this isn't really ready for production use, given that it doesn't even work on a fresh 0.60.5 app without multiple workarounds. It's also super slow (maybe 3-5x slowdown) compared to JSC in debug mode with our app and I experienced some crashes. Assuming Facebook are using this internally I'm sure the situation will improve rapidly though.

justincrow commented 5 years ago

I was getting this issue migrating from react-native 0.60.4 to 0.60.5. I deleted the '.gradle' directory under 'android', and re-synced/rebuilt the project in Android Studio and that did the trick for me.

TomBerriot commented 5 years ago

Our app doesn't work in production build with Hermes but works in developement fine, with and without debugging. I hope guides will come out to explain out to get it faster in developement though.

In any case our production app is around 2 MB smaller though it doesn't work for now. ^^

I had to use a polyfill for the Reflect API as our app uses Redux ORM, which uses the Reflect API on web usually.

tmaly1980 commented 5 years ago

I can't figure this out. I've followed most of the advice and this still crashes even when hermes is disabled. Any idea why? Where exactly is this libhermes.so supposed to be?

tmaly1980 commented 5 years ago

If you enable hermes - you will get 2x error couldn't find DSO to load: libhermes.so If you disable hermes - you will get only once couldn't find DSO to load: libhermes.so

So in conclusion you cant disable that nonsense and your app will crash no matter what. Seems like we will have to wait for a year or so until they come up with the proper documentation on how to upgrade to RN 6

@SourceCipher What did you figure out with this? Did you ever get it working?

tmaly1980 commented 5 years ago

OK for me, I had to add jsc to android/build.gradle, because it'll otherwise try to load hermes by default:

maven {
    // Android JSC is installed from npm
    url("$rootDir/../node_modules/jsc-android/dist")
}
SourceCipher commented 5 years ago

@tmaly1980 With that message you quoted, I figured out that the hermes engine wasnt working 😆

Did you managed to upgrade to RN 0.6?

tmaly1980 commented 5 years ago

@SourceCipher Yes, it works, these are the bits from my app/build.gradle

project.ext.react = [
    entryFile: "index.android.js",
    enableHermes: false
]

def enableHermes = project.ext.react.get("enableHermes", false);
def jscFlavor = 'org.webkit:android-jsc:+'
def safeExtGet(prop, fallback) {
    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
}

// ... later on ....

dependencies {
    // ....
    if (enableHermes) {
        def hermesPath = "../../node_modules/hermesvm/android/";
        debugImplementation files(hermesPath + "hermes-debug.aar")
        releaseImplementation files(hermesPath + "hermes-release.aar")
    } else {
        implementation jscFlavor
    }
    // ....
}

After that, though I ran into red screen issues connecting to 10.0.2.2:8081, which I solved by modifying AndroidManifest.xml:

<application
     android:usesCleartextTraffic="true"
     ....
usmansbk commented 5 years ago

This bug is still on 0.60.6, 3 versions later.

8BallBomBom commented 5 years ago

Still an issue on 0.61.0 aswell.

ducanhmai205 commented 5 years ago

0.60.4 still face this issue.

HananeAlSamrout commented 5 years ago

1-upgrade react-native to 0.61 2-enable hermes

project.ext.react = [
    entryFile: "index.js",
    enableHermes: true
]
def enableHermes = project.ext.react.get("enableHermes", true);

3-add in android/app/build.gradle

android {
...
packagingOptions{
         exclude '**/libhermes-inspector.so'
         exclude '**/libhermes-executor-debug.so'
         exclude '**/libjscexecutor.so'
    }
...
}
aliozinan commented 5 years ago

In my case I had "hermes-engine" folder instead of "hermesvm" under node_modules so when I changed the folder name to hermes-engine in the app's build.gradle the error was gone (my RN version is 0.61.0)

on RN 0.61.1 this problem seems resolved so i would suggest upgrading your RN version.