From cba205b82c11cfbff03a728db9aa9654bee95c01 Mon Sep 17 00:00:00 2001 From: Ramanpreet Nara Date: Fri, 3 May 2019 13:25:56 -0700 Subject: [PATCH] Introduce TurboModuleManagerDelegate Summary: `TurboModuleManagerDelegate` is an abstract base class with the following API: ``` public TurboModule getModule(String name, ReactApplicationContext reactApplicationContext); public CxxModuleWrapper getLegacyCxxModule(String name, ReactApplicationContext reactApplicationContext); ``` ``` std::shared_ptr getTurboModule(std::string name, jni::global_ref turboModule, std::shared_ptr jsInvoker) override; std::shared_ptr getTurboModule(std::string name, std::shared_ptr jsInvoker) override; ``` On the C++ side, when asked to provide a TurboModule with name `name`: 1. First, is this a CxxModule? If so: 1. Create the CxxModule and return 2. Otherwise: 1. Somehow get a Java instance of the TurboModule 2. If this Java object represents a CxxModule, like `FbReactLibSodiumModule`: 1. Grab the C++ part of this object, and wrap it in a `TurboCxxModule.cpp` and return. 3. Otherwise: 1. Wrap the Java object in a C++ HostObject and return. This pseudocode demonstrates how we'd use `TurboModuleManagerDelegate` to implement `__turboModuleProxy`. ``` __turboModuleProxy(name, jsCallInvoker): let cxxModule = TurboModuleManagerDelegate::getTurboModule(name, jsCallInvoker) if (!cxxModule) { return cxxModule; } // JNI Call that forwards to TurboModuleManagerDelegate.getLegacyCxxModule let javaCxxModule : CxxModuleWrapper = TurboModuleManager.getLegacyCxxModule(name) if (!javaCxxModule) { return std::shared_ptr(javaCxxModule.getModule()) } // JNI Call that forwards to TurboModuleManagerDelegate.getModule let javaModule : TurboModule = TurboModuleManager.getModule(name) if (!javaCxxModule) { return TurboModuleManagerDelegate::getTurboModule(name, javaModule, jsCallInvoker) } return null ``` Reviewed By: mdvacca Differential Revision: D15111335 fbshipit-source-id: c7b0aeda0e4565e3a2729e7f9604775782b6f893 --- .../turbomodule/core/TurboModuleManager.java | 20 +++----- .../core/TurboModuleManagerDelegate.java | 49 +++++++++++++++++++ .../facebook/react/turbomodule/core/jni/BUCK | 24 ++------- .../react/turbomodule/core/jni/OnLoad.cpp | 13 +++++ .../core/jni/TurboModuleManager.cpp | 23 +++++---- .../turbomodule/core/jni/TurboModuleManager.h | 12 ++--- .../core/jni/TurboModuleManagerDelegate.h | 31 ++++++++++++ ReactCommon/jscallinvoker/BUCK | 5 +- 8 files changed, 123 insertions(+), 54 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java create mode 100644 ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/OnLoad.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManagerDelegate.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java index 77a1c21bc..9264db4f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManager.java @@ -27,41 +27,37 @@ public class TurboModuleManager implements JSIModule { } private final ReactApplicationContext mReactApplicationContext; + private final TurboModuleManagerDelegate mTurbomoduleManagerDelegate; @DoNotStrip @SuppressWarnings("unused") private final HybridData mHybridData; - private final ModuleProvider mModuleProvider; public TurboModuleManager( - ReactApplicationContext reactApplicationContext, JavaScriptContextHolder jsContext, ModuleProvider moduleProvider) { + ReactApplicationContext reactApplicationContext, JavaScriptContextHolder jsContext, TurboModuleManagerDelegate tmmDelegate) { mReactApplicationContext = reactApplicationContext; JSCallInvokerHolderImpl instanceHolder = (JSCallInvokerHolderImpl) mReactApplicationContext .getCatalystInstance() .getJSCallInvokerHolder(); - mHybridData = initHybrid(jsContext.get(), instanceHolder); - mModuleProvider = moduleProvider; + mHybridData = initHybrid(jsContext.get(), instanceHolder, tmmDelegate); + mTurbomoduleManagerDelegate = tmmDelegate; } @DoNotStrip @SuppressWarnings("unused") - protected TurboModule getJavaModule(String name) { - return mModuleProvider.getModule(name, mReactApplicationContext); + private TurboModule getJavaModule(String name) { + return mTurbomoduleManagerDelegate.getModule(name); } - protected native HybridData initHybrid(long jsContext, JSCallInvokerHolderImpl jsQueue); + private native HybridData initHybrid(long jsContext, JSCallInvokerHolderImpl jsQueue, TurboModuleManagerDelegate tmmDelegate); - protected native void installJSIBindings(); + private native void installJSIBindings(); public void installBindings() { installJSIBindings(); } - protected ReactApplicationContext getReactApplicationContext() { - return mReactApplicationContext; - } - @Override public void initialize() {} diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java new file mode 100644 index 000000000..eabeae276 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/TurboModuleManagerDelegate.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +package com.facebook.react.turbomodule.core; + +import com.facebook.jni.HybridData; +import com.facebook.react.bridge.CxxModuleWrapper; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.turbomodule.core.interfaces.TurboModule; +import com.facebook.soloader.SoLoader; +import javax.annotation.Nullable; + +public abstract class TurboModuleManagerDelegate { + static { + SoLoader.loadLibrary("turbomodulejsijni"); + } + + private final HybridData mHybridData; + private final ReactApplicationContext mReactApplicationContext; + + protected abstract HybridData initHybrid(); + + protected TurboModuleManagerDelegate(ReactApplicationContext rac) { + mHybridData = initHybrid(); + mReactApplicationContext = rac; + } + + protected ReactApplicationContext getReactApplicationContext() { + return mReactApplicationContext; + } + + /** + * Create and return a TurboModule Java object with name `moduleName`. + * If `moduleName` isn't a TurboModule, return null. + */ + @Nullable + public abstract TurboModule getModule(String moduleName); + + /** + * Create an return a CxxModuleWrapper NativeModule with name `moduleName`. + * If `moduleName` isn't a CxxModule, return null. + */ + @Nullable + public abstract CxxModuleWrapper getLegacyCxxModule(String moduleName); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/BUCK b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/BUCK index d6ad08ba8..0b255a2e1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/BUCK @@ -2,24 +2,14 @@ load("@fbsource//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "FBJNI_TARGET", " rn_xplat_cxx_library( name = "jni", - platforms = ANDROID, - preferred_linkage = "static", - visibility = [ - "PUBLIC", - ], - exported_deps = [ - ":turbomodulemanager", - ], -) - -rn_xplat_cxx_library( - name = "turbomodulemanager", srcs = [ + "OnLoad.cpp", "TurboModuleManager.cpp", ], header_namespace = "", exported_headers = { "jsireact/TurboModuleManager.h": "TurboModuleManager.h", + "jsireact/TurboModuleManagerDelegate.h": "TurboModuleManagerDelegate.h", }, compiler_flags = [ "-fexceptions", @@ -28,23 +18,20 @@ rn_xplat_cxx_library( "-Wall", ], platforms = ANDROID, - preferred_linkage = "static", preprocessor_flags = [ "-DLOG_TAG=\"ReactNative\"", "-DWITH_FBSYSTRACE=1", ], + soname = "libturbomodulejsijni.$(ext)", visibility = [ "PUBLIC", ], deps = [ react_native_target("jni/react/jni:jni"), - "fbsource//xplat/jsi:JSIDynamic", - "fbsource//xplat/jsi:jsi", - ":jscallinvokerholder", ], exported_deps = [ "fbsource//xplat/jsi:jsi", - react_native_xplat_target("cxxreact:bridge"), + ":jscallinvokerholder", react_native_xplat_target("turbomodule/core:core"), ], ) @@ -76,9 +63,6 @@ rn_xplat_cxx_library( visibility = [ "PUBLIC", ], - deps = [ - react_native_xplat_target("cxxreact:bridge"), - ], exported_deps = [ react_native_xplat_target("jscallinvoker:jscallinvoker"), ], diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/OnLoad.cpp b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/OnLoad.cpp new file mode 100644 index 000000000..034511e87 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/OnLoad.cpp @@ -0,0 +1,13 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include + +#include "TurboModuleManager.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::xplat::initialize(vm, [] { + // TODO: dvacca ramanpreet unify this with the way "ComponentDescriptorFactory" is defined in Fabric + facebook::react::TurboModuleManager::registerNatives(); + }); +} diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.cpp b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.cpp index ca9844826..8cfa6621a 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.cpp @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -21,26 +20,27 @@ namespace facebook { namespace react { -static JTurboModuleProviderFunctionType moduleProvider_ = nullptr; - TurboModuleManager::TurboModuleManager( jni::alias_ref jThis, jsi::Runtime* rt, - std::shared_ptr jsCallInvoker + std::shared_ptr jsCallInvoker, + jni::alias_ref tmmDelegate ): javaPart_(jni::make_global(jThis)), runtime_(rt), - jsCallInvoker_(jsCallInvoker) + jsCallInvoker_(jsCallInvoker), + turboModuleManagerDelegate_(jni::make_global(tmmDelegate)) {} jni::local_ref TurboModuleManager::initHybrid( jni::alias_ref jThis, jlong jsContext, - jni::alias_ref jsCallInvokerHolder + jni::alias_ref jsCallInvokerHolder, + jni::alias_ref tmmDelegate ) { auto jsCallInvoker = jsCallInvokerHolder->cthis()->getJSCallInvoker(); - return makeCxxInstance(jThis, (jsi::Runtime *) jsContext, jsCallInvoker); + return makeCxxInstance(jThis, (jsi::Runtime *) jsContext, jsCallInvoker, tmmDelegate); } void TurboModuleManager::registerNatives() { @@ -57,18 +57,17 @@ void TurboModuleManager::installJSIBindings() { TurboModuleBinding::install(*runtime_, std::make_shared( [this](const std::string &name) { const auto moduleInstance = getJavaModule(name); - return moduleProvider_(name, moduleInstance, jsCallInvoker_); + return turboModuleManagerDelegate_->cthis()->getTurboModule(name, moduleInstance, jsCallInvoker_); }) ); } jni::global_ref TurboModuleManager::getJavaModule(std::string name) { static auto method = javaClassStatic()->getMethod(const std::string&)>("getJavaModule"); - return make_global(method(javaPart_.get(), name)); -} -void TurboModuleManager::setModuleProvider(JTurboModuleProviderFunctionType fn) { - moduleProvider_ = fn; + auto module = jni::make_global(method(javaPart_.get(), name)); + + return module; } } // namespace react diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.h b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.h index 34cd1194d..305b3b185 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.h +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManager.h @@ -14,35 +14,35 @@ #include #include #include +#include namespace facebook { namespace react { -using JTurboModuleProviderFunctionType = std::function( - const std::string &name, jni::global_ref moduleInstance, std::shared_ptr jsInvoker)>; - class TurboModuleManager : public jni::HybridClass { public: static auto constexpr kJavaDescriptor = "Lcom/facebook/react/turbomodule/core/TurboModuleManager;"; static jni::local_ref initHybrid( jni::alias_ref jThis, jlong jsContext, - jni::alias_ref jsCallInvokerHolder + jni::alias_ref jsCallInvokerHolder, + jni::alias_ref tmmDelegate ); static void registerNatives(); - static void setModuleProvider(JTurboModuleProviderFunctionType moduleProvider); private: friend HybridBase; jni::global_ref javaPart_; jsi::Runtime* runtime_; std::shared_ptr jsCallInvoker_; + jni::global_ref turboModuleManagerDelegate_; jni::global_ref getJavaModule(std::string name); void installJSIBindings(); explicit TurboModuleManager( jni::alias_ref jThis, jsi::Runtime *rt, - std::shared_ptr jsCallInvoker + std::shared_ptr jsCallInvoker, + jni::alias_ref tmmDelegate ); }; diff --git a/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManagerDelegate.h b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManagerDelegate.h new file mode 100644 index 000000000..fbd469082 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/turbomodule/core/jni/TurboModuleManagerDelegate.h @@ -0,0 +1,31 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class TurboModuleManagerDelegate : public jni::HybridClass { +public: + static auto constexpr kJavaDescriptor = "Lcom/facebook/react/turbomodule/core/TurboModuleManagerDelegate;"; + + virtual std::shared_ptr getTurboModule(std::string name, jni::global_ref turboModule, std::shared_ptr jsInvoker) = 0; + virtual std::shared_ptr getTurboModule(std::string name, std::shared_ptr jsInvoker) = 0; + +private: + friend HybridBase; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/jscallinvoker/BUCK b/ReactCommon/jscallinvoker/BUCK index 085dbab1a..068eadab5 100644 --- a/ReactCommon/jscallinvoker/BUCK +++ b/ReactCommon/jscallinvoker/BUCK @@ -1,4 +1,4 @@ -load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "FBJNI_TARGET", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") +load("//tools/build_defs/oss:rn_defs.bzl", "ANDROID", "APPLE", "react_native_xplat_target", "rn_xplat_cxx_library", "subdir_glob") rn_xplat_cxx_library( name = "jscallinvoker", @@ -18,9 +18,6 @@ rn_xplat_cxx_library( "-std=c++14", "-Wall", ], - fbandroid_deps = [ - FBJNI_TARGET, - ], platforms = (ANDROID, APPLE), preferred_linkage = "static", preprocessor_flags = [