Integrate execution of C++ ViewManagers in React Native Android renderer

Summary:
Execution of C++ ViewManagers in RN Android renderer

changelog: [internal] internal

Reviewed By: sammy-SC

Differential Revision: D38725770

fbshipit-source-id: cd18e02940c4cb2559acdaf535e60f98b4cada13
This commit is contained in:
David Vacca
2022-09-15 09:48:25 -07:00
committed by Facebook GitHub Bot
parent 0519dfeeaf
commit 5fb0ad0a48
6 changed files with 86 additions and 5 deletions
@@ -16,6 +16,7 @@ import com.facebook.common.logging.FLog;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReactMarker;
import com.facebook.react.bridge.ReactMarkerConstants;
import com.facebook.react.fabric.CppViewMutationsWrapper;
import com.facebook.react.fabric.events.EventEmitterWrapper;
import com.facebook.react.fabric.mounting.MountingManager;
import com.facebook.react.fabric.mounting.SurfaceMountingManager;
@@ -50,6 +51,7 @@ public class IntBufferBatchMountItem implements MountItem {
static final int INSTRUCTION_UPDATE_PADDING = 512;
static final int INSTRUCTION_UPDATE_OVERFLOW_INSET = 1024;
static final int INSTRUCTION_REMOVE_DELETE_TREE = 2048;
static final int INSTRUCTION_RUN_CPP_VIEWS = 4096;
private final int mSurfaceId;
private final int mCommitNumber;
@@ -97,6 +99,10 @@ public class IntBufferBatchMountItem implements MountItem {
return obj != null ? (EventEmitterWrapper) obj : null;
}
private static CppViewMutationsWrapper castToCppViewMutationWrapper(Object obj) {
return obj != null ? (CppViewMutationsWrapper) obj : null;
}
@Override
public void execute(@NonNull MountingManager mountingManager) {
SurfaceMountingManager surfaceMountingManager = mountingManager.getSurfaceManager(mSurfaceId);
@@ -178,6 +184,8 @@ public class IntBufferBatchMountItem implements MountItem {
} else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
surfaceMountingManager.updateEventEmitter(
mIntBuffer[i++], castToEventEmitter(mObjBuffer[j++]));
} else if (type == INSTRUCTION_RUN_CPP_VIEWS) {
castToCppViewMutationWrapper(mObjBuffer[j++]).runCppViewMutations();
} else {
throw new IllegalArgumentException(
"Invalid type argument to IntBufferBatchMountItem: " + type + " at index: " + i);
@@ -280,6 +288,9 @@ public class IntBufferBatchMountItem implements MountItem {
} else if (type == INSTRUCTION_UPDATE_EVENT_EMITTER) {
j += 1;
s.append(String.format("UPDATE EVENTEMITTER [%d]\n", mIntBuffer[i++]));
} else if (type == INSTRUCTION_RUN_CPP_VIEWS) {
j += 1;
s.append(String.format("RUN CPP_VIEWS [%d]\n", mIntBuffer[i++]));
} else {
FLog.e(TAG, "String so far: " + s.toString());
throw new IllegalArgumentException(
@@ -24,6 +24,7 @@ rn_xplat_cxx_library(
soname = "libfabricjni.$(ext)",
visibility = ["PUBLIC"],
deps = [
react_native_xplat_target("butter:butter"),
react_native_xplat_target("react/renderer/mapbuffer:mapbuffer"),
react_native_xplat_target("react/config:config"),
react_native_xplat_target("react/renderer/animations:animations"),
@@ -382,13 +382,17 @@ void Binding::installFabricUIManager(
<< this << ").";
}
sharedCppComponentRegistry_ =
std::shared_ptr<const facebook::react::CppComponentRegistry>(
cppComponentRegistry ? cppComponentRegistry : nullptr);
// Use std::lock and std::adopt_lock to prevent deadlocks by locking mutexes
// at the same time
std::unique_lock<butter::shared_mutex> lock(installMutex_);
auto globalJavaUiManager = make_global(javaUIManager);
mountingManager_ =
std::make_shared<FabricMountingManager>(config, globalJavaUiManager);
mountingManager_ = std::make_shared<FabricMountingManager>(
config, sharedCppComponentRegistry_, globalJavaUiManager);
ContextContainer::Shared contextContainer =
std::make_shared<ContextContainer>();
@@ -73,6 +73,7 @@ struct CppMountItem final {
UpdatePadding = 512,
UpdateOverflowInset = 1024,
RemoveDeleteTree = 2048,
RunCPPMutations = 4096
};
#pragma mark - Fields
@@ -6,6 +6,7 @@
*/
#include "FabricMountingManager.h"
#include "CppViewMutationsWrapper.h"
#include "EventEmitterWrapper.h"
#include "StateWrapperImpl.h"
#include "viewPropConversions.h"
@@ -38,8 +39,10 @@ static bool getFeatureFlagValue(const char *name) {
FabricMountingManager::FabricMountingManager(
std::shared_ptr<const ReactNativeConfig> &config,
std::shared_ptr<const CppComponentRegistry> &cppComponentRegistry,
global_ref<jobject> &javaUIManager)
: javaUIManager_(javaUIManager),
cppComponentRegistry_(cppComponentRegistry),
enableEarlyEventEmitterUpdate_(
config->getBool("react_fabric:enable_early_event_emitter_update")),
disablePreallocateViews_(
@@ -82,6 +85,8 @@ static inline int getIntBufferSizeForType(CppMountItem::Type mountItemType) {
return 7; // tag, parentTag, x, y, w, h, DisplayType
case CppMountItem::Type::UpdateOverflowInset:
return 5; // tag, left, top, right, bottom
case CppMountItem::Type::RunCPPMutations:
return 1;
case CppMountItem::Undefined:
case CppMountItem::Multiple:
return -1;
@@ -124,7 +129,8 @@ static inline void computeBufferSizes(
std::vector<CppMountItem> &cppUpdatePaddingMountItems,
std::vector<CppMountItem> &cppUpdateLayoutMountItems,
std::vector<CppMountItem> &cppUpdateOverflowInsetMountItems,
std::vector<CppMountItem> &cppUpdateEventEmitterMountItems) {
std::vector<CppMountItem> &cppUpdateEventEmitterMountItems,
ShadowViewMutationList &cppViewMutations) {
CppMountItem::Type lastType = CppMountItem::Type::Undefined;
int numSameType = 0;
for (auto const &mountItem : cppCommonMountItems) {
@@ -183,6 +189,11 @@ static inline void computeBufferSizes(
cppDeleteMountItems.size(),
batchMountItemIntsSize,
batchMountItemObjectsSize);
if (cppViewMutations.size() > 0) {
batchMountItemIntsSize++;
batchMountItemObjectsSize++;
}
}
static inline void writeIntBufferTypePreamble(
@@ -293,7 +304,7 @@ void FabricMountingManager::executeMount(
std::vector<CppMountItem> cppUpdateLayoutMountItems;
std::vector<CppMountItem> cppUpdateOverflowInsetMountItems;
std::vector<CppMountItem> cppUpdateEventEmitterMountItems;
auto cppViewMutations = ShadowViewMutationList();
{
std::lock_guard allocatedViewsLock(allocatedViewsMutex_);
@@ -318,6 +329,25 @@ void FabricMountingManager::executeMount(
bool isVirtual = mutation.mutatedViewIsVirtual();
// Detect if the mutation instruction belongs to C++ view managers
if (cppComponentRegistry_) {
auto componentName = newChildShadowView.componentName
? newChildShadowView.componentName
: oldChildShadowView.componentName;
auto name = std::string(componentName);
if (cppComponentRegistry_->containsComponentManager(name)) {
// is this thread safe?
cppViewMutations.push_back(mutation);
// This is a hack that could be avoided by using Portals
// Only execute mutations instructions for Root C++ ViewManagers
// because Root C++ Components have a Android view counterpart.
if (!cppComponentRegistry_->isRootComponent(name)) {
continue;
}
}
}
switch (mutationType) {
case ShadowViewMutation::Create: {
bool revisionCheck =
@@ -502,7 +532,8 @@ void FabricMountingManager::executeMount(
cppUpdatePaddingMountItems,
cppUpdateLayoutMountItems,
cppUpdateOverflowInsetMountItems,
cppUpdateEventEmitterMountItems);
cppUpdateEventEmitterMountItems,
cppViewMutations);
static auto createMountItemsIntBufferBatchContainer =
jni::findClassStatic(UIManagerJavaDescriptor)
@@ -809,6 +840,36 @@ void FabricMountingManager::executeMount(
}
}
if (cppViewMutations.size() > 0) {
writeIntBufferTypePreamble(
CppMountItem::Type::RunCPPMutations,
1,
env,
intBufferArray,
intBufferPosition);
// TODO review this logic and memory mamangement
// this might not be necessary:
// temp[0] = 1234;
// env->SetIntArrayRegion(intBufferArray, intBufferPosition, 1, temp);
// intBufferPosition += 1;
// Do not hold a reference to javaCppMutations from the C++ side.
auto javaCppMutations = CppViewMutationsWrapper::newObjectJavaArgs();
CppViewMutationsWrapper *cppViewMutationsWrapper = cthis(javaCppMutations);
// TODO move this to init methods
cppViewMutationsWrapper->cppComponentRegistry = cppComponentRegistry_;
// TODO is moving the cppViewMutations safe / thread safe?
// cppViewMutations will be accessed from the UI Thread in a near future
// can they dissapear?
cppViewMutationsWrapper->cppViewMutations =
std::make_shared<std::vector<facebook::react::ShadowViewMutation>>(
std::move(cppViewMutations));
(*objBufferArray)[objBufferPosition++] = javaCppMutations.get();
}
// If there are no items, we pass a nullptr instead of passing the object
// through the JNI
auto batch = createMountItemsIntBufferBatchContainer(
@@ -7,6 +7,7 @@
#pragma once
#include "CppComponentRegistry.h"
#include "FabricMountItem.h"
#include <react/config/ReactNativeConfig.h>
@@ -33,6 +34,7 @@ class FabricMountingManager final {
FabricMountingManager(
std::shared_ptr<const ReactNativeConfig> &config,
std::shared_ptr<const CppComponentRegistry> &cppComponentRegistry,
jni::global_ref<jobject> &javaUIManager);
void onSurfaceStart(SurfaceId surfaceId);
@@ -68,6 +70,7 @@ class FabricMountingManager final {
butter::map<SurfaceId, butter::set<Tag>> allocatedViewRegistry_{};
std::recursive_mutex allocatedViewsMutex_;
std::shared_ptr<const CppComponentRegistry> cppComponentRegistry_;
bool const enableEarlyEventEmitterUpdate_{false};
bool const disablePreallocateViews_{false};