Detangle destroy and create accesses

Differential Revision: D5823786

fbshipit-source-id: d6a6e29b856361a6b1d5ab48397607a844b5ab53
This commit is contained in:
Kathy Gray 2017-09-20 04:59:42 -07:00 committed by Facebook Github Bot
parent 628cbe170b
commit 6334ed2ff3
1 changed files with 70 additions and 33 deletions

View File

@ -137,13 +137,18 @@ public class ReactInstanceManager {
private final DevSupportManager mDevSupportManager;
private final boolean mUseDeveloperSupport;
private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener;
private final Object mReactContextLock = new Object();
private @Nullable volatile ReactContext mCurrentReactContext;
private final Context mApplicationContext;
private @Nullable @ThreadConfined(UI) DefaultHardwareBackBtnHandler mDefaultBackButtonImpl;
private @Nullable Activity mCurrentActivity;
private final Collection<ReactInstanceEventListener> mReactInstanceEventListeners =
Collections.synchronizedSet(new HashSet<ReactInstanceEventListener>());
// Identifies whether the instance manager is or soon will be initialized (on background thread)
private volatile boolean mHasStartedCreatingInitialContext = false;
// Identifies whether the insance manager destroy function is in process,
// while true any spawned create thread should wait for proper clean up before initializing
private volatile Boolean mHasStartedDestroying = false;
private final UIImplementationProvider mUIImplementationProvider;
private final MemoryPressureRouter mMemoryPressureRouter;
private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler;
@ -473,13 +478,13 @@ public class ReactInstanceManager {
public void onBackPressed() {
UiThreadUtil.assertOnUiThread();
ReactContext reactContext = mCurrentReactContext;
if (mCurrentReactContext == null) {
if (reactContext == null) {
// Invoke without round trip to JS.
FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
invokeDefaultOnBackPressed();
} else {
DeviceEventManagerModule deviceEventManagerModule =
Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class);
reactContext.getNativeModule(DeviceEventManagerModule.class);
deviceEventManagerModule.emitHardwareBackPressed();
}
}
@ -497,7 +502,8 @@ public class ReactInstanceManager {
@ThreadConfined(UI)
public void onNewIntent(Intent intent) {
UiThreadUtil.assertOnUiThread();
if (mCurrentReactContext == null) {
ReactContext currentContext = getCurrentReactContext();
if (currentContext == null) {
FLog.w(ReactConstants.TAG, "Instance detached from instance manager");
} else {
String action = intent.getAction();
@ -505,18 +511,18 @@ public class ReactInstanceManager {
if (Intent.ACTION_VIEW.equals(action) && uri != null) {
DeviceEventManagerModule deviceEventManagerModule =
Assertions.assertNotNull(mCurrentReactContext)
.getNativeModule(DeviceEventManagerModule.class);
currentContext.getNativeModule(DeviceEventManagerModule.class);
deviceEventManagerModule.emitNewIntentReceived(uri);
}
mCurrentReactContext.onNewIntent(mCurrentActivity, intent);
currentContext.onNewIntent(mCurrentActivity, intent);
}
}
private void toggleElementInspector() {
if (mCurrentReactContext != null) {
mCurrentReactContext
ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
currentContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit("toggleElementInspector", null);
}
@ -623,6 +629,8 @@ public class ReactInstanceManager {
UiThreadUtil.assertOnUiThread();
PrinterHolder.getPrinter().logMessage(ReactDebugOverlayTags.RN_CORE, "RNCore: Destroy");
mHasStartedDestroying = true;
if (mUseDeveloperSupport) {
mDevSupportManager.setDevSupportEnabled(false);
mDevSupportManager.stopInspector();
@ -631,54 +639,62 @@ public class ReactInstanceManager {
moveToBeforeCreateLifecycleState();
if (mCreateReactContextThread != null) {
mCreateReactContextThread.interrupt();
mCreateReactContextThread = null;
}
mMemoryPressureRouter.destroy(mApplicationContext);
if (mCurrentReactContext != null) {
mCurrentReactContext.destroy();
mCurrentReactContext = null;
mHasStartedCreatingInitialContext = false;
synchronized (mReactContextLock) {
if (mCurrentReactContext != null) {
mCurrentReactContext.destroy();
mCurrentReactContext = null;
}
}
mHasStartedCreatingInitialContext = false;
mCurrentActivity = null;
ResourceDrawableIdHelper.getInstance().clear();
mHasStartedDestroying = false;
synchronized (mHasStartedDestroying) {
mHasStartedDestroying.notifyAll();
}
}
private synchronized void moveToResumedLifecycleState(boolean force) {
if (mCurrentReactContext != null) {
ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
// we currently don't have an onCreate callback so we call onResume for both transitions
if (force ||
mLifecycleState == LifecycleState.BEFORE_RESUME ||
mLifecycleState == LifecycleState.BEFORE_CREATE) {
mCurrentReactContext.onHostResume(mCurrentActivity);
currentContext.onHostResume(mCurrentActivity);
}
}
mLifecycleState = LifecycleState.RESUMED;
}
private synchronized void moveToBeforeResumeLifecycleState() {
if (mCurrentReactContext != null) {
ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
if (mLifecycleState == LifecycleState.BEFORE_CREATE) {
mCurrentReactContext.onHostResume(mCurrentActivity);
mCurrentReactContext.onHostPause();
currentContext.onHostResume(mCurrentActivity);
currentContext.onHostPause();
} else if (mLifecycleState == LifecycleState.RESUMED) {
mCurrentReactContext.onHostPause();
currentContext.onHostPause();
}
}
mLifecycleState = LifecycleState.BEFORE_RESUME;
}
private synchronized void moveToBeforeCreateLifecycleState() {
if (mCurrentReactContext != null) {
ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
if (mLifecycleState == LifecycleState.RESUMED) {
mCurrentReactContext.onHostPause();
currentContext.onHostPause();
mLifecycleState = LifecycleState.BEFORE_RESUME;
}
if (mLifecycleState == LifecycleState.BEFORE_RESUME) {
mCurrentReactContext.onHostDestroy();
currentContext.onHostDestroy();
}
}
mLifecycleState = LifecycleState.BEFORE_CREATE;
@ -692,8 +708,9 @@ public class ReactInstanceManager {
@ThreadConfined(UI)
public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
if (mCurrentReactContext != null) {
mCurrentReactContext.onActivityResult(activity, requestCode, resultCode, data);
ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
currentContext.onActivityResult(activity, requestCode, resultCode, data);
}
}
@ -722,8 +739,9 @@ public class ReactInstanceManager {
// If react context is being created in the background, JS application will be started
// automatically when creation completes, as root view is part of the attached root view list.
if (mCreateReactContextThread == null && mCurrentReactContext != null) {
attachRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance());
ReactContext currentContext = getCurrentReactContext();
if (mCreateReactContextThread == null && currentContext != null) {
attachRootViewToInstance(rootView, currentContext.getCatalystInstance());
}
}
@ -736,8 +754,9 @@ public class ReactInstanceManager {
public void detachRootView(ReactRootView rootView) {
UiThreadUtil.assertOnUiThread();
if (mAttachedRootViews.remove(rootView)) {
if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) {
detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance());
ReactContext currentContext = getCurrentReactContext();
if (currentContext != null && currentContext.hasActiveCatalystInstance()) {
detachViewFromInstance(rootView, currentContext.getCatalystInstance());
}
}
}
@ -777,7 +796,9 @@ public class ReactInstanceManager {
@VisibleForTesting
public @Nullable ReactContext getCurrentReactContext() {
return mCurrentReactContext;
synchronized (mReactContextLock) {
return mCurrentReactContext;
}
}
public LifecycleState getLifecycleState() {
@ -828,14 +849,28 @@ public class ReactInstanceManager {
private void runCreateReactContextOnNewThread(final ReactContextInitParams initParams) {
Log.d(ReactConstants.TAG, "ReactInstanceManager.runCreateReactContextOnNewThread()");
UiThreadUtil.assertOnUiThread();
if (mCurrentReactContext != null) {
tearDownReactContext(mCurrentReactContext);
mCurrentReactContext = null;
synchronized (mReactContextLock) {
if (mCurrentReactContext != null) {
tearDownReactContext(mCurrentReactContext);
mCurrentReactContext = null;
}
}
mCreateReactContextThread = new Thread(new Runnable() {
@Override
public void run() {
synchronized (ReactInstanceManager.this.mHasStartedDestroying) {
while (ReactInstanceManager.this.mHasStartedDestroying) {
try {
ReactInstanceManager.this.mHasStartedDestroying.wait();
} catch (InterruptedException e) {
continue;
}
}
}
// As destroy() may have run and set this to false, ensure that it is true before we create
mHasStartedCreatingInitialContext = true;
try {
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
final ReactApplicationContext reactApplicationContext = createReactContext(
@ -879,7 +914,9 @@ public class ReactInstanceManager {
ReactMarker.logMarker(PRE_SETUP_REACT_CONTEXT_END);
ReactMarker.logMarker(SETUP_REACT_CONTEXT_START);
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "setupReactContext");
mCurrentReactContext = Assertions.assertNotNull(reactContext);
synchronized (mReactContextLock) {
mCurrentReactContext = Assertions.assertNotNull(reactContext);
}
CatalystInstance catalystInstance =
Assertions.assertNotNull(reactContext.getCatalystInstance());