Description
Environment
Environment:
OS: macOS High Sierra 10.13.5
Node: 8.3.0
Yarn: 1.3.2
npm: 6.0.1
Watchman: 4.9.0
Xcode: Xcode 9.3.1 Build version 9E501
Android Studio: 3.1 AI-173.4819257
Packages: (wanted => installed)
react: 16.3.1 => 16.3.1
react-native: 0.55.4 => 0.55.4
Description
During (Android) development I was noticing that sometimes my AsyncTask
's were no longer executed. When analyzing the thread dump I noticed that at these times there was always an AsyncTask
from React Native's CatalystInstanceImpl
alive & running:
https://github.com/facebook/react-native/blob/0.56-stable/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java#L351
"AsyncTask #7@6218" prio=5 tid=0x4f5 nid=NA runnable
java.lang.Thread.State: RUNNABLE
at com.facebook.jni.HybridData$Destructor.deleteNative(HybridData.java:-1)
at com.facebook.jni.HybridData$Destructor.destruct(HybridData.java:73)
at com.facebook.jni.HybridData.resetNative(HybridData.java:39)
- locked <0x1871> (a com.facebook.jni.HybridData)
at com.facebook.react.bridge.CatalystInstanceImpl$1$1.run(CatalystInstanceImpl.java:349)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
Since this task is executed on the global / shared AsyncTask.SERIAL_EXECUTOR
other AsyncTask
will no longer execute.
It seems like after reloading the bridge this AsyncTask
is trying to clean up some (native / c++) resources asynchronously but starts hanging if the bridge is reloaded again while cleaning is still in-progress. I currently related this behavior only to rapid reloading but it might also happen at other moments.
Note that I've only seen it happen when Debugging JS. Without debugging it reloads fine so far.
Reproducible Demo
- Start an Emulator. I used a Nexus 5X / API 27.
react-native init BlockingAsyncTask
cd BlockingAsyncTask
react-native start
open http://localhost:8081/debugger-ui
react-native run-android
- In emulator:
CMD+M
->Debug JS Remotely
adb logcat | grep CatalystInstanceImpl.destroy
Notice that the adb logcat will contain two lines:
06-25 22:21:29.104 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:21:29.143 30424 30454 D ReactNative: CatalystInstanceImpl.destroy() end
Which is fine. The start
and end
logs should be balanced.
- Press R+R again in the emulator:
Again, nicely balanced start
and end
logs:
06-25 22:27:25.545 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:27:25.552 30424 30791 D ReactNative: CatalystInstanceImpl.destroy() end
- But now, try to rapidly reload by pressing R+R+R+R:
This time the log shows:
06-25 22:29:03.440 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:29:03.444 30424 30886 D ReactNative: CatalystInstanceImpl.destroy() end
06-25 22:29:03.689 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
Notice that the last start
log has not been balanced with an end
log.
- Any consequent reload now results in only a
start
log but noend
log:
06-25 22:30:01.285 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:30:04.127 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:30:15.552 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start
06-25 22:30:20.883 30424 30424 D ReactNative: CatalystInstanceImpl.destroy() start