Fix NullPointerException caused by race condition in ReactInstanceManager.getViewManagerNames method

Summary:
This diff fixes a NullPointerException that is caused when the method ReactInstanceManager.getViewManagerNames is called at the same time ReactInstanceManager is being destroyed.

Following the stacktrace I noticed that this crash can only happen when RN was destroyed by another thread while this method was being executed

This diff fixes the NullPointerException, but it doesn't fix the root cause race condition that cuases this bug

changelog: [Android][Fixed] Fix NullPointerException caused by race condition in ReactInstanceManager.getViewManagerNames method

Reviewed By: JoshuaGross

Differential Revision: D29616401

fbshipit-source-id: 6ae8ecdd765d2fe3529fef3237f08b182d8ed243
This commit is contained in:
David Vacca
2021-07-08 12:09:34 -07:00
committed by Facebook GitHub Bot
parent 8ed4068381
commit fb386fccdd
@@ -918,38 +918,40 @@ public class ReactInstanceManager {
public @Nullable List<String> getViewManagerNames() {
Systrace.beginSection(TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.getViewManagerNames");
if (mViewManagerNames == null) {
ReactApplicationContext context;
synchronized (mReactContextLock) {
context = (ReactApplicationContext) getCurrentReactContext();
if (context == null || !context.hasActiveReactInstance()) {
return null;
}
}
synchronized (mPackages) {
if (mViewManagerNames == null) {
Set<String> uniqueNames = new HashSet<>();
for (ReactPackage reactPackage : mPackages) {
SystraceMessage.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.getViewManagerName")
.arg("Package", reactPackage.getClass().getSimpleName())
.flush();
if (reactPackage instanceof ViewManagerOnDemandReactPackage) {
List<String> names =
((ViewManagerOnDemandReactPackage) reactPackage).getViewManagerNames(context);
if (names != null) {
uniqueNames.addAll(names);
}
}
SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
mViewManagerNames = new ArrayList<>(uniqueNames);
}
List<String> viewManagerNames = mViewManagerNames;
if (viewManagerNames != null) {
return viewManagerNames;
}
ReactApplicationContext context;
synchronized (mReactContextLock) {
context = (ReactApplicationContext) getCurrentReactContext();
if (context == null || !context.hasActiveReactInstance()) {
return null;
}
}
return new ArrayList<>(mViewManagerNames);
synchronized (mPackages) {
if (mViewManagerNames == null) {
Set<String> uniqueNames = new HashSet<>();
for (ReactPackage reactPackage : mPackages) {
SystraceMessage.beginSection(
TRACE_TAG_REACT_JAVA_BRIDGE, "ReactInstanceManager.getViewManagerName")
.arg("Package", reactPackage.getClass().getSimpleName())
.flush();
if (reactPackage instanceof ViewManagerOnDemandReactPackage) {
List<String> names =
((ViewManagerOnDemandReactPackage) reactPackage).getViewManagerNames(context);
if (names != null) {
uniqueNames.addAll(names);
}
}
SystraceMessage.endSection(TRACE_TAG_REACT_JAVA_BRIDGE).flush();
}
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
mViewManagerNames = new ArrayList<>(uniqueNames);
}
return mViewManagerNames;
}
}
/** Add a listener to be notified of react instance events. */