From 60e00d9d96d7b186c1d4c1542caddc1b74eeb3da Mon Sep 17 00:00:00 2001 From: Petter Hesselberg Date: Fri, 6 Sep 2019 00:14:50 -0700 Subject: [PATCH] =?UTF-8?q?Ensure=20SoLoader=20is=20initialized=20before?= =?UTF-8?q?=20attempting=20to=20load=20jscexecutor=20=E2=80=A6=20(#26343)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: This change fixes the issue "[ReactInstanceManagerBuilder.build fails unless SoLoader.init has been called](https://github.com/facebook/react-native/issues/26342)" on Android. The `ReactInstanceManager` constructor calls `initializeSoLoaderIfNecessary`, so the intent is clearly that things should work without an explicit call to `SoLoader.init` on the part of the application. However, with the introduction of Hermes, we have `ReactInstanceManagerBuilder.getDefaultJSExecutorFactory`, which gets called before the `ReactInstanceManager` constructor. It attempts this: SoLoader.loadLibrary("jscexecutor"); This fails with the following stack trace: java.lang.RuntimeException: Unable to start activity ComponentInfo{com.facebook.react.uiapp/com.facebook.react.uiapp.RNTesterActivity}: java.lang.RuntimeException: SoLoader.init() not yet called at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2957) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696) at android.os.Handler.dispatchMessage(Handler.java:105) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6944) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374) Caused by: java.lang.RuntimeException: SoLoader.init() not yet called at com.facebook.soloader.SoLoader.assertInitialized(SoLoader.java:781) at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:505) at com.facebook.soloader.SoLoader.loadLibrary(SoLoader.java:484) at com.facebook.react.ReactInstanceManagerBuilder.getDefaultJSExecutorFactory(ReactInstanceManagerBuilder.java:291) at com.facebook.react.ReactInstanceManagerBuilder.build(ReactInstanceManagerBuilder.java:266) at com.facebook.react.ReactNativeHost.createReactInstanceManager(ReactNativeHost.java:86) at com.facebook.react.ReactNativeHost.getReactInstanceManager(ReactNativeHost.java:38) at com.facebook.react.ReactDelegate.loadApp(ReactDelegate.java:103) at com.facebook.react.ReactActivityDelegate.loadApp(ReactActivityDelegate.java:83) at com.facebook.react.ReactActivityDelegate.onCreate(ReactActivityDelegate.java:78) at com.facebook.react.uiapp.RNTesterActivity$RNTesterActivityDelegate.onCreate(RNTesterActivity.java:40) at com.facebook.react.ReactActivity.onCreate(ReactActivity.java:44) at android.app.Activity.performCreate(Activity.java:7183) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1220) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2910) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3032)  at android.app.ActivityThread.-wrap11(Unknown Source:0)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1696)  at android.os.Handler.dispatchMessage(Handler.java:105)  at android.os.Looper.loop(Looper.java:164)  at android.app.ActivityThread.main(ActivityThread.java:6944)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:327)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1374)  ## Changelog [Android] [Fixed] - Don't crash ReactInstanceManagerBuilder.build even if SoLoader has not been explicitly initialized Pull Request resolved: https://github.com/facebook/react-native/pull/26343 Test Plan: To demonstrate the defect, remove the call to `SoLoader.init` from `RNTester.onCreate` and run the app. To demonstrate the fix, apply this PR, which does in fact also remove the call to `SoLoader.init` Differential Revision: D17223701 Pulled By: mdvacca fbshipit-source-id: c508ab52bd3fefe8a946ebab7b2906a5d8c21e0f --- .../com/facebook/react/uiapp/RNTesterApplication.java | 1 - .../java/com/facebook/react/ReactInstanceManager.java | 2 +- .../com/facebook/react/ReactInstanceManagerBuilder.java | 9 +++++++-- 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java b/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java index e91eac877f2..f5accca2c82 100644 --- a/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java +++ b/RNTester/android/app/src/main/java/com/facebook/react/uiapp/RNTesterApplication.java @@ -47,7 +47,6 @@ public class RNTesterApplication extends Application implements ReactApplication public void onCreate() { ReactFontManager.getInstance().addCustomFont(this, "Rubik", R.font.rubik); super.onCreate(); - SoLoader.init(this, /* native exopackage */ false); initializeFlipper(this); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 6f2338c7978..2c8b5eea7e4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -317,7 +317,7 @@ public class ReactInstanceManager { return new ArrayList<>(mPackages); } - private static void initializeSoLoaderIfNecessary(Context applicationContext) { + static void initializeSoLoaderIfNecessary(Context applicationContext) { // Call SoLoader.initialize here, this is required for apps that does not use exopackage and // does not use SoLoader for loading other native code except from the one used by React Native // This way we don't need to require others to have additional initialization code and to diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java index e58b8cc4550..04b0d519521 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java @@ -5,10 +5,13 @@ package com.facebook.react; +import static com.facebook.react.ReactInstanceManager.initializeSoLoaderIfNecessary; import static com.facebook.react.modules.systeminfo.AndroidInfoHelpers.getFriendlyDeviceName; import android.app.Activity; import android.app.Application; +import android.content.Context; + import androidx.annotation.Nullable; import com.facebook.hermes.reactexecutor.HermesExecutorFactory; import com.facebook.infer.annotation.Assertions; @@ -254,6 +257,7 @@ public class ReactInstanceManagerBuilder { } // We use the name of the device and the app for debugging & metrics + //noinspection ConstantConditions String appName = mApplication.getPackageName(); String deviceName = getFriendlyDeviceName(); @@ -262,7 +266,7 @@ public class ReactInstanceManagerBuilder { mCurrentActivity, mDefaultHardwareBackBtnHandler, mJavaScriptExecutorFactory == null - ? getDefaultJSExecutorFactory(appName, deviceName) + ? getDefaultJSExecutorFactory(appName, deviceName, mApplication.getApplicationContext()) : mJavaScriptExecutorFactory, (mJSBundleLoader == null && mJSBundleAssetUrl != null) ? JSBundleLoader.createAssetLoader( @@ -284,9 +288,10 @@ public class ReactInstanceManagerBuilder { mCustomPackagerCommandHandlers); } - private JavaScriptExecutorFactory getDefaultJSExecutorFactory(String appName, String deviceName) { + private JavaScriptExecutorFactory getDefaultJSExecutorFactory(String appName, String deviceName, Context applicationContext) { try { // If JSC is included, use it as normal + initializeSoLoaderIfNecessary(applicationContext); SoLoader.loadLibrary("jscexecutor"); return new JSCExecutorFactory(appName, deviceName); } catch (UnsatisfiedLinkError jscE) {