Summary: This feature is not necessary any longer with Fast Refresh enabled by default.
Reviewed By: gaearon
Differential Revision: D17156607
fbshipit-source-id: 2396a86d192c6b5d90cbed9cefbf13367dd6b699
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
Summary:
This ressurects D14994945 and fixes the following extra issues:
1. Source map not being accounted for after reloads
2. Breakpoints being resent before Hermes is ready for them
3. Connection being dropped when reloading at inopportune times
This hopefully fixes the issue of having to close and re-open the debugger if
it's attached when reloading.
Reviewed By: sahrens
Differential Revision: D17100911
fbshipit-source-id: df988e7bb532170f5add47b9e49cd7c8ddf67b43
Summary: Fixes the crash when calling setCameraDistance with NaN on Android Q.
Reviewed By: JoshuaGross, mdvacca
Differential Revision: D17170045
fbshipit-source-id: 386f969e70c56bca6ae5b8ffead62453ebb72857
Summary: This diff migrates `FbReactTTRCStepRenderFlagManager` to use the generated `TTRCStepRenderFlagManagerDelegate` for setting its properties. A bit more work was required to migrate this view manager since it doesn't extend `BaseViewManager`, so I had to add an adapter which made it possible to pass an instance of `FbReactTTRCStepRenderFlagManager` to `TTRCStepRenderFlagManagerDelegate`.
Reviewed By: mdvacca
Differential Revision: D16984172
fbshipit-source-id: 7bf8c1342435c4e615eb9e7ca711f53c63ed3438
Summary:
Our JS codegen assumes that all Android view managers extend `BaseViewManager` which allows generated delegates to set base view props using `BaseViewManagerDelegate`, see and example of the generated delegate for `FbReactTTRCStepRenderFlagManager`:
```
public class TTRCStepRenderFlagManagerDelegate<T extends View, U extends BaseViewManager<T, ? extends LayoutShadowNode> & TTRCStepRenderFlagManagerInterface<T>>{
public TTRCStepRenderFlagManagerDelegate(U viewManager) {
super(viewManager);
}
Override
public void setProperty(T view, String propName, Nullable Object value) {
switch (propName) {
case "traceId":
mViewManager.setTraceId(view, value == null ? null : (String) value);
break;
case "stepName":
mViewManager.setStepName(view, value == null ? null : (String) value);
break;
default:
super.setProperty(view, propName, value);
}
}
}
```
The problem is that `FbReactTTRCStepRenderFlagManager` doesn't extend `BaseViewManager`, but `ViewManager`, which means that we cannot use it with the generated delegate. We cannot use `ViewManager` instead of `BaseViewManager` in our JS codegen either, otherwise we will not be able to set base view props.
This diff makes it possible for delegates generated by JS to be used by Android view managers that do not extend `BaseViewManager`. By having a `BaseViewManagerInterface` we will be able to introduce a no-op base view manager implementation and wrap our original view manager in it so that we can pass as a constructor parameter to `BaseViewManagerDelegate`.
See an example of this approach for `FbReactTTRCStepRenderFlagManager`:
```
public class FbReactTTRCStepRenderFlagManager extends ViewManager<FbReactTTRCStepRenderFlag, ReactShadowNodeImpl> implements TTRCStepRenderFlagManagerInterface<FbReactTTRCStepRenderFlag> {
private final ViewManagerDelegate<FbReactTTRCStepRenderFlag> mDelegate;
public FbReactTTRCStepRenderFlagManager() {
mDelegate = new TTRCStepRenderFlagManagerDelegate<>(new ViewManagerWrapper(this));
}
...
private static class ViewManagerWrapper extends BaseViewManagerAdapter<FbReactTTRCStepRenderFlag> implements TTRCStepRenderFlagManagerInterface<FbReactTTRCStepRenderFlag> {
private final TTRCStepRenderFlagManagerInterface<FbReactTTRCStepRenderFlag> mViewManager;
private FbReactTTRCStepRenderFlagManagerAdapter(TTRCStepRenderFlagManagerInterface<FbReactTTRCStepRenderFlag> viewManager) {
mViewManager = viewManager;
}
Override
public void setTraceId(FbReactTTRCStepRenderFlag view, Nullable String traceId) {
mViewManager.setTraceId(view, traceId);
}
Override
public void setStepName(FbReactTTRCStepRenderFlag view, Nullable String stepName) {
mViewManager.setStepName(view, stepName);
}
}
}
```
Reviewed By: mdvacca
Differential Revision: D16984121
fbshipit-source-id: ea2761dda68a96ff3ba6ac64153bc4e56e396774
Summary:
We probably don't always need to crash in these cases.
This should replace all prod/dev crashes with logged SoftExceptions.
Note that this is currently only used for Fabric.
Changelog:
[Internal]
Reviewed By: mdvacca
Differential Revision: D17170459
fbshipit-source-id: 70757ae88deb8c893b36971d879174e25a194fb9
Summary:
## Summary
When an exception is raised by Java in a synchronous call from JS to Java, the Java portion of the stack trace is simply ignored when the exception is forwarded to JS. This problem doesn't exist for async calls. I did some digging to figure out why this works with async calls, but not sync calls, to get to the bottom of T52585087.
In T52585087, `TurboModuleRegistry.get<Spec>('I18nAssets')` fails because of a `NullPointerException` in Java. However, since there's no stack trace associated with the `NullPointerException`, it's hard to diagnose the problem.
## Asynchronous calls
ReactNative's NativeModules thread is a background thread on which we schedule asynchronous NativeModule method invocations. We spawn our background threads in Java using the [`MessageQueueThreadImpl`](https://fburl.com/diffusion/u0vdm5k3). Each thread is associated with a queue on which you can schedule some work. These `MessageQueueThread`s have a [C++ API](https://fburl.com/diffusion/596740d8) that we can use to schedule some work from C++.
NativeModule method invocations in JS produce a C++/Java boundry, because our JS executes C++, which executes the Java NativeModule method. But since the method is asynchronous, instead of invoking it immediately, we wrap it in a C++ lambda and use the C++ API of `MessageQueueThread` to schedule it to be invoked later. Therefore, when it actually invokes, we'll get Java invoking C++, which invokes Java.
When the NativeModule method (implemented in Java) throws an exception, fbjni will convert that exception into a `jni::JniException` and start unwinding the C++ stack. Eventually, this exception will reach the outermost Java/C++ boundry. Typically, at this point, the program would crash, but because we used fbjni to register all our native functions, our `jni::JniException` will automatically be converted into a regular Java exception. This exception will be caught by MessageQueueThreadHandler [here](https://fburl.com/diffusion/c4thoca7), and handled using our ExceptionHandler NativeModule.
## Synchronous calls
In synchronous execution, JS uses a `JSI::HostObject` to call the Java method directly. If the Java method throws an error, because we're using fbjni, that Java exception will be converted to a `jni::JniException` object, which will contain the stack tract of the Java object. However, from what I could gather, Hermes doesn't know about `jni::JniException`. So, simply ignore the stack trace associated with the Java exception, understanding only the exception message. Hence, all synchronous calls into Java only display the JS stack trace. What we really want is to build an platform-agnostic abstraction that understands `jni::JniException` (and whatever its analogue is in iOS, if any) and use that to bridge between Native and JS.
## Temporary Solution
We know that when NativeModules are created, we do a synchronous call from JS to C++ to Java. This synchronous call happens when you do a property access on the `NativeModules` object. Therefore, at the very least, to get to the bottom of T52585087, we could log all exceptions that are thrown whenever a NativeModule is created. This should help us get to the bottom of T52585087.
Reviewed By: mdvacca
Differential Revision: D17126667
fbshipit-source-id: a6fb27aaea094b9559939ddcc260d3a2c6e71492
Summary:
We added the accessibilityState property as a more semantically rich way for components to describe information about their state to accessibility services. This PR removes the old accessibilityStates property.
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
## Changelog
[General] [Change] - Remove accessibilityStates property.
Pull Request resolved: https://github.com/facebook/react-native/pull/26168
Test Plan: Ensure that RNTester accessibility examples function properly on both iOS and Android.
Differential Revision: D17152891
Pulled By: cpojer
fbshipit-source-id: d71d3cf0f2e0846979d2ba104b6c69e4e5725252
Summary: The progress bar on Android was disabled in D5329011 because of T19653381, but was never enabled again. I spent some time trying to reproduce the issue of the bundle being stuck while loading, but didn't succeed. So let's enable the progress bar and monitor whether people would start seeing this bug again.
Reviewed By: cpojer
Differential Revision: D17148134
fbshipit-source-id: 5130b809460bc743d26a6e88961f81061089fe1d
Summary: Prior to Android P things like setScaleX() allowed passing float values that were bogus such as Float.NaN. If the app is targeting Android P or later then passing these values will result in an exception being thrown. Since JS might still send Float.NaN, we want to keep the code backward compatible and continue using the fallback value if an invalid float is passed. `sanitizeFloatPropertyValue` is an exact copy of the private method with the same name in `android.view.View.java`.
Reviewed By: cpojer
Differential Revision: D17153279
fbshipit-source-id: 036acc4baa6f0b7f206488991b428a84374fa453
Summary:
Android implementation of the Appearance native module. Exposes the user's preferred color scheme: "dark" for Night theme ON, "light" for Night theme OFF.
Emits a `appearanceChanged` event when the current uiMode configuration changes.
To make your app handle Night mode changes, make sure to do the following:
* Declare your Activity can handle uiMode configuration changes (https://developer.android.com/preview/features/darktheme#java):
```
android:configChanges="uiMode"
```
* Make sure to pass the configuration changed activity lifecycle callback from your ReactActivity:
```
Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged();
if (mReactInstanceManager != null) {
mReactInstanceManager.onConfigurationChanged(newConfig);
}
}
```
### RNTester
Adds the AppearanceExample to RNTester on Android.
Changelog:
[Android][Added] - New Appearance module exposes the user's current Night theme preference
Reviewed By: makovkastar
Differential Revision: D16942161
fbshipit-source-id: d24a8ff800a1c5f70f4efdec6891396c2078067e
Summary: Support existing, backwards-compatible AndroidTextInput component for minimal support of TextInput on Android.
Reviewed By: shergin, mdvacca
Differential Revision: D17086758
fbshipit-source-id: 25726f22229e0d5dfe96eb36b386a5317601283d
Summary: Support for `sendAccessibilityEvent` in the FabricUIManager.
Reviewed By: shergin
Differential Revision: D17142507
fbshipit-source-id: 5c131d7caa1e4189fd41ecfb558d0027394b6a15
Summary:
The purpose of `EventBeat` is handling an asynchronous callback to itself which is being delivered on some different thread. That brings a challenge of ensuring that the `EventBeat` object stays valid during the timeframe of callback execution. The concept of Owner helps with that.
The owner is a shared pointer that retains (probably indirectly) the `EventBeat` object. To ensure the correctness of the call, `EventBeat` retains the owner (practically creating a retain cycle) during executing the callback. In case if the pointer to the owner already null, `EventBeat` skips executing the callback.
It's impossible to retain itself directly or refer to the shared pointer to itself from a constructor. `OwnerBox` is designed to work around this issue; it allows to store the pointer later, right after the creation of some other object that owns an `EventBeat`.
Reviewed By: JoshuaGross
Differential Revision: D17128549
fbshipit-source-id: 7ed34fd865430975157fd362f51c4a3d64214430
Summary: This diff removes the 'RCT' prefix (if it's present) from the names of the generated Java classes. The motivation is that we don't want to have any Java files having this prefix in the RN Android codebase.
Reviewed By: JoshuaGross
Differential Revision: D17123804
fbshipit-source-id: 31905d3141e0f58ea47cdbdb0cf77d2d105de9a9
Summary: This diff checks in the OSS view manager interfaces and delegates generated by the JS codegen. This is a temporary workaround since we don't have the JS codegen running in open source.
Reviewed By: fkgozali
Differential Revision: D17104816
fbshipit-source-id: 848afc081785c9a78891d3dc0740ebe858eb8891
Summary:
The commit and batch points are just showing up as points in scuba relativity which isn't very useful - we want to know how long they take as well, so make them ranges.
Also adds view creation and update counts as annotations which can be handy for debugging regressions.
Reviewed By: JoshuaGross, axe-fb
Differential Revision: D17083058
fbshipit-source-id: dd29d12731734252930c9a4424bddbb98a8acccf
Summary:
We noticed a repro-able crash in Ride in T52804960 on Android Q due to NaN being passed into setCameraDistance
on View
see Oleg's related post: https://fb.workplace.com/groups/rn.support/permalink/2682537011794897/
It looks like a generic fix or wrapper around View setCameraDistance might be planned in T48580247
But in the meantime, it kind of maybe seems reasonable-ish to say, ~~if the value of an input node is NaN, don't use it in the math for this node?~~ if a one of the inputs for this node evaluates to NaN, update that input node first? But I'm not super familiar with the Animations library so maybe that's not a good idea, idk.
From what I can tell in our specific error, it's coming from an InterpolatedNode A based off an AdditionNode B which tried to add a ValueNode C + a InterpolatedNode D, but D had only just been created and not had it's first update, so it's value was NaN, and so when B runs it's update value of C + NaN means B's new values is also NaN, and A's subsequent update based on that now comes out to NaN. Atleast that's what it seems like based on Log statements.
Reviewed By: olegbl
Differential Revision: D16960177
fbshipit-source-id: 99c8ca35be4b5e99f7c21db6733ebd622ae39d07
Summary:
After some thought, we decided we don't need the flexibility of
separate horizontal and vertical props - it would be much nicer
to just have a single prop for the edge length and then the native
code can enable the booleans as appropriate.
Original PR: https://github.com/facebook/react-native/pull/26163
Original commit changeset: f72a9a890d90
Reviewed By: TheSavior
Differential Revision: D16997468
fbshipit-source-id: 7973262287a7ec2cee5957f8dc1806a0f28c1432
Summary: [Android] [Fixed] - Make sure the default accessibility hint is read for buttons on Android.
Reviewed By: PeteTheHeat
Differential Revision: D16974987
fbshipit-source-id: e7b932041f82d41271d9393e651967789c05f38a
Summary: When debugging supporting a Fabric component, a redbox was being shown without a title which resulted in an infinite redbox loop, followed by OOM. That isn't helpful so we just safely work around the null title while indicating what happened to aid in debugging.
Reviewed By: lunaleaps
Differential Revision: D16921053
fbshipit-source-id: df1f4a691df0c10de53c91e4a9356a04a9005a97
Summary: This was an experiment to patch individual deltas in development instead of reloading the whole JS bundle. With improvements such as Fast Refresh that reduces the need for reloads and bundle splitting that reduces the number of modules and memory by 10x, we won't be needing this complex optimization that we never properly made work. This diff removes that code and I will be removing the JS side of things in Metro in a follow-up diff.
Reviewed By: fkgozali
Differential Revision: D16832709
fbshipit-source-id: 46596a3126d52d7d74f4b9ffc9a6ee9d82ec9522
Summary:
There have been multiple complaints about combining RN with various
other FB libraries, including Litho and Flipper, because of bundled dependencies
that can't be deduplicated by Gradle.
This is one of three current conflicts:
1) Proguard annotations (this PR)
2) Yoga
3) fbjni
While the Yoga group name doesn't make a massive amount of sense
it was the easiest existing package to use and since we don't
have a better namespace for this, we might as well use this.
A similar change to Litho is landing right now.
## Changelog
[Android] [Changed] - Use centralized package for DoNotStrip annotation
Pull Request resolved: https://github.com/facebook/react-native/pull/26069
Test Plan:
```
yarn
./gradlew :RNTester:android:app:assembleDebug
```
Reviewed By: cpojer
Differential Revision: D16827430
Pulled By: passy
fbshipit-source-id: 87542b5422fee598d8e635651441f0ecd42eb9d7
Summary: The OnLoad.cpp file is needed since it actually registers the jni functions, it wasn't included in the build so it wasn't working correctly.
Reviewed By: jbower-fb
Differential Revision: D16826230
fbshipit-source-id: 0243e456c4015879d17650737a6a27a58a3d0d9a
Summary: This diff adds a feature flag which must be enabled if view managers should be allowed to use a delegate for setting their properties.
Reviewed By: mdvacca
Differential Revision: D16762876
fbshipit-source-id: ae3466d7f02ed02f203dbb79f5e0843e6d9fdd45
Summary: ModuleRegistryBuilder does as assertion to verify that all `cxxModules` are instances of `CxxModuleWrapperBase::javaStaticClass()`. This assertion is causing the crash in T48554656. Since we don't know which NativeModule is causing this problem, it's difficult to get to the bottom of this. So, for now, I'm improving the assertion message in the hopes that it helps us get to the bottom of this issue.
Reviewed By: mdvacca
Differential Revision: D16774711
fbshipit-source-id: 82318b8ff5ab735ae642da81777c1b5588e8a483
Summary:
This diff introduces an interface `ViewManagerDelegate` and its base implementation `BaseViewManagerDelegate`, which is used as a parent class for all view manager delegates generated by the JS codegen. Before the changes in this diff, generated delegates didn't support setting the base view properties such as background color, rotation, opacity, etc. Now it's possible to do by using `BaseViewManagerDelegate.setProperty(...)`, and since all generated delegates extend BaseViewManagerDelegate, they can just call `super.setProperty(...)` for properties they don't want to handle.
This diff also introduced a new method `ViewManager.getDelegate()`. This will allow view managers to return an instance of the delegate generated by JS and ensure that the view properties are set in a type-safe manner. If this method returns null (it does by default), we fall back to the default implementation of setting view properties using Java-generated `$$PropsSetter`
classes.
This is an example of an interface class generated by JS:
```
public interface RCTAxialGradientViewViewManagerInterface<T extends View> {
void setColors(T view, Nullable ReadableArray value);
void setLocations(T view, Nullable ReadableArray value);
void setEndX(T view, Float value);
void setEndY(T view, Float value);
void setStartX(T view, Float value);
void setStartY(T view, Float value);
}
```
This is an example of a delegate class generated by JS:
```
public class RCTAxialGradientViewManagerDelegate<T extends View, U extends BaseViewManager<T, ? extends LayoutShadowNode> & RCTAxialGradientViewManagerInterface<T>> extends BaseViewManagerDelegate<T, U> {
public RCTAxialGradientViewManagerDelegate(U viewManager) {
super(viewManager);
}
Override
public void setProperty(T view, String propName, Nullable Object value) {
switch (propName) {
case "colors":
mViewManager.setColors(view, (ReadableArray) value);
break;
case "locations":
mViewManager.setLocations(view, (ReadableArray) value);
break;
case "endX":
mViewManager.setEndX(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "endY":
mViewManager.setEndY(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "startX":
mViewManager.setStartX(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
case "startY":
mViewManager.setStartY(view, value == null ? Float.NaN : ((Double) value).floatValue());
break;
default:
super.setProperty(view, propName, value);
}
}
}
```
NOTE: What if a view manager, for instance ReactAxialGradientManager, wanted to add support for the borderRadius prop? In the old Java codegen, it would just need to create a method and annotate it with ReactProp (name = ViewProps.BORDER_RADIUS) and $$PropsSetter would call this method when a property with this name must be set. With the new JS codegen, borderRadius is a part of the basic view props, so setBorderRadius is not generated as a part of the ViewManagerInterface, so it’s not possible to set this value. I see two options: 1) add a method boolean setProperty (String propName, Object value) and let the view manager handle it in a non-type safe way (return true if it’s been handled). 2) Generate BaseViewManagerInterface which will include all basic view props and make BaseViewManager implement this interface, leaving all methods empty so that it stays compatible with the current implementation. Override these methods in a view manager that needs to handle a specific property in a custom way (so we would override setBorderRadius in ReactAxialGradientManager).
Reviewed By: mdvacca
Differential Revision: D16667686
fbshipit-source-id: 06a15a92f8af55640b7a53c5a34f40366d1be2a8
Summary:
Changing showSoftKeyboard and hideSoftKeyboard to be protected, as we need this change for an internal control that extends ReactEditText.
## Changelog
[Android] [Changed] - part of our react native platform, we have a control that extends ReactEditText and we need to be able to override these 2 methods.
Pull Request resolved: https://github.com/facebook/react-native/pull/25964
Test Plan: The change has been in Microsoft's branch of RN for almost 2 years, and since it's a relatively small change we've done a quick sanity check in RNTester prior to this PR, making sure the TextInput page loads fine and it's functional.
Differential Revision: D16686878
Pulled By: cpojer
fbshipit-source-id: 63035ee9c58e93bc0fa40e5bec318df05322c6c5
Summary: Some surfaces throw ConcurrentModificationException when logging detailed perf for Fabric. I've refactored the ReactMarker class to use a threadsafe ArrayList and removed synchronization, which is safer and should improve perf everywhere the markers are used, even if there are zero listeners.
Reviewed By: mdvacca
Differential Revision: D16656139
fbshipit-source-id: 34572f9ad19028a273e0837b0b895c5e8a47976a
Summary:
## The Problem
1. `CatalystInstanceImpl` indirectly holds on to the `jsi::Runtime`. When you destroy `CatalystInstanceImpl`, you destroy the `jsi::Runtime`. As a part of reloading React Native, we destroy and re-create `CatalystInstanceImpl`, which destroys and re-creates the `jsi::Runtime`.
2. When JS passes in a callback to a TurboModule method, we take that callback (a `jsi::Function`) and wrap it in a Java `Callback` (implemented by `JCxxCallbackImpl`). This Java `Callback`, when executed, schedules the `jsi::Function` to be invoked on a Java thread at a later point in time. **Note:** The Java NativeModule can hold on to the Java `Callback` (and, by transitivity, the `jsi::Function`) for potentially forever.
3. It is a requirement of `jsi::Runtime` that all objects associated with the Runtime (ex: `jsi::Function`) must be destroyed before the Runtime itself is destroyed. See: https://fburl.com/m3mqk6wt
### jsi.h
```
/// .................................................... In addition, to
/// make shutdown safe, destruction of objects associated with the Runtime
/// must be destroyed before the Runtime is destroyed, or from the
/// destructor of a managed HostObject or HostFunction. Informally, this
/// means that the main source of unsafe behavior is to hold a jsi object
/// in a non-Runtime-managed object, and not clean it up before the Runtime
/// is shut down. If your lifecycle is such that avoiding this is hard,
/// you will probably need to do use your own locks.
class Runtime {
public:
virtual ~Runtime();
```
Therefore, when you delete `CatalystInstanceImpl`, you could end up with a situation where the `jsi::Runtime` is destroyed before all `jsi::Function`s are destroyed. In dev, this leads the program to crash when you reload the app after having used a TurboModule method that uses callbacks.
## The Solution
If the only reference to a `HostObject` or a `HostFunction` is in the JS Heap, then the `HostObject` and `HostFunction` destructors can destroy JSI objects. The TurboModule cache is the only thing, aside from the JS Heap, that holds a reference to all C++ TurboModules. But that cache (and the entire native side of `TurboModuleManager`) is destroyed when we call `mHybridData.resetNative()` in `TurboModuleManager.onCatalystInstanceDestroy()` in D16552730. (I verified this by commenting out `mHybridData.resetNative()` and placing a breakpoint in the destructor of `JavaTurboModule`). So, when we're cleaning up `TurboModuleManager`, the only reference to a Java TurboModule is the JS Heap. Therefore, it's safe and correct for us to destroy all `jsi::Function`s created by the Java TurboModule in `~JavaTurboModule`. So, in this diff, I keep a set of all `CallbackWrappers`, and explicitly call `destroy()` on them in the `JavaTurboModule` destructor. Note that since `~JavaTurboModule` accesses `callbackWrappers_`, it must be executed on the JS Thread, since `createJavaCallbackFromJSIFunction` also accesses `callbackWrappers_` on the JS Thread.
For additional safety, I also eagerly destroyed the `jsi::Function` after it's been invoked once. I'm not yet sure if we only want JS callbacks to only ever be invoked once. So, I've created a Task to document this work: T48128233.
Reviewed By: mdvacca
Differential Revision: D16623340
fbshipit-source-id: 3a4c3efc70b9b3c8d329f19fdf4b4423c489695b