Fix crash associated with setJSResponderHandler

Summary:
In Fabric we're seeing setJSResponderHandler called during teardown of a surface, which causes a crash because the SurfaceId is no longer available at that point.

Guard against setJSResponderHandler being called on a dead surface.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D26734786

fbshipit-source-id: 838d682ee0dd1d4de49993fa479dc2097cf33521
This commit is contained in:
Joshua Gross 2021-03-01 15:46:07 -08:00 коммит произвёл Facebook GitHub Bot
Родитель b08362ade5
Коммит 21a434ceec
3 изменённых файлов: 22 добавлений и 31 удалений

Просмотреть файл

@ -1079,8 +1079,15 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
new MountItem() {
@Override
public void execute(MountingManager mountingManager) {
mountingManager.setJSResponder(
surfaceId, reactTag, initialReactTag, blockNativeResponder);
SurfaceMountingManager surfaceMountingManager =
mountingManager.getSurfaceManager(surfaceId);
if (surfaceMountingManager != null) {
surfaceMountingManager.setJSResponder(
reactTag, initialReactTag, blockNativeResponder);
} else {
FLog.e(
TAG, "setJSResponder skipped, surface no longer available [" + surfaceId + "]");
}
}
@Override

Просмотреть файл

@ -270,38 +270,15 @@ public class MountingManager {
getSurfaceManagerForViewEnforced(reactTag).updateProps(reactTag, props);
}
/**
* Set the JS responder for the view associated with the tags received as a parameter.
*
* <p>The JSResponder coordinates the return values of the onInterceptTouch method in Android
* Views. This allows JS to coordinate when a touch should be handled by JS or by the Android
* native views. See {@link JSResponderHandler} for more details.
*
* <p>This method is going to be executed on the UIThread as soon as it is delivered from JS to
* RN.
*
* <p>Currently, there is no warranty that the view associated with the react tag exists, because
* this method is not handled by the react commit process.
*
* @param reactTag React tag of the first parent of the view that is NOT virtual
* @param initialReactTag React tag of the JS view that initiated the touch operation
* @param blockNativeResponder If native responder should be blocked or not
*/
@UiThread
public synchronized void setJSResponder(
int surfaceId, int reactTag, int initialReactTag, boolean blockNativeResponder) {
UiThreadUtil.assertOnUiThread();
getSurfaceManagerEnforced(surfaceId, "setJSResponder")
.setJSResponder(reactTag, initialReactTag, blockNativeResponder);
}
/**
* Clears the JS Responder specified by {@link #setJSResponder(int, int, int, boolean)}. After
* this method is called, all the touch events are going to be handled by JS.
*/
@UiThread
public void clearJSResponder() {
// MountingManager and SurfaceMountingManagers all share the same JSResponderHandler.
// Must be called on MountingManager instead of SurfaceMountingManager, because we don't
// know what surfaceId it's being called for.
mJSResponderHandler.clearJSResponder();
}

Просмотреть файл

@ -16,6 +16,7 @@ import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
import com.facebook.react.uimanager.StateWrapper;
/** {@link MountItem} that is used to pre-allocate views for JS components. */
@ -53,9 +54,15 @@ public class PreAllocateViewMountItem implements MountItem {
if (ENABLE_FABRIC_LOGS) {
FLog.d(TAG, "Executing pre-allocation of: " + toString());
}
mountingManager
.getSurfaceManagerEnforced(mSurfaceId, "PreAllocateViewMountItem")
.preallocateView(mComponent, mReactTag, mProps, mStateWrapper, mIsLayoutable);
SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(mSurfaceId);
if (surfaceMountingManager == null) {
FLog.e(
TAG,
"Skipping View PreAllocation; no SurfaceMountingManager found for [" + mSurfaceId + "]");
return;
}
surfaceMountingManager.preallocateView(
mComponent, mReactTag, mProps, mStateWrapper, mIsLayoutable);
}
@Override