A framework for building native macOS apps with React.
Перейти к файлу
Ramanpreet Nara 9fdc8daf61 Fix race in TurboModuleManager initialization
Summary:
## Description
To initialize `TurboModuleManager`, we first need to wait until `ReactContext` is initialized. Then, we get the `TurboModuleManager` instance and assign it as the `TurboModuleRegistry` of `CatalystInstanceImpl`. This allows `CatalystInstanceImpl` to return TurboModules from its `getNativeModule` method. In `FbReactFragment`, we also wait until the `ReactContext` is initialized before then eagerly initialize a bunch of NativeModules. All this waiting is done by adding instances of `ReactInstanceEventListener` to `ReactInstanceManager`'s `mReactInstanceEventListeners` synchronized Set. When the `ReactContext` is finally initialized, we loop over this set and invoke all the listeners.

## Problem
We want to initialize `TurboModuleManager` and set it as the `TurboModuleRegistry` of `CatalystInstanceImpl` before we start eagerly initializing our NativeModules. Why? Because otherwise TurboModules that need to be eagerly initialized won't be. The fact that we're using a Set to manage the `ReactInstanceEventListener`s means that our listeners can be invoked in any order. This is bad because we can start to eagerly initialize NativeModules before we've had the chance to assign `TurboModuleManager` as the `TurboModuleRegistry` of `CatalystInstanceImpl`. In development, this race was leading to the following crash:

```
06-05 11:11:02.020 10461 10617 E AndroidRuntime: FATAL EXCEPTION: CombinedTP8
06-05 11:11:02.020 10461 10617 E AndroidRuntime: Process: com.facebook.wakizashi, PID: 10461
06-05 11:11:02.020 10461 10617 E AndroidRuntime: java.lang.AssertionError: Could not find module with name PrimedStorage
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.infer.annotation.Assertions.assertNotNull(Assertions.java:35)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:147)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:444)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.fbreact.fragment.FbReactFragment$4$1.run(FbReactFragment.java:418)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.executors.WrappingExecutorService$1.run(WrappingExecutorService.java:82)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.combinedthreadpool.queue.CombinedSimpleTask.run(CombinedSimpleTask.java:81)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.combinedthreadpool.queue.CombinedLifetimeThreadFactory$1.run(CombinedLifetimeThreadFactory.java:40)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.executors.NamedThreadFactory$1.run(NamedThreadFactory.java:53)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.lang.Thread.run(Thread.java:764)
```

## Diagnosing the crash

It looks like `NativeModuleRegistry.getModule` was throwing an error because `PrimedStorage` was null. `PrimedStorage` was turned into a TurboModule, so of course it wouldn't be in the `NativeModuleRegistry`. It should be in the `TurboModuleRegistry`. So, I placed an assertion in `CatalystInstanceImpl`:

```
Override
public NativeModule getNativeModule(String moduleName) {
  Assertions.assertNotNull(mTurboModuleRegistry, "TurboModuleRegsitry is not null");
  if (mTurboModuleRegistry != null) {
    TurboModule turboModule = mTurboModuleRegistry.getModule(moduleName);

    if (turboModule != null) {
      return (NativeModule)turboModule;
    }
  }

  return mNativeModuleRegistry.getModule(moduleName);
}
```

Sure enough, this assertion started tripping, which meant that `mTurboModuleRegistry` was null. From this information, I hypothesized that we started to eagerly initialize our NativeModules before `TurboModuleManager` was initialized. To verify this hypothesis, I added logging statements in each `ReactInstanceEventListener`: P65477469. `eagerInitializeReactNativeComponents (START)` documents when we start to eagerly intialize our NativeModules. `getReactInstanceManager (START)` documents when we start to initialize `TurboModuleManager` inside `FbReactInstanceHolder.getReactInstanceManager` method. Sure enough, when the program finally crashed, I saw in our logs that we started eagerly initializing our NativeModules before we initialized the TurboModuleManager:

```
06-05 11:11:01.951 10461 10617 V Ramanpreet: eagerInitializeReactNativeComponents (START): 1559758261951
06-05 11:11:01.956 10461 10461 V Ramanpreet: getReactInstanceManager (START): 1559758261956
06-05 11:11:01.958 10461 10461 D SoLoader: About to load: libturbomodulejsijni.so
06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-zstd
06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-xzs
06-05 11:11:01.960 10461 10461 D SoLoader: libturbomodulejsijni.so not found on /data/data/com.facebook.wakizashi/lib-assets
06-05 11:11:01.961 10461 10461 D SoLoader: libturbomodulejsijni.so found on /data/data/com.facebook.wakizashi/lib-main
06-05 11:11:01.965 10461 10461 D SoLoader: Loading lib dependencies: [libfb.so, libfbjni.so, libglog.so, libdouble-conversion.so, libxplat_jsi_jsiAndroid.so, libxplat_jsi_JSIDynamicAndroid.so, libfbsystrace.so, libmemalign16.so, libgnustl_shared.so, libm.so, libc.so]
06-05 11:11:01.999 10461 10769 D SoLoader: init exiting
06-05 11:11:01.999 10461 10461 D SoLoader: Loaded: libturbomodulejsijni.so
06-05 11:11:01.999 10461 10461 D SoLoader: About to load: libfb4aturbomodulemanagerdelegate.so
06-05 11:11:01.999 10461 10769 W fb4a.ImagePipelineFactory: ImagePipelineFactory has already been initialized! `ImagePipelineFactory.initialize(...)` should only be called once to avoid unexpected behavior.
06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-zstd
06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-xzs
06-05 11:11:02.002 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so not found on /data/data/com.facebook.wakizashi/lib-assets
06-05 11:11:02.004 10461 10461 D SoLoader: libfb4aturbomodulemanagerdelegate.so found on /data/data/com.facebook.wakizashi/lib-main
06-05 11:11:02.007 10461 10461 D SoLoader: Loading lib dependencies: [libturbomodulejsijni.so, libfb.so, libfbjni.so, libxplat_jsi_jsiAndroid.so, libxplat_jsi_JSIDynamicAndroid.so, libreactnativejni.so, libmemalign16.so, libgnustl_shared.so, libc.so]
06-05 11:11:02.020 10461 10617 E AndroidRuntime: FATAL EXCEPTION: CombinedTP8
06-05 11:11:02.020 10461 10617 E AndroidRuntime: Process: com.facebook.wakizashi, PID: 10461
06-05 11:11:02.020 10461 10617 E AndroidRuntime: java.lang.AssertionError: Could not find module with name PrimedStorage
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.infer.annotation.Assertions.assertNotNull(Assertions.java:35)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.react.bridge.NativeModuleRegistry.getModule(NativeModuleRegistry.java:147)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.react.bridge.CatalystInstanceImpl.getNativeModule(CatalystInstanceImpl.java:444)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.fbreact.fragment.FbReactFragment$4$1.run(FbReactFragment.java:418)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:457)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.executors.WrappingExecutorService$1.run(WrappingExecutorService.java:82)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.combinedthreadpool.queue.CombinedSimpleTask.run(CombinedSimpleTask.java:81)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.combinedthreadpool.queue.CombinedLifetimeThreadFactory$1.run(CombinedLifetimeThreadFactory.java:40)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at com.facebook.common.executors.NamedThreadFactory$1.run(NamedThreadFactory.java:53)
06-05 11:11:02.020 10461 10617 E AndroidRuntime: 	at java.lang.Thread.run(Thread.java:764)
06-05 11:11:02.038  1647  1667 I WifiService: requestActivityInfo uid=1000
06-05 11:11:02.038  1647  1667 I WifiService: reportActivityInfo uid=1000
06-05 11:11:02.038  1647  1667 I WifiService: getSupportedFeatures uid=1000
06-05 11:11:02.044  1647  1667 E BluetoothAdapter: Bluetooth binder is null
06-05 11:11:02.049  1647  1667 E KernelCpuSpeedReader: Failed to read cpu-freq: /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state (No such file or directory)
06-05 11:11:02.050  1647  1667 E BatteryExternalStatsWorker: modem info is invalid: ModemActivityInfo{ mTimestamp=0 mSleepTimeMs=0 mIdleTimeMs=0 mTxTimeMs[]=[0, 0, 0, 0, 0] mRxTimeMs=0 mEnergyUsed=0}
06-05 11:11:02.057  2147 10435 W ctxmgr  : [AclManager]No 2 for (accnt=account#-517948760#, com.google.android.gms(10013):IndoorOutdoorProducer, vrsn=13280000, 0, 3pPkg = null ,  3pMdlId = null ,  pid = 2147). Was: 3 for 57, account#-517948760#
06-05 11:11:02.077 10461 10461 D SoLoader: Loaded: libfb4aturbomodulemanagerdelegate.so
06-05 11:11:02.079 10461 10461 V Ramanpreet: getReactInstanceManager (END): 1559758262079
```

Reviewed By: mdvacca

Differential Revision: D15676746

fbshipit-source-id: a7ac02d868abf31c5d664b10f70b6db247f388f5
2019-06-05 19:05:41 -07:00
.appveyor Bump Android NDK to r19c (#25140) 2019-06-04 13:59:36 -07:00
.circleci Bump Android NDK to r19c (#25140) 2019-06-04 13:59:36 -07:00
.github Bots cleanup, avoid leaving inline reviews when N>5 (#24923) 2019-05-21 19:38:54 -07:00
IntegrationTests Migrate IntegrationTests from Haste to path-based requires (#24750) 2019-05-08 03:17:03 -07:00
Libraries TurboModules: Improve Error Message 2019-06-05 17:35:01 -07:00
RNTester Back out "[react-native][PR] [Blob] Release underlying resources when JS instance is GC'ed on Android" 2019-06-05 01:49:54 -07:00
React RN: Restore Debug Bridge Description (iOS) 2019-06-05 19:00:32 -07:00
ReactAndroid Fix race in TurboModuleManager initialization 2019-06-05 19:05:41 -07:00
ReactCommon RN: Restore Debug Bridge Description (iOS) 2019-06-05 19:00:32 -07:00
bots Bots cleanup, avoid leaving inline reviews when N>5 (#24923) 2019-05-21 19:38:54 -07:00
flow Make RelayObservable Source return type disjoint 2019-05-28 12:13:49 -07:00
flow-typed/npm remove deprecated utilities 2019-01-15 13:59:31 -08:00
gradle/wrapper bump Gradle to 5.4.1 (#24542) 2019-04-27 00:10:04 -07:00
jest Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper (#24811) 2019-06-05 10:55:08 -07:00
keystores Use fb_native_wrapper for all targets 2018-10-31 11:47:42 -07:00
local-cli Update references to the CLI (#23052) 2019-01-21 09:13:08 -08:00
packages Fabric: Enable CXX (aka Default) platfrom fravour for all C++ Fabric targets 2019-06-04 15:34:34 -07:00
scripts Bump Android NDK to r19c (#25140) 2019-06-04 13:59:36 -07:00
template Make Flow configs use path-based imports instead of Haste (#24812) 2019-06-05 16:00:52 -07:00
third-party-podspecs Fabric: working podspecs & works in RNTester (#23803) 2019-03-15 23:59:22 -07:00
tools/build_defs Migration of RN-Android OSS tests to Android X 2019-03-17 08:13:30 -07:00
.buckconfig Bump Android SDK to 28, Build Tools to 28.0.2, Gradle to 4.7, Gradle Plugin to 3.2.0 (#21632) 2018-12-05 09:06:31 -08:00
.buckjavaargs limiting BUCK's memory for CI 2016-02-01 10:49:33 -08:00
.clang-format Moving ObjC specific clang-format rules to the common config 2019-02-11 13:07:09 -08:00
.editorconfig editorconfig: Set indent_size for BUCK files to 4 (#21554) 2018-10-08 23:17:38 -07:00
.eslintignore Eliminate eslint npm version mismatch warnings and bump some to latest (#23969) 2019-03-19 11:14:30 -07:00
.eslintrc Add a lint rule to disallow Haste imports (#25058) 2019-05-30 07:45:16 -07:00
.flowconfig Make Flow configs use path-based imports instead of Haste (#24812) 2019-06-05 16:00:52 -07:00
.flowconfig.android Make Flow configs use path-based imports instead of Haste (#24812) 2019-06-05 16:00:52 -07:00
.gitattributes Added a .gitattributes file, ensuring that Bash script source files (gradlew and 2015-10-13 23:10:39 -04:00
.gitignore - Update folder structure of RNTester's JS directory. (#25013) 2019-05-28 08:39:18 -07:00
.nvmrc Add .nvmrc + fix node version for eslint 5 compat (#20109) 2018-07-31 02:34:16 -07:00
.prettierrc Set the Prettier config so it is not forced on users of @react-native-community/eslint-config (#24635) 2019-04-29 09:44:51 -07:00
CODE_OF_CONDUCT.md Update repo documentation to match other Facebook projects 2018-09-10 18:02:26 -07:00
CONTRIBUTING.md (CONTRIBUTING.md) Link to Issues wiki (#25035) 2019-05-28 07:04:12 -07:00
ECOSYSTEM.md Add document describing the RN ecosystem. (#24493) 2019-04-17 09:06:37 -07:00
LICENSE Update copyright headers to yearless format 2018-09-11 15:33:07 -07:00
LICENSE-docs More licenses 2015-03-24 19:59:10 -07:00
README.md Add document describing the RN ecosystem. (#24493) 2019-04-17 09:06:37 -07:00
React.podspec Move iOS Geolocation code out from the repo 2019-04-02 15:36:10 -07:00
Releases.md Fix typo in Releases.md (#20487) 2018-08-01 07:16:56 -07:00
build.gradle.kts bump android gradle plugin to 3.4.1 (#24883) 2019-05-24 11:53:17 -07:00
cli.js Show full price instead of monthly price within the lead form 2019-03-28 16:07:19 -07:00
gradlew bump Gradle to 5.4.1 (#24542) 2019-04-27 00:10:04 -07:00
gradlew.bat bump Gradle to 5.4.1 (#24542) 2019-04-27 00:10:04 -07:00
jest-preset.js Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper (#24811) 2019-06-05 10:55:08 -07:00
jest.config.js Delete hasteImpl, providesModuleNodeModules, and modulePathNameMapper (#24811) 2019-06-05 10:55:08 -07:00
metro.config.js Use latest React Native CLI (#24517) 2019-04-24 05:09:10 -07:00
package.json Deploy Flow v0.100 to xplat/js 2019-06-03 23:03:41 -07:00
react-native.config.js - update CLI to alpha.20 to fix Android tests (#24869) 2019-05-16 06:11:15 -07:00
react.gradle Android Fix for 9145: No longer hard code build port (#23616) 2019-06-05 06:15:06 -07:00
rn-get-polyfills.js Remove Polyfills from RN Open Source 2019-04-04 15:20:33 -07:00
runXcodeTests.sh Update copyright headers to yearless format 2018-09-11 15:33:07 -07:00
settings.gradle.kts Gradle KTS (#24631) 2019-04-29 02:41:05 -07:00
template.config.js Improvement: Adjust template to match new init command (#24138) 2019-04-01 16:25:48 -07:00
yarn.lock Deploy Flow v0.100 to xplat/js 2019-06-03 23:03:41 -07:00

README.md

React Native

Learn once, write anywhere:
Build mobile apps with React.

React Native is released under the MIT license. Current CircleCI build status. Current Appveyor build status. Current npm package version. PRs welcome! Follow @reactnative

Getting Started · Learn the Basics · Showcase · Contribute · Community · Support

React Native brings React's declarative UI framework to iOS and Android. With React Native, you use native UI controls and have full access to the native platform.

  • Declarative. React makes it painless to create interactive UIs. Declarative views make your code more predictable and easier to debug.
  • Component-Based. Build encapsulated components that manage their own state, then compose them to make complex UIs.
  • Developer Velocity. See local changes in seconds. Changes to JavaScript code can be live reloaded without rebuilding the native app.
  • Portability. Reuse code across iOS, Android, and other platforms.

React Native is developed and supported by many companies and individual core contributors. Find out more in our ecosystem overview.

Contents

📋 Requirements

React Native apps may target iOS 9.0 and Android 4.1 (API 16) or newer. You may use Windows, macOS, or Linux as your development operating system, though building and running iOS apps is limited to macOS. Tools like Expo can be used to work around this.

🎉 Building your first React Native app

Follow the Getting Started guide. The recommended way to install React Native depends on your project. Here you can find short guides for the most common scenarios:

📖 Documentation

The full documentation for React Native can be found on our website.

The React Native documentation discusses components, APIs, and topics that are specific to React Native. For further documentation on the React API that is shared between React Native and React DOM, refer to the React documentation.

The source for the React Native documentation and website is hosted on a separate repo, @facebook/react-native-website.

🚀 Upgrading

Upgrading to new versions of React Native may give you access to more APIs, views, developer tools and other goodies. See the Upgrading Guide for instructions.

React Native releases are discussed in the React Native Community, @react-native-community/react-native-releases.

👏 How to Contribute

The main purpose of this repository is to continue evolving React Native core. We want to make contributing to this project as easy and transparent as possible, and we are grateful to the community for contributing bugfixes and improvements. Read below to learn how you can take part in improving React Native.

Code of Conduct

Facebook has adopted a Code of Conduct that we expect project participants to adhere to. Please read the full text so that you can understand what actions will and will not be tolerated.

Contributing Guide

Read our Contributing Guide to learn about our development process, how to propose bugfixes and improvements, and how to build and test your changes to React Native.

Open Source Roadmap

You can learn more about our vision for React Native in the Roadmap.

Good First Issues

We have a list of good first issues that contain bugs which have a relatively limited scope. This is a great place to get started, gain experience, and get familiar with our contribution process.

Discussions

Larger discussions and proposals are discussed in @react-native-community/discussions-and-proposals.

📄 License

React Native is MIT licensed, as found in the LICENSE file.

React Native documentation is Creative Commons licensed, as found in the LICENSE-docs file.