NativeAnimatedModule: fix crash that can occur when animated node setup races with NativeAnimatedModule setup
Summary: When switching between non-Fabric and Fabric screens, I believe that `initializeEventListenerForUIManagerType` is not always being called on the NativeAnimatedNodesManager if `NativeAnimatedModule.initializeLifecycleEventListenersForViewTag` is being called before the NativeAnimatedNodesManager ivar has been set. This should occur very infrequently, but logs indicate that it /does/ happen in some marginal cases. Protecting against these cases should be trivial, by using the `getNodesManager` method which is responsible for returning a nodes manager or creating a new one. The existing uses of the `NativeAnimatedNodesManager` ivar also occur on different threads and we were not protecting against this, so I'm changing it to an atomic. It's very likely that the inconsistency issues in the past were caused not by ordering errors, but thread races. Changelog: [Internal] Reviewed By: fkgozali Differential Revision: D24267118 fbshipit-source-id: 68abbff7ef3d0b2ecc9aa9977165663ad9447ab8
This commit is contained in:
Родитель
4d247fe058
Коммит
71bb19827b
|
@ -17,6 +17,7 @@ import com.facebook.react.bridge.Arguments;
|
||||||
import com.facebook.react.bridge.Callback;
|
import com.facebook.react.bridge.Callback;
|
||||||
import com.facebook.react.bridge.LifecycleEventListener;
|
import com.facebook.react.bridge.LifecycleEventListener;
|
||||||
import com.facebook.react.bridge.ReactApplicationContext;
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.facebook.react.bridge.ReactSoftException;
|
||||||
import com.facebook.react.bridge.ReadableMap;
|
import com.facebook.react.bridge.ReadableMap;
|
||||||
import com.facebook.react.bridge.UIManager;
|
import com.facebook.react.bridge.UIManager;
|
||||||
import com.facebook.react.bridge.UIManagerListener;
|
import com.facebook.react.bridge.UIManagerListener;
|
||||||
|
@ -34,6 +35,7 @@ import com.facebook.react.uimanager.common.UIManagerType;
|
||||||
import com.facebook.react.uimanager.common.ViewUtil;
|
import com.facebook.react.uimanager.common.ViewUtil;
|
||||||
import java.util.Queue;
|
import java.util.Queue;
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Module that exposes interface for creating and managing animated nodes on the "native" side.
|
* Module that exposes interface for creating and managing animated nodes on the "native" side.
|
||||||
|
@ -111,7 +113,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||||
private final ConcurrentLinkedQueue<UIThreadOperation> mPreOperations =
|
private final ConcurrentLinkedQueue<UIThreadOperation> mPreOperations =
|
||||||
new ConcurrentLinkedQueue<>();
|
new ConcurrentLinkedQueue<>();
|
||||||
|
|
||||||
private @Nullable NativeAnimatedNodesManager mNodesManager;
|
private final AtomicReference<NativeAnimatedNodesManager> mNodesManager = new AtomicReference<>();
|
||||||
|
|
||||||
private boolean mBatchingControlledByJS = false; // TODO T71377544: delete
|
private boolean mBatchingControlledByJS = false; // TODO T71377544: delete
|
||||||
private volatile long mCurrentFrameNumber; // TODO T71377544: delete
|
private volatile long mCurrentFrameNumber; // TODO T71377544: delete
|
||||||
|
@ -223,6 +225,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||||
executeAllOperations(mOperations, batchNumber);
|
executeAllOperations(mOperations, batchNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UiThread
|
||||||
private void executeAllOperations(Queue<UIThreadOperation> operationQueue, long maxBatchNumber) {
|
private void executeAllOperations(Queue<UIThreadOperation> operationQueue, long maxBatchNumber) {
|
||||||
NativeAnimatedNodesManager nodesManager = getNodesManager();
|
NativeAnimatedNodesManager nodesManager = getNodesManager();
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -315,15 +318,15 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private NativeAnimatedNodesManager getNodesManager() {
|
private NativeAnimatedNodesManager getNodesManager() {
|
||||||
if (mNodesManager == null) {
|
if (mNodesManager.get() == null) {
|
||||||
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();
|
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();
|
||||||
|
|
||||||
if (reactApplicationContext != null) {
|
if (reactApplicationContext != null) {
|
||||||
mNodesManager = new NativeAnimatedNodesManager(reactApplicationContext);
|
mNodesManager.compareAndSet(null, new NativeAnimatedNodesManager(reactApplicationContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return mNodesManager;
|
return mNodesManager.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearFrameCallback() {
|
private void clearFrameCallback() {
|
||||||
|
@ -340,7 +343,7 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setNodesManager(NativeAnimatedNodesManager nodesManager) {
|
public void setNodesManager(NativeAnimatedNodesManager nodesManager) {
|
||||||
mNodesManager = nodesManager;
|
mNodesManager.set(nodesManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -358,8 +361,14 @@ public class NativeAnimatedModule extends NativeAnimatedModuleSpec
|
||||||
mNumNonFabricAnimations++;
|
mNumNonFabricAnimations++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mNodesManager != null) {
|
NativeAnimatedNodesManager nodesManager = getNodesManager();
|
||||||
mNodesManager.initializeEventListenerForUIManagerType(mUIManagerType);
|
if (nodesManager != null) {
|
||||||
|
nodesManager.initializeEventListenerForUIManagerType(mUIManagerType);
|
||||||
|
} else {
|
||||||
|
ReactSoftException.logSoftException(
|
||||||
|
NAME,
|
||||||
|
new RuntimeException(
|
||||||
|
"initializeLifecycleEventListenersForViewTag could not get NativeAnimatedNodesManager"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscribe to UIManager (Fabric or non-Fabric) lifecycle events if we haven't yet
|
// Subscribe to UIManager (Fabric or non-Fabric) lifecycle events if we haven't yet
|
||||||
|
|
Загрузка…
Ссылка в новой задаче