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
This commit is contained in:
Родитель
7b9c456e7d
Коммит
9fdc8daf61
|
@ -158,7 +158,7 @@ public class ReactInstanceManager {
|
|||
private @Nullable @ThreadConfined(UI) DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
|
||||
private @Nullable Activity mCurrentActivity;
|
||||
private final Collection<ReactInstanceEventListener> mReactInstanceEventListeners =
|
||||
Collections.synchronizedSet(new HashSet<ReactInstanceEventListener>());
|
||||
Collections.synchronizedList(new ArrayList<ReactInstanceEventListener>());
|
||||
// Identifies whether the instance manager is or soon will be initialized (on background thread)
|
||||
private volatile boolean mHasStartedCreatingInitialContext = false;
|
||||
// Identifies whether the instance manager destroy function is in process,
|
||||
|
|
Загрузка…
Ссылка в новой задаче