From 5fb0ad0a48c45dbdb8d2a2f06c32029c635e4a9d Mon Sep 17 00:00:00 2001 From: David Vacca Date: Thu, 15 Sep 2022 09:48:25 -0700 Subject: [PATCH] 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 --- .../mountitems/IntBufferBatchMountItem.java | 11 +++ ReactAndroid/src/main/jni/react/fabric/BUCK | 1 + .../src/main/jni/react/fabric/Binding.cpp | 8 ++- .../main/jni/react/fabric/FabricMountItem.h | 1 + .../react/fabric/FabricMountingManager.cpp | 67 ++++++++++++++++++- .../jni/react/fabric/FabricMountingManager.h | 3 + 6 files changed, 86 insertions(+), 5 deletions(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java index 00541d484e5..c6c3396eb79 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/mounting/mountitems/IntBufferBatchMountItem.java @@ -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( diff --git a/ReactAndroid/src/main/jni/react/fabric/BUCK b/ReactAndroid/src/main/jni/react/fabric/BUCK index c9315e08fb2..0a9480be3ee 100644 --- a/ReactAndroid/src/main/jni/react/fabric/BUCK +++ b/ReactAndroid/src/main/jni/react/fabric/BUCK @@ -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"), diff --git a/ReactAndroid/src/main/jni/react/fabric/Binding.cpp b/ReactAndroid/src/main/jni/react/fabric/Binding.cpp index a419fcefc8f..128f5085b9d 100644 --- a/ReactAndroid/src/main/jni/react/fabric/Binding.cpp +++ b/ReactAndroid/src/main/jni/react/fabric/Binding.cpp @@ -382,13 +382,17 @@ void Binding::installFabricUIManager( << this << ")."; } + sharedCppComponentRegistry_ = + std::shared_ptr( + cppComponentRegistry ? cppComponentRegistry : nullptr); + // Use std::lock and std::adopt_lock to prevent deadlocks by locking mutexes // at the same time std::unique_lock lock(installMutex_); auto globalJavaUiManager = make_global(javaUIManager); - mountingManager_ = - std::make_shared(config, globalJavaUiManager); + mountingManager_ = std::make_shared( + config, sharedCppComponentRegistry_, globalJavaUiManager); ContextContainer::Shared contextContainer = std::make_shared(); diff --git a/ReactAndroid/src/main/jni/react/fabric/FabricMountItem.h b/ReactAndroid/src/main/jni/react/fabric/FabricMountItem.h index f9cb4c623e2..adc6ed81b04 100644 --- a/ReactAndroid/src/main/jni/react/fabric/FabricMountItem.h +++ b/ReactAndroid/src/main/jni/react/fabric/FabricMountItem.h @@ -73,6 +73,7 @@ struct CppMountItem final { UpdatePadding = 512, UpdateOverflowInset = 1024, RemoveDeleteTree = 2048, + RunCPPMutations = 4096 }; #pragma mark - Fields diff --git a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp index 69609f862a5..bc584166eb7 100644 --- a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp +++ b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.cpp @@ -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 &config, + std::shared_ptr &cppComponentRegistry, global_ref &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 &cppUpdatePaddingMountItems, std::vector &cppUpdateLayoutMountItems, std::vector &cppUpdateOverflowInsetMountItems, - std::vector &cppUpdateEventEmitterMountItems) { + std::vector &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 cppUpdateLayoutMountItems; std::vector cppUpdateOverflowInsetMountItems; std::vector 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::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( diff --git a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h index ebd95dd8094..b1162d290dc 100644 --- a/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h +++ b/ReactAndroid/src/main/jni/react/fabric/FabricMountingManager.h @@ -7,6 +7,7 @@ #pragma once +#include "CppComponentRegistry.h" #include "FabricMountItem.h" #include @@ -33,6 +34,7 @@ class FabricMountingManager final { FabricMountingManager( std::shared_ptr &config, + std::shared_ptr &cppComponentRegistry, jni::global_ref &javaUIManager); void onSurfaceStart(SurfaceId surfaceId); @@ -68,6 +70,7 @@ class FabricMountingManager final { butter::map> allocatedViewRegistry_{}; std::recursive_mutex allocatedViewsMutex_; + std::shared_ptr cppComponentRegistry_; bool const enableEarlyEventEmitterUpdate_{false}; bool const disablePreallocateViews_{false};