diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/bindings/BindingsInstaller.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/bindings/BindingsInstaller.h new file mode 100644 index 00000000000..df87b259a49 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/bindings/BindingsInstaller.h @@ -0,0 +1,26 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include + +#include +#include + +namespace facebook { +namespace react { + +class BindingsInstaller { + public: + ReactInstance::BindingsInstallFunc getBindingsInstallFunc() { + auto installBindings = [](jsi::Runtime &runtime) { + jsi::installQPLBindings(runtime); + jsi::installUserFlowBindings(runtime); + }; + return installBindings; + } +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/.clang-tidy b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/.clang-tidy new file mode 100644 index 00000000000..f80a6058031 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/.clang-tidy @@ -0,0 +1,20 @@ +--- +Checks: ' +*, +-cert-err60-cpp, +-cppcoreguidelines-pro-bounds-pointer-arithmetic, +-cppcoreguidelines-special-member-functions, +-cppcoreguidelines-pro-type-const-cast, +-fuchsia-default-arguments-calls, +-fuchsia-multiple-inheritance, +-google-readability-casting, +-google-runtime-int, +-google-runtime-references, +-hicpp-special-member-functions, +-llvm-header-guard, +-misc-non-private-member-variables-in-classes, +-misc-unused-parameters, +-modernize-use-trailing-return-type, +-performance-unnecessary-value-param +' +... diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp new file mode 100644 index 00000000000..9c91ae0749e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.cpp @@ -0,0 +1,27 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "JHermesInstance.h" + +#include + +namespace facebook { +namespace react { + +jni::local_ref JHermesInstance::initHybrid( + jni::alias_ref) { + return makeCxxInstance(); +} + +void JHermesInstance::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JHermesInstance::initHybrid), + }); +} + +std::unique_ptr JHermesInstance::createJSRuntime() noexcept { + // TODO T105438175 Pass ReactNativeConfig to init Hermes with MobileConfig + return HermesInstance::createJSRuntime(); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h new file mode 100644 index 00000000000..8f972c6e7a1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/JHermesInstance.h @@ -0,0 +1,37 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include "../../jni/JJSEngineInstance.h" + +namespace facebook { +namespace react { + +class JHermesInstance + : public jni::HybridClass { + public: + static constexpr auto kJavaDescriptor = + "Lcom/facebook/venice/hermes/HermesInstance;"; + + static jni::local_ref initHybrid(jni::alias_ref); + + static void registerNatives(); + + std::unique_ptr createJSRuntime() noexcept; + + ~JHermesInstance() {} + + private: + friend HybridBase; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/OnLoad.cpp new file mode 100644 index 00000000000..5113866fa02 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/hermes/jni/OnLoad.cpp @@ -0,0 +1,11 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include +#include + +#include "JHermesInstance.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { + return facebook::xplat::initialize( + vm, [] { facebook::react::JHermesInstance::registerNatives(); }); +} diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/.clang-tidy b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/.clang-tidy new file mode 100644 index 00000000000..f80a6058031 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/.clang-tidy @@ -0,0 +1,20 @@ +--- +Checks: ' +*, +-cert-err60-cpp, +-cppcoreguidelines-pro-bounds-pointer-arithmetic, +-cppcoreguidelines-special-member-functions, +-cppcoreguidelines-pro-type-const-cast, +-fuchsia-default-arguments-calls, +-fuchsia-multiple-inheritance, +-google-readability-casting, +-google-runtime-int, +-google-runtime-references, +-hicpp-special-member-functions, +-llvm-header-guard, +-misc-non-private-member-variables-in-classes, +-misc-unused-parameters, +-modernize-use-trailing-return-type, +-performance-unnecessary-value-param +' +... diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessJSCallInvoker.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessJSCallInvoker.cpp new file mode 100644 index 00000000000..ab153845db3 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessJSCallInvoker.cpp @@ -0,0 +1,26 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "BridgelessJSCallInvoker.h" + +#include +#include + +namespace facebook { +namespace react { + +BridgelessJSCallInvoker::BridgelessJSCallInvoker( + RuntimeExecutor runtimeExecutor) + : runtimeExecutor_(std::move(runtimeExecutor)) {} + +void BridgelessJSCallInvoker::invokeAsync(std::function &&func) { + runtimeExecutor_([func = std::move(func)](jsi::Runtime &runtime) { func(); }); +} + +void BridgelessJSCallInvoker::invokeSync(std::function &&func) { + // TODO: Replace JS Callinvoker with RuntimeExecutor. + throw std::runtime_error( + "Synchronous native -> JS calls are currently not supported."); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessJSCallInvoker.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessJSCallInvoker.h new file mode 100644 index 00000000000..6c2edef10d1 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessJSCallInvoker.h @@ -0,0 +1,25 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include +#include + +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class BridgelessJSCallInvoker : public CallInvoker { + public: + explicit BridgelessJSCallInvoker(RuntimeExecutor runtimeExecutor); + void invokeAsync(std::function &&func) override; + void invokeSync(std::function &&func) override; + + private: + RuntimeExecutor runtimeExecutor_; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessNativeCallInvoker.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessNativeCallInvoker.cpp new file mode 100644 index 00000000000..6631d972708 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessNativeCallInvoker.cpp @@ -0,0 +1,24 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "BridgelessNativeCallInvoker.h" + +#include +#include + +namespace facebook { +namespace react { + +BridgelessNativeCallInvoker::BridgelessNativeCallInvoker( + std::shared_ptr messageQueueThread) + : messageQueueThread_(std::move(messageQueueThread)) {} + +void BridgelessNativeCallInvoker::invokeAsync(std::function &&func) { + messageQueueThread_->runOnQueue(std::move(func)); +} + +void BridgelessNativeCallInvoker::invokeSync(std::function &&func) { + messageQueueThread_->runOnQueueSync(std::move(func)); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessNativeCallInvoker.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessNativeCallInvoker.h new file mode 100644 index 00000000000..3974bc0dec6 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/BridgelessNativeCallInvoker.h @@ -0,0 +1,27 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include +#include + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class BridgelessNativeCallInvoker : public CallInvoker { + public: + explicit BridgelessNativeCallInvoker( + std::shared_ptr messageQueueThread); + void invokeAsync(std::function &&func) override; + void invokeSync(std::function &&func) override; + + private: + std::shared_ptr messageQueueThread_; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h new file mode 100644 index 00000000000..14cdcc7109e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSEngineInstance.h @@ -0,0 +1,24 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include +#include + +namespace facebook { + +namespace react { + +class JJSEngineInstance : public jni::HybridClass, + public JSEngineInstance { + public: + static auto constexpr kJavaDescriptor = + "Lcom/facebook/venice/JSEngineInstance;"; + + private: + friend HybridBase; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp new file mode 100644 index 00000000000..9ff68ea5327 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.cpp @@ -0,0 +1,32 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "JJSTimerExecutor.h" + +#include +#include + +namespace facebook { +namespace react { + +void JJSTimerExecutor::setTimerManager( + std::weak_ptr timerManager) { + assert(timerManager && "`timerManager` must not be `nullptr`."); + timerManager_ = timerManager; +} + +void JJSTimerExecutor::callTimers(WritableNativeArray *timerIDs) { + if (auto timerManager = timerManager_.lock()) { + for (const auto &timerID : timerIDs->consume()) { + timerManager->callTimer((uint32_t)timerID.asInt()); + } + } +} + +void JJSTimerExecutor::registerNatives() { + registerHybrid({ + makeNativeMethod("callTimers", JJSTimerExecutor::callTimers), + }); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h new file mode 100644 index 00000000000..3356432c99a --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJSTimerExecutor.h @@ -0,0 +1,34 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include +#include +#include +#include + +namespace facebook { +namespace react { + +class JJSTimerExecutor : public jni::HybridClass { + public: + JJSTimerExecutor() = default; + + constexpr static auto kJavaDescriptor = + "Lcom/facebook/venice/JSTimerExecutor;"; + + static void registerNatives(); + + void setTimerManager(std::weak_ptr timerManager); + + void callTimers(WritableNativeArray *timerIDs); + + private: + friend HybridBase; + + std::weak_ptr timerManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp new file mode 100644 index 00000000000..ab96d19d096 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.cpp @@ -0,0 +1,27 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "JJavaTimerManager.h" + +#include +#include + +namespace facebook { +namespace react { + +void JJavaTimerManager::createTimer( + uint32_t timerID, + double duration, + bool repeat) { + static const auto method = + javaClassStatic()->getMethod("createTimer"); + method(self(), timerID, (long)duration, static_cast(repeat)); +} + +void JJavaTimerManager::deleteTimer(uint32_t timerID) { + static const auto method = + javaClassStatic()->getMethod("deleteTimer"); + method(self(), timerID); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h new file mode 100644 index 00000000000..e8692e65d75 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JJavaTimerManager.h @@ -0,0 +1,23 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include + +#include +#include + +namespace facebook { +namespace react { + +struct JJavaTimerManager : jni::JavaClass { + static auto constexpr kJavaDescriptor = + "Lcom/facebook/react/modules/core/JavaTimerManager;"; + + void createTimer(uint32_t timerID, double duration, bool repeat); + + void deleteTimer(uint32_t timerID); +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp new file mode 100644 index 00000000000..bcc7940833e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.cpp @@ -0,0 +1,23 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "JReactExceptionManager.h" +#include +#include +#include +#include + +namespace facebook { +namespace react { + +void JReactExceptionManager::reportJsException( + const JReadableMapBuffer::javaobject errorMapBuffer) { + static const auto method = + javaClassStatic()->getMethod( + "reportJsException"); + if (self() != nullptr) { + method(self(), errorMapBuffer); + } +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h new file mode 100644 index 00000000000..2d5886010f6 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactExceptionManager.h @@ -0,0 +1,22 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include +#include + +namespace facebook { +namespace react { + +class JReactExceptionManager + : public facebook::jni::JavaClass { + public: + static auto constexpr kJavaDescriptor = + "Lcom/facebook/venice/exceptionmanager/ReactJsExceptionHandler;"; + + void reportJsException(const JReadableMapBuffer::javaobject errorMapBuffer); +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp new file mode 100644 index 00000000000..dde2e3ed80b --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.cpp @@ -0,0 +1,228 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "JReactInstance.h" + +#ifdef WITH_FBSYSTRACE +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "BridgelessJSCallInvoker.h" +#include "BridgelessNativeCallInvoker.h" +#include "JavaTimerRegistry.h" + +namespace facebook { +namespace react { + +JReactInstance::JReactInstance( + jni::alias_ref jsEngineInstance, + jni::alias_ref jsMessageQueueThread, + jni::alias_ref nativeMessageQueueThread, + jni::alias_ref javaTimerManager, + jni::alias_ref jsTimerExecutor, + jni::alias_ref jReactExceptionManager, + bool isProfiling) noexcept { + // TODO(janzer): Lazily create runtime + auto sharedJSMessageQueueThread = + std::make_shared(jsMessageQueueThread); + auto sharedNativeMessageQueueThread = + std::make_shared(nativeMessageQueueThread); + + // Create the timer manager (for JS timers) + auto timerRegistry = + std::make_unique(jni::make_global(javaTimerManager)); + auto timerManager = std::make_shared(std::move(timerRegistry)); + jsTimerExecutor->cthis()->setTimerManager(timerManager); + + // Create the instance + std::unique_ptr bindingsInstaller = + std::make_unique(); + + jReactExceptionManager_ = jni::make_global(jReactExceptionManager); + auto jsErrorHandlingFunc = [this](MapBuffer errorMap) noexcept { + if (jReactExceptionManager_ != nullptr) { + auto jErrorMap = + JReadableMapBuffer::createWithContents(std::move(errorMap)); + jReactExceptionManager_->reportJsException(jErrorMap.get()); + } + }; + + instance_ = std::make_unique( + jsEngineInstance->cthis()->createJSRuntime(), + sharedJSMessageQueueThread, + timerManager, + std::move(jsErrorHandlingFunc)); + auto appBindingInstaller = bindingsInstaller->getBindingsInstallFunc(); + + auto bufferedRuntimeExecutor = instance_->getBufferedRuntimeExecutor(); + timerManager->setRuntimeExecutor(bufferedRuntimeExecutor); + + ReactInstance::JSRuntimeFlags options = {.isProfiling = isProfiling}; + instance_->initializeRuntime( + options, + [appBindingInstaller, instance = instance_.get()](jsi::Runtime &runtime) { + react::Logger androidLogger = + static_cast( + &reactAndroidLoggingHook); + react::bindNativeLogger(runtime, androidLogger); + appBindingInstaller(runtime); + }); + + auto unbufferedRuntimeExecutor = instance_->getUnbufferedRuntimeExecutor(); + // Set up the JS and native modules call invokers (for TurboModules) + auto jsInvoker = + std::make_unique(unbufferedRuntimeExecutor); + jsCallInvokerHolder_ = jni::make_global( + CallInvokerHolder::newObjectCxxArgs(std::move(jsInvoker))); + auto nativeInvoker = std::make_unique( + sharedNativeMessageQueueThread); + nativeCallInvokerHolder_ = jni::make_global( + CallInvokerHolder::newObjectCxxArgs(std::move(nativeInvoker))); + + // Storing this here to make sure the Java reference doesn't get destroyed + unbufferedRuntimeExecutor_ = jni::make_global( + JRuntimeExecutor::newObjectCxxArgs(unbufferedRuntimeExecutor)); + bufferedRuntimeExecutor_ = jni::make_global( + JRuntimeExecutor::newObjectCxxArgs(bufferedRuntimeExecutor)); + runtimeScheduler_ = jni::make_global( + JRuntimeScheduler::newObjectCxxArgs(instance_->getRuntimeScheduler())); +} + +jni::local_ref JReactInstance::initHybrid( + jni::alias_ref /* unused */, + jni::alias_ref jsEngineInstance, + jni::alias_ref jsMessageQueueThread, + jni::alias_ref nativeMessageQueueThread, + jni::alias_ref javaTimerManager, + jni::alias_ref jsTimerExecutor, + jni::alias_ref jReactExceptionManager, + bool isProfiling) { + return makeCxxInstance( + jsEngineInstance, + jsMessageQueueThread, + nativeMessageQueueThread, + javaTimerManager, + jsTimerExecutor, + jReactExceptionManager, + isProfiling); +} + +void JReactInstance::loadJSBundleFromAssets( + jni::alias_ref assetManager, + const std::string &assetURL) { + const int kAssetsLength = 9; // strlen("assets://"); + auto sourceURL = assetURL.substr(kAssetsLength); + + auto manager = extractAssetManager(assetManager); + auto script = loadScriptFromAssets(manager, sourceURL); + instance_->loadScript(std::move(script), sourceURL); +} + +void JReactInstance::loadJSBundleFromFile( + const std::string &fileName, + const std::string &sourceURL) { + std::unique_ptr script; + RecoverableError::runRethrowingAsRecoverable( + [&fileName, &script]() { script = JSBigFileString::fromPath(fileName); }); + instance_->loadScript(std::move(script), sourceURL); +} + +/** + * This is needed to initialize TurboModules; in the future this will be + * replaced with something similar to runtimeExecutor, which we'll use for + * Fabric as well. + * TODO T44251068 Replace with runtimeExecutor + */ +jni::alias_ref +JReactInstance::getJSCallInvokerHolder() { + return jsCallInvokerHolder_; +} + +jni::alias_ref +JReactInstance::getNativeCallInvokerHolder() { + return nativeCallInvokerHolder_; +} + +jni::global_ref +JReactInstance::createJSTimerExecutor( + jni::alias_ref /* unused */) { + return jni::make_global(JJSTimerExecutor::newObjectCxxArgs()); +} + +void JReactInstance::callFunctionOnModule( + const std::string &moduleName, + const std::string &methodName, + NativeArray *args) { + instance_->callFunctionOnModule(moduleName, methodName, args->consume()); +} + +jni::alias_ref +JReactInstance::getUnbufferedRuntimeExecutor() noexcept { + return unbufferedRuntimeExecutor_; +} + +jni::alias_ref +JReactInstance::getBufferedRuntimeExecutor() noexcept { + return bufferedRuntimeExecutor_; +} + +jni::alias_ref +JReactInstance::getRuntimeScheduler() noexcept { + return runtimeScheduler_; +} + +void JReactInstance::registerSegment( + int segmentId, + const std::string &segmentPath) noexcept { + instance_->registerSegment((uint32_t)segmentId, segmentPath); +} + +void JReactInstance::handleMemoryPressureJs(jint level) { + instance_->handleMemoryPressureJs(level); +} + +void JReactInstance::registerNatives() { + registerHybrid({ + makeNativeMethod("initHybrid", JReactInstance::initHybrid), + makeNativeMethod( + "createJSTimerExecutor", JReactInstance::createJSTimerExecutor), + makeNativeMethod( + "loadJSBundleFromAssets", JReactInstance::loadJSBundleFromAssets), + makeNativeMethod( + "loadJSBundleFromFile", JReactInstance::loadJSBundleFromFile), + makeNativeMethod( + "getJSCallInvokerHolder", JReactInstance::getJSCallInvokerHolder), + makeNativeMethod( + "getNativeCallInvokerHolder", + JReactInstance::getNativeCallInvokerHolder), + makeNativeMethod( + "callFunctionOnModule", JReactInstance::callFunctionOnModule), + makeNativeMethod( + "getUnbufferedRuntimeExecutor", + JReactInstance::getUnbufferedRuntimeExecutor), + makeNativeMethod( + "getBufferedRuntimeExecutor", + JReactInstance::getBufferedRuntimeExecutor), + makeNativeMethod( + "getRuntimeScheduler", JReactInstance::getRuntimeScheduler), + + makeNativeMethod( + "registerSegmentNative", JReactInstance::registerSegment), + makeNativeMethod( + "handleMemoryPressureJs", JReactInstance::handleMemoryPressureJs), + }); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h new file mode 100644 index 00000000000..049c2dc1f21 --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JReactInstance.h @@ -0,0 +1,99 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "JJSEngineInstance.h" +#include "JJSTimerExecutor.h" +#include "JJavaTimerManager.h" +#include "JReactExceptionManager.h" + +namespace facebook { +namespace react { + +class JReactInstance : public jni::HybridClass { + public: + constexpr static auto kJavaDescriptor = "Lcom/facebook/venice/ReactInstance;"; + + static jni::local_ref initHybrid( + jni::alias_ref, + jni::alias_ref jsEngineInstance, + jni::alias_ref jsMessageQueueThread, + jni::alias_ref + nativeMessageQueueThread, + jni::alias_ref javaTimerManager, + jni::alias_ref jsTimerExecutor, + jni::alias_ref jReactExceptionManager, + bool isProfiling); + + /* + * Instantiates and returns an instance of `JSTimerExecutor`. + */ + static jni::global_ref createJSTimerExecutor( + jni::alias_ref /* unused */); + + static void registerNatives(); + + void loadJSBundleFromAssets( + jni::alias_ref assetManager, + const std::string &assetURL); + + void loadJSBundleFromFile( + const std::string &fileName, + const std::string &sourceURL); + + void callFunctionOnModule( + const std::string &moduleName, + const std::string &methodName, + NativeArray *args); + + jni::alias_ref + getUnbufferedRuntimeExecutor() noexcept; + jni::alias_ref + getBufferedRuntimeExecutor() noexcept; + jni::alias_ref getRuntimeScheduler() noexcept; + + void registerSegment(int segmentId, const std::string &segmentPath) noexcept; + + void handleMemoryPressureJs(jint level); + + private: + friend HybridBase; + + explicit JReactInstance( + jni::alias_ref jsEngineInstance, + jni::alias_ref jsMessageQueueThread, + jni::alias_ref + nativeMessageQueueThread, + jni::alias_ref javaTimerManager, + jni::alias_ref jsTimerExecutor, + jni::alias_ref jReactExceptionManager, + bool isProfiling) noexcept; + + jni::alias_ref getJSCallInvokerHolder(); + jni::alias_ref getNativeCallInvokerHolder(); + + std::unique_ptr instance_; + jni::global_ref unbufferedRuntimeExecutor_; + jni::global_ref bufferedRuntimeExecutor_; + jni::global_ref runtimeScheduler_; + jni::global_ref jsCallInvokerHolder_; + jni::global_ref nativeCallInvokerHolder_; + jni::global_ref jReactExceptionManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp new file mode 100644 index 00000000000..5ff658f1b1e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.cpp @@ -0,0 +1,25 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include "JavaTimerRegistry.h" + +namespace facebook { +namespace react { + +JavaTimerRegistry::JavaTimerRegistry( + jni::global_ref javaTimerManager) + : javaTimerManager_(javaTimerManager) {} + +void JavaTimerRegistry::createTimer(uint32_t timerID, double delayMS) { + javaTimerManager_->createTimer(timerID, delayMS, /* repeat */ false); +} + +void JavaTimerRegistry::createRecurringTimer(uint32_t timerID, double delayMS) { + javaTimerManager_->createTimer(timerID, delayMS, /* repeat */ true); +} + +void JavaTimerRegistry::deleteTimer(uint32_t timerID) { + javaTimerManager_->deleteTimer(timerID); +} + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h new file mode 100644 index 00000000000..b55d16ea55e --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/JavaTimerRegistry.h @@ -0,0 +1,35 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#pragma once + +#include + +#include +#include + +#include "JJavaTimerManager.h" + +namespace facebook { +namespace react { + +/** + * Call into JavaTimerManager.java to schedule and delete timers + * with the Platform. + */ +class JavaTimerRegistry : public PlatformTimerRegistry { + public: + JavaTimerRegistry( + jni::global_ref javaTimerManager); + +#pragma mark - PlatformTimerRegistry + + void createTimer(uint32_t timerID, double delayMS) override; + void createRecurringTimer(uint32_t timerID, double delayMS) override; + void deleteTimer(uint32_t timerID) override; + + private: + jni::global_ref javaTimerManager_; +}; + +} // namespace react +} // namespace facebook diff --git a/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/OnLoad.cpp b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/OnLoad.cpp new file mode 100644 index 00000000000..920be178f9c --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/jni/react/bridgeless/jni/OnLoad.cpp @@ -0,0 +1,16 @@ +// (c) Meta Platforms, Inc. and affiliates. Confidential and proprietary. + +#include +#include +#include + +#include "JJSTimerExecutor.h" +#include "JReactInstance.h" + +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void * /*unused*/) { + return facebook::xplat::initialize(vm, [] { + facebook::react::JReactMarker::setLogPerfMarkerIfNeeded(); + facebook::react::JReactInstance::registerNatives(); + facebook::react::JJSTimerExecutor::registerNatives(); + }); +}