From 178691226394d092d32fd6f98a2a24d9ec6a1dca Mon Sep 17 00:00:00 2001 From: Nicola Corti Date: Thu, 3 Apr 2025 06:49:59 -0700 Subject: [PATCH] Decouple NativeMap and NativeArray from `reactnativejni` (#50437) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/50437 Currently we do have `NativeArray`, `NativeMap` being tightly coupled with the old arch (i.e. everything inside `libreactnativejni.so`). Those classes however are primitives used also by the New Arch and they should be accessible even without the bridge infra. I've noticed this dependency while working on the Legacy Arch warnings. Here I'm refactoring those primitives to live in a separate `libreactnativejni_common` module that can be loaded indipendently. Changelog: [Internal] [Changed] - Decouple NativeMap and NativeArray from `reactnativejni` Reviewed By: javache, mdvacca Differential Revision: D71635967 fbshipit-source-id: 64b0fc26491977a0e6c5be4688ff91969c81d680 --- .../ReactAndroid/api/ReactAndroid.api | 1 + .../facebook/react/bridge/DynamicNative.kt | 7 +++ .../com/facebook/react/bridge/NativeArray.kt | 3 +- .../com/facebook/react/bridge/NativeMap.kt | 3 +- .../soloader/OpenSourceMergedSoMapping.kt | 4 ++ .../ReactAndroid/src/main/jni/CMakeLists.txt | 2 + .../src/main/jni/react/jni/CMakeLists.txt | 53 ++++++++++++++++++- .../src/main/jni/react/jni/OnLoad-common.cpp | 31 +++++++++++ .../src/main/jni/react/jni/OnLoad.cpp | 13 ----- 9 files changed, 100 insertions(+), 17 deletions(-) create mode 100644 packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp diff --git a/packages/react-native/ReactAndroid/api/ReactAndroid.api b/packages/react-native/ReactAndroid/api/ReactAndroid.api index b3945ca0e88..b214bb12af9 100644 --- a/packages/react-native/ReactAndroid/api/ReactAndroid.api +++ b/packages/react-native/ReactAndroid/api/ReactAndroid.api @@ -3554,6 +3554,7 @@ public final class com/facebook/react/soloader/OpenSourceMergedSoMapping : com/f public final fun libreact_newarchdefaults_so ()I public final fun libreactnative_so ()I public final fun libreactnativeblob_so ()I + public final fun libreactnativejni_common_so ()I public final fun libreactnativejni_so ()I public final fun librninstance_so ()I public final fun libturbomodulejsijni_so ()I diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/DynamicNative.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/DynamicNative.kt index 7418ce37d4e..e8ceb6dc500 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/DynamicNative.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/DynamicNative.kt @@ -9,6 +9,7 @@ package com.facebook.react.bridge import com.facebook.jni.HybridClassBase import com.facebook.proguard.annotations.DoNotStripAny +import com.facebook.soloader.SoLoader /** * An implementation of [Dynamic] that has a C++ implementation. @@ -45,4 +46,10 @@ private class DynamicNative : HybridClassBase(), Dynamic { override fun recycle() { // Noop - nothing to recycle since there is no pooling } + + private companion object { + init { + SoLoader.loadLibrary("reactnativejni_common") + } + } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArray.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArray.kt index 937759a8723..e75ce7964d5 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArray.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeArray.kt @@ -9,6 +9,7 @@ package com.facebook.react.bridge import com.facebook.jni.HybridClassBase import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.soloader.SoLoader /** Base class for an array whose members are stored in native code (C++). */ @DoNotStrip @@ -19,7 +20,7 @@ public abstract class NativeArray protected constructor() : private companion object { init { - BridgeSoLoader.staticInit() + SoLoader.loadLibrary("reactnativejni_common") } } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeMap.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeMap.kt index 16dfdcadc7d..22bed164f52 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeMap.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeMap.kt @@ -9,6 +9,7 @@ package com.facebook.react.bridge import com.facebook.jni.HybridClassBase import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.soloader.SoLoader /** Base class for a Map whose keys and values are stored in native code (C++). */ @DoNotStrip @@ -17,7 +18,7 @@ public abstract class NativeMap : HybridClassBase() { private companion object { init { - BridgeSoLoader.staticInit() + SoLoader.loadLibrary("reactnativejni_common") } } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt index 6ad54b64b05..f12130841bc 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/soloader/OpenSourceMergedSoMapping.kt @@ -30,6 +30,7 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping { "react_newarchdefaults", "reactnativeblob", "reactnativejni", + "reactnativejni_common", "rninstance", "turbomodulejsijni", "uimanagerjni", @@ -68,6 +69,7 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping { "reactnative" -> libreactnative_so() "reactnativeblob" -> libreactnativeblob_so() "reactnativejni" -> libreactnativejni_so() + "reactnativejni_common" -> libreactnativejni_common_so() "rninstance" -> librninstance_so() "turbomodulejsijni" -> libturbomodulejsijni_so() "uimanagerjni" -> libuimanagerjni_so() @@ -109,6 +111,8 @@ public object OpenSourceMergedSoMapping : ExternalSoMapping { public external fun libreactnativejni_so(): Int + public external fun libreactnativejni_common_so(): Int + public external fun librninstance_so(): Int public external fun libturbomodulejsijni_so(): Int diff --git a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt index 7727ee5e344..ff601b74ae0 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/CMakeLists.txt @@ -214,6 +214,7 @@ add_library(reactnative $ $ $ + $ $ $ $ @@ -303,6 +304,7 @@ target_include_directories(reactnative $ $ $ + $ $ $ $ diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt index c905899cf14..5840cc97050 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/CMakeLists.txt @@ -8,7 +8,37 @@ set(CMAKE_VERBOSE_MAKEFILE on) include(${REACT_COMMON_DIR}/cmake-utils/react-native-flags.cmake) -file(GLOB reactnativejni_SRC CONFIGURE_DEPENDS *.cpp) + +file(GLOB reactnativejni_common_SRC CONFIGURE_DEPENDS *.cpp) + +############################# +### reactnativejni_common ### +############################# + +# This library contains the code from reactnativejni that is used by both old and new +# arch so it can be built in a separate library. + +include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-utils.cmake) + +add_library( + reactnativejni_common + OBJECT + JDynamicNative.cpp + NativeArray.cpp + NativeCommon.cpp + NativeMap.cpp + OnLoad-common.cpp + ReadableNativeArray.cpp + ReadableNativeMap.cpp + WritableNativeArray.cpp + WritableNativeMap.cpp +) +target_merge_so(reactnativejni_common) +target_include_directories(reactnativejni_common PUBLIC ../../) + +target_link_libraries(reactnativejni_common fbjni folly_runtime) +target_compile_reactnative_options(reactnativejni_common PRIVATE) +target_compile_options(reactnativejni_common PRIVATE -Wno-unused-lambda-capture) ###################### ### reactnativejni ### @@ -19,7 +49,25 @@ include(${REACT_ANDROID_DIR}/src/main/jni/first-party/jni-lib-merge/SoMerging-ut add_library( reactnativejni OBJECT - ${reactnativejni_SRC} + CatalystInstanceImpl.cpp + InspectorNetworkRequestListener.cpp + JExecutor.cpp + JInspector.cpp + JMessageQueueThread.cpp + JReactCxxErrorHandler.cpp + JReactMarker.cpp + JReactSoftExceptionLogger.cpp + JRuntimeExecutor.cpp + JRuntimeScheduler.cpp + JSLoader.cpp + JSLogging.cpp + JavaModuleWrapper.cpp + JniJSModulesUnbundle.cpp + MethodInvoker.cpp + ModuleRegistryBuilder.cpp + OnLoad.cpp + ReactInstanceManagerInspectorTarget.cpp + SafeReleaseJniRef.cpp ) target_merge_so(reactnativejni) @@ -35,6 +83,7 @@ target_link_libraries(reactnativejni logger react_cxxreact react_renderer_runtimescheduler + reactnativejni_common runtimeexecutor yoga ) diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp new file mode 100644 index 00000000000..a72b4dffcb1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad-common.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include "JCallback.h" +#include "JDynamicNative.h" +#include "NativeArray.h" +#include "NativeMap.h" +#include "WritableNativeArray.h" +#include "WritableNativeMap.h" + +namespace facebook::react { + +extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { + return facebook::jni::initialize(vm, [] { + JCxxCallbackImpl::registerNatives(); + JDynamicNative::registerNatives(); + NativeArray::registerNatives(); + NativeMap::registerNatives(); + ReadableNativeArray::registerNatives(); + ReadableNativeMap::registerNatives(); + WritableNativeArray::registerNatives(); + WritableNativeMap::registerNatives(); + }); +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp index ccc8f6bd4da..42b66bc3df2 100644 --- a/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ b/packages/react-native/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp @@ -15,14 +15,10 @@ #include "CatalystInstanceImpl.h" #include "CxxModuleWrapperBase.h" #include "InspectorNetworkRequestListener.h" -#include "JCallback.h" -#include "JDynamicNative.h" #include "JInspector.h" #include "JReactMarker.h" #include "JavaScriptExecutorHolder.h" #include "ReactInstanceManagerInspectorTarget.h" -#include "WritableNativeArray.h" -#include "WritableNativeMap.h" #ifndef WITH_GLOGINIT #define WITH_GLOGINIT 1 @@ -44,17 +40,8 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { gloginit::initialize(); FLAGS_minloglevel = 0; #endif - CatalystInstanceImpl::registerNatives(); CxxModuleWrapperBase::registerNatives(); - JCxxCallbackImpl::registerNatives(); - NativeArray::registerNatives(); - ReadableNativeArray::registerNatives(); - WritableNativeArray::registerNatives(); - NativeMap::registerNatives(); - ReadableNativeMap::registerNatives(); - WritableNativeMap::registerNatives(); - JDynamicNative::registerNatives(); JReactMarker::registerNatives(); JInspector::registerNatives(); ReactInstanceManagerInspectorTarget::registerNatives();