Skip to content

Commit

Permalink
Fix ReactInstanceManager deadlock
Browse files Browse the repository at this point in the history
Summary:
D12829677 introduced a deadlock where onHostResume holds the lock on `moveToResumedLifecycleState()` then waits for the `mReactContext` lock, but at the same time setupReactContext holds the `mReactContext` lock and waits for `moveToResumedLifecycleState()` https://our.intern.facebook.com/intern/everpaste/?handle=GAgXFgLQH1ZlQikBAMQzo2LZ6h9TbiAxAAAz. The purpose of the previous diff was to make sure that detachRootoView and
setupReactContext did not interfere with each other, and implemented that by blocking on mReactContext. Since this overloads the usage of mReactContext, let's use a different lock `mAttachedRootViews` to implement this behavior instead

Reviewed By: mdvacca

Differential Revision: D12989555

fbshipit-source-id: c12e5fd9c5fa4c2037167e9400dc0c1578e38959
  • Loading branch information
ayc1 authored and facebook-github-bot committed Nov 9, 2018
1 parent 80f92ad commit df7e8c6
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
@RunWith(AndroidJUnit4.class)
public class ReactInstanceManagerTest {

private static final String TEST_MODULE = "ViewLayoutTestApp";

private ReactInstanceManager mReactInstanceManager;
private ReactRootView mReactRootView;

Expand All @@ -45,7 +47,25 @@ public void setup() {
@UiThreadTest
public void testMountUnmount() {
mReactInstanceManager.onHostResume(mActivityRule.getActivity());
mReactRootView.startReactApplication(mReactInstanceManager, "ViewLayoutTestApp");
mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
mReactRootView.unmountReactApplication();
}

@Test
@UiThreadTest
public void testResume() throws InterruptedException {
mReactInstanceManager.onHostResume(mActivityRule.getActivity());
mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
Thread.sleep(1000);
mReactInstanceManager.onHostResume(mActivityRule.getActivity());
}

@Test
@UiThreadTest
public void testRecreateContext() throws InterruptedException {
mReactInstanceManager.onHostResume(mActivityRule.getActivity());
mReactInstanceManager.createReactContextInBackground();
Thread.sleep(1000);
mReactRootView.startReactApplication(mReactInstanceManager, TEST_MODULE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -741,11 +741,13 @@ public void attachRootView(ReactRootView rootView) {
@ThreadConfined(UI)
public void detachRootView(ReactRootView rootView) {
UiThreadUtil.assertOnUiThread();
if (mAttachedRootViews.contains(rootView)) {
ReactContext currentContext = getCurrentReactContext();
mAttachedRootViews.remove(rootView);
if (currentContext != null && currentContext.hasActiveCatalystInstance()) {
detachViewFromInstance(rootView, currentContext.getCatalystInstance());
synchronized (mAttachedRootViews) {
if (mAttachedRootViews.contains(rootView)) {
ReactContext currentContext = getCurrentReactContext();
mAttachedRootViews.remove(rootView);
if (currentContext != null && currentContext.hasActiveCatalystInstance()) {
detachViewFromInstance(rootView, currentContext.getCatalystInstance());
}
}
}
}
Expand Down Expand Up @@ -904,10 +906,12 @@ private void recreateReactContextInBackground(
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
UiThreadUtil.assertOnUiThread();
synchronized (mReactContextLock) {
if (mCurrentReactContext != null) {
tearDownReactContext(mCurrentReactContext);
mCurrentReactContext = null;
synchronized (mAttachedRootViews) {
synchronized (mReactContextLock) {
if (mCurrentReactContext != null) {
tearDownReactContext(mCurrentReactContext);
mCurrentReactContext = null;
}
}
}

Expand Down Expand Up @@ -979,8 +983,11 @@ private void setupReactContext(final ReactApplicationContext reactContext) {
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
synchronized (mAttachedRootViews) {
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}

CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());

Expand All @@ -990,10 +997,8 @@ private void setupReactContext(final ReactApplicationContext reactContext) {
moveReactContextToCurrentLifecycleState();

ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_START);
synchronized (mAttachedRootViews) {
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView);
}
for (ReactRootView rootView : mAttachedRootViews) {
attachRootViewToInstance(rootView);
}
ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END);
}
Expand Down

0 comments on commit df7e8c6

Please sign in to comment.