diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.java b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.java deleted file mode 100644 index 361af5448d7..00000000000 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.java +++ /dev/null @@ -1,480 +0,0 @@ -/* - * 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. - */ - -package com.facebook.react.internal.turbomodule.core; - -import androidx.annotation.GuardedBy; -import androidx.annotation.Nullable; -import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; -import com.facebook.infer.annotation.Nullsafe; -import com.facebook.jni.HybridData; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.CxxModuleWrapper; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.RuntimeExecutor; -import com.facebook.react.internal.turbomodule.core.interfaces.TurboModuleRegistry; -import com.facebook.react.turbomodule.core.CallInvokerHolderImpl; -import com.facebook.react.turbomodule.core.NativeMethodCallInvokerHolderImpl; -import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder; -import com.facebook.react.turbomodule.core.interfaces.NativeMethodCallInvokerHolder; -import com.facebook.react.turbomodule.core.interfaces.TurboModule; -import com.facebook.soloader.SoLoader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * This is the main class and entry point for TurboModules. Note that this is a hybrid class, and - * has a C++ counterpart This class installs the JSI bindings. It also implements the method to get - * a Java module, that the C++ counterpart calls. - */ -@Nullsafe(Nullsafe.Mode.LOCAL) -public class TurboModuleManager implements TurboModuleRegistry { - private static final String TAG = "TurboModuleManager"; - - private final List mEagerInitModuleNames; - private final ModuleProvider mTurboModuleProvider; - private final ModuleProvider mLegacyModuleProvider; - private final @Nullable TurboModuleManagerDelegate mDelegate; - - static { - SoLoader.loadLibrary("turbomodulejsijni"); - } - - // Prevents the creation of new TurboModules once cleanup as been initiated. - private final Object mModuleCleanupLock = new Object(); - - @GuardedBy("mModuleCleanupLock") - private boolean mModuleCleanupStarted = false; - - // List of TurboModules that have been, or are currently being, instantiated - @GuardedBy("mModuleCleanupLock") - private final Map mModuleHolders = new HashMap<>(); - - @DoNotStrip - @SuppressWarnings("unused") - private final HybridData mHybridData; - - public TurboModuleManager( - RuntimeExecutor runtimeExecutor, - @Nullable final TurboModuleManagerDelegate delegate, - CallInvokerHolder jsCallInvokerHolder, - NativeMethodCallInvokerHolder nativeMethodCallInvokerHolder) { - mDelegate = delegate; - mHybridData = - initHybrid( - runtimeExecutor, - (CallInvokerHolderImpl) jsCallInvokerHolder, - (NativeMethodCallInvokerHolderImpl) nativeMethodCallInvokerHolder, - delegate); - installJSIBindings(shouldEnableLegacyModuleInterop()); - - mEagerInitModuleNames = - delegate == null ? Collections.emptyList() : delegate.getEagerInitModuleNames(); - - ModuleProvider nullProvider = moduleName -> null; - - mTurboModuleProvider = - delegate == null - ? nullProvider - : moduleName -> (NativeModule) delegate.getModule(moduleName); - - mLegacyModuleProvider = - delegate == null || !shouldEnableLegacyModuleInterop() - ? nullProvider - : moduleName -> { - NativeModule nativeModule = delegate.getLegacyModule(moduleName); - if (nativeModule != null) { - // TurboModuleManagerDelegate.getLegacyModule must never return a TurboModule - Assertions.assertCondition( - !(nativeModule instanceof TurboModule), - "NativeModule \"" + moduleName + "\" is a TurboModule"); - return nativeModule; - } - return null; - }; - } - - private boolean isTurboModule(String moduleName) { - return mDelegate != null && mDelegate.unstable_isModuleRegistered(moduleName); - } - - private boolean isLegacyModule(String moduleName) { - return mDelegate != null && mDelegate.unstable_isLegacyModuleRegistered(moduleName); - } - - private boolean shouldEnableLegacyModuleInterop() { - return mDelegate != null && mDelegate.unstable_shouldEnableLegacyModuleInterop(); - } - - @Override - public List getEagerInitModuleNames() { - return mEagerInitModuleNames; - } - - // used from TurboModuleManager.cpp - @SuppressWarnings("unused") - @DoNotStrip - private static List getMethodDescriptorsFromModule( - NativeModule module) { - return TurboModuleInteropUtils.getMethodDescriptorsFromModule(module); - } - - // used from TurboModuleManager.cpp - @SuppressWarnings("unused") - @DoNotStrip - @Nullable - private NativeModule getLegacyJavaModule(String moduleName) { - /* - * This API is invoked from global.nativeModuleProxy. - * Only call getModule if the native module is a legacy module. - */ - if (!isLegacyModule(moduleName)) { - return null; - } - - final NativeModule module = getModule(moduleName); - return !(module instanceof CxxModuleWrapper) && !(module instanceof TurboModule) - ? module - : null; - } - - // used from TurboModuleManager.cpp - @SuppressWarnings("unused") - @DoNotStrip - @Nullable - private CxxModuleWrapper getLegacyCxxModule(String moduleName) { - /* - * This API is invoked from global.nativeModuleProxy. - * Only call getModule if the native module is a legacy module. - */ - if (!isLegacyModule(moduleName)) { - return null; - } - - final NativeModule module = getModule(moduleName); - return module instanceof CxxModuleWrapper && !(module instanceof TurboModule) - ? (CxxModuleWrapper) module - : null; - } - - // used from TurboModuleManager.cpp - @SuppressWarnings("unused") - @DoNotStrip - @Nullable - private CxxModuleWrapper getTurboLegacyCxxModule(String moduleName) { - /* - * This API is invoked from global.__turboModuleProxy. - * Only call getModule if the native module is a turbo module. - */ - if (!isTurboModule(moduleName)) { - return null; - } - - final NativeModule module = getModule(moduleName); - return module instanceof CxxModuleWrapper && module instanceof TurboModule - ? (CxxModuleWrapper) module - : null; - } - - // used from TurboModuleManager.cpp - @SuppressWarnings("unused") - @DoNotStrip - @Nullable - private TurboModule getTurboJavaModule(String moduleName) { - /* - * This API is invoked from global.__turboModuleProxy. - * Only call getModule if the native module is a turbo module. - */ - if (!isTurboModule(moduleName)) { - return null; - } - - final NativeModule module = getModule(moduleName); - return !(module instanceof CxxModuleWrapper) && module instanceof TurboModule - ? (TurboModule) module - : null; - } - - /** - * Return the NativeModule instance that corresponds to the provided moduleName. - * - *

This method: - Creates and initializes the module if it doesn't already exist. - Returns - * null after TurboModuleManager has been torn down. - */ - @Nullable - public NativeModule getModule(String moduleName) { - ModuleHolder moduleHolder; - - synchronized (mModuleCleanupLock) { - if (mModuleCleanupStarted) { - /* - * Always return null after cleanup has started, so that getNativeModule(moduleName) returns null. - */ - FLog.e( - TAG, - "getModule(): Tried to get module \"%s\", but TurboModuleManager was tearing down" - + " (legacy: %b, turbo: %b)", - moduleName, - isLegacyModule(moduleName), - isTurboModule(moduleName)); - return null; - } - - /* - * TODO(T64619790): Should we populate mModuleHolders ahead of time, to avoid having - * * to control concurrent access to it? - */ - if (!mModuleHolders.containsKey(moduleName)) { - mModuleHolders.put(moduleName, new ModuleHolder()); - } - - moduleHolder = mModuleHolders.get(moduleName); - } - - if (moduleHolder == null) { - FLog.e(TAG, "getModule(): Tried to get module \"%s\", but moduleHolder was null", moduleName); - return null; - } - - TurboModulePerfLogger.moduleCreateStart(moduleName, moduleHolder.getModuleId()); - NativeModule module = getOrCreateModule(moduleName, moduleHolder, true); - - if (module != null) { - TurboModulePerfLogger.moduleCreateEnd(moduleName, moduleHolder.getModuleId()); - } else { - TurboModulePerfLogger.moduleCreateFail(moduleName, moduleHolder.getModuleId()); - } - - return module; - } - - /** - * Given a ModuleHolder, and the TurboModule's moduleName, return the TurboModule instance. - * - *

Use the ModuleHolder to ensure that if n threads race to create TurboModule x, then only the - * first thread creates x. All n - 1 other threads wait until the x is created and initialized. - */ - @Nullable - private NativeModule getOrCreateModule( - String moduleName, ModuleHolder moduleHolder, boolean shouldPerfLog) { - boolean shouldCreateModule = false; - - synchronized (moduleHolder) { - if (moduleHolder.isDoneCreatingModule()) { - if (shouldPerfLog) { - TurboModulePerfLogger.moduleCreateCacheHit(moduleName, moduleHolder.getModuleId()); - } - - return moduleHolder.getModule(); - } - - if (!moduleHolder.isCreatingModule()) { - // Only one thread gets here - shouldCreateModule = true; - moduleHolder.startCreatingModule(); - } - } - - if (shouldCreateModule) { - TurboModulePerfLogger.moduleCreateConstructStart(moduleName, moduleHolder.getModuleId()); - NativeModule nativeModule = mTurboModuleProvider.getModule(moduleName); - - if (nativeModule == null) { - nativeModule = mLegacyModuleProvider.getModule(moduleName); - } - - TurboModulePerfLogger.moduleCreateConstructEnd(moduleName, moduleHolder.getModuleId()); - TurboModulePerfLogger.moduleCreateSetUpStart(moduleName, moduleHolder.getModuleId()); - - if (nativeModule != null) { - synchronized (moduleHolder) { - moduleHolder.setModule(nativeModule); - } - - /* - * TurboModuleManager is initialized after ReactApplicationContext has been set up. - * NativeModules should be initialized after ReactApplicationContext has been set up. - * Therefore, we should initialize on the TurboModule now. - */ - nativeModule.initialize(); - } else { - FLog.e( - TAG, - "getOrCreateModule(): Unable to create module \"%s\" (legacy: %b, turbo: %b)", - moduleName, - isLegacyModule(moduleName), - isTurboModule(moduleName)); - } - - TurboModulePerfLogger.moduleCreateSetUpEnd(moduleName, moduleHolder.getModuleId()); - synchronized (moduleHolder) { - moduleHolder.endCreatingModule(); - moduleHolder.notifyAll(); - } - - return nativeModule; - } - - synchronized (moduleHolder) { - boolean wasInterrupted = false; - while (moduleHolder.isCreatingModule()) { - try { - // Wait until TurboModule is created and initialized - moduleHolder.wait(); - } catch (InterruptedException e) { - wasInterrupted = true; - } - } - - if (wasInterrupted) { - /* - * TurboModules should ideally be quick to create and initialize. Therefore, - * we wait until the TurboModule is done initializing before re-interrupting the - * current thread. - */ - Thread.currentThread().interrupt(); - } - - return moduleHolder.getModule(); - } - } - - /** Which NativeModules have been created? */ - public Collection getModules() { - final List moduleHolders = new ArrayList<>(); - synchronized (mModuleCleanupLock) { - moduleHolders.addAll(mModuleHolders.values()); - } - - final List modules = new ArrayList<>(); - for (final ModuleHolder moduleHolder : moduleHolders) { - synchronized (moduleHolder) { - // No need to wait for the TurboModule to finish being created and initialized - if (moduleHolder.getModule() != null) { - modules.add(moduleHolder.getModule()); - } - } - } - - return modules; - } - - public boolean hasModule(String moduleName) { - ModuleHolder moduleHolder; - synchronized (mModuleCleanupLock) { - moduleHolder = mModuleHolders.get(moduleName); - } - - if (moduleHolder != null) { - synchronized (moduleHolder) { - if (moduleHolder.getModule() != null) { - return true; - } - } - } - - return false; - } - - private native HybridData initHybrid( - RuntimeExecutor runtimeExecutor, - CallInvokerHolderImpl jsCallInvokerHolder, - NativeMethodCallInvokerHolderImpl nativeMethodCallInvoker, - @Nullable TurboModuleManagerDelegate tmmDelegate); - - private native void installJSIBindings(boolean shouldCreateLegacyModules); - - @Override - public void invalidate() { - /* - * Halt the production of new TurboModules. - * - *

After this point, mModuleHolders will not be accessed by TurboModuleManager. - * Therefore, it won't be modified. - * - *

The ModuleHolders in mModuleHolders, however, can still be populated with newly - * created TurboModules. - */ - synchronized (mModuleCleanupLock) { - mModuleCleanupStarted = true; - } - - for (final Map.Entry moduleHolderEntry : mModuleHolders.entrySet()) { - final String moduleName = moduleHolderEntry.getKey(); - final ModuleHolder moduleHolder = moduleHolderEntry.getValue(); - - /** - * ReactNative could start tearing down before this particular TurboModule has been fully - * initialized. In this case, we should wait for initialization to complete, before destroying - * the TurboModule. - */ - final NativeModule nativeModule = getOrCreateModule(moduleName, moduleHolder, false); - - if (nativeModule != null) { - nativeModule.invalidate(); - } - } - - mModuleHolders.clear(); - - // Delete the native part of this hybrid class. - mHybridData.resetNative(); - } - - private static class ModuleHolder { - private volatile @Nullable NativeModule mModule = null; - private volatile boolean mIsTryingToCreate = false; - private volatile boolean mIsDoneCreatingModule = false; - private static volatile int sHolderCount = 0; - private volatile int mModuleId; - - public ModuleHolder() { - mModuleId = sHolderCount; - sHolderCount += 1; - } - - int getModuleId() { - return mModuleId; - } - - void setModule(NativeModule module) { - mModule = module; - } - - @Nullable - NativeModule getModule() { - return mModule; - } - - void startCreatingModule() { - mIsTryingToCreate = true; - } - - void endCreatingModule() { - mIsTryingToCreate = false; - mIsDoneCreatingModule = true; - } - - boolean isDoneCreatingModule() { - return mIsDoneCreatingModule; - } - - boolean isCreatingModule() { - return mIsTryingToCreate; - } - } - - private interface ModuleProvider { - @Nullable - NativeModule getModule(String name); - } -} diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt new file mode 100644 index 00000000000..b7ae3fed8af --- /dev/null +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/internal/turbomodule/core/TurboModuleManager.kt @@ -0,0 +1,405 @@ +/* + * 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. + */ + +package com.facebook.react.internal.turbomodule.core + +import androidx.annotation.GuardedBy +import com.facebook.common.logging.FLog +import com.facebook.jni.HybridData +import com.facebook.proguard.annotations.DoNotStrip +import com.facebook.react.bridge.CxxModuleWrapper +import com.facebook.react.bridge.NativeModule +import com.facebook.react.bridge.RuntimeExecutor +import com.facebook.react.common.annotations.FrameworkAPI +import com.facebook.react.internal.turbomodule.core.interfaces.TurboModuleRegistry +import com.facebook.react.turbomodule.core.CallInvokerHolderImpl +import com.facebook.react.turbomodule.core.NativeMethodCallInvokerHolderImpl +import com.facebook.react.turbomodule.core.interfaces.CallInvokerHolder +import com.facebook.react.turbomodule.core.interfaces.NativeMethodCallInvokerHolder +import com.facebook.react.turbomodule.core.interfaces.TurboModule +import com.facebook.soloader.SoLoader +import kotlin.concurrent.Volatile + +/** + * This is the main class and entry point for TurboModules. Note that this is a hybrid class, and + * has a C++ counterpart This class installs the JSI bindings. It also implements the method to get + * a Java module, that the C++ counterpart calls. + */ +@OptIn(FrameworkAPI::class) +public class TurboModuleManager( + runtimeExecutor: RuntimeExecutor, + private val delegate: TurboModuleManagerDelegate?, + jsCallInvokerHolder: CallInvokerHolder, + nativeMethodCallInvokerHolder: NativeMethodCallInvokerHolder +) : TurboModuleRegistry { + + public override val eagerInitModuleNames: List + private val turboModuleProvider: ModuleProvider + private val legacyModuleProvider: ModuleProvider + + // Prevents the creation of new TurboModules once cleanup as been initiated. + private val moduleCleanupLock = Object() + + @GuardedBy("moduleCleanupLock") private var moduleCleanupStarted = false + + // List of TurboModules that have been, or are currently being, instantiated + @GuardedBy("moduleCleanupLock") private val moduleHolders = mutableMapOf() + + @Suppress("NoHungarianNotation") + @DoNotStrip + private val mHybridData: HybridData = + initHybrid( + runtimeExecutor, + jsCallInvokerHolder as CallInvokerHolderImpl, + nativeMethodCallInvokerHolder as NativeMethodCallInvokerHolderImpl, + delegate) + + init { + + installJSIBindings(shouldEnableLegacyModuleInterop()) + + eagerInitModuleNames = delegate?.eagerInitModuleNames ?: emptyList() + + val nullProvider: ModuleProvider = ModuleProvider { _: String -> null } + + turboModuleProvider = + if (delegate == null) nullProvider + else + ModuleProvider { moduleName: String -> delegate.getModule(moduleName) as NativeModule? } + + legacyModuleProvider = + if (delegate == null || !shouldEnableLegacyModuleInterop()) nullProvider + else + ModuleProvider { moduleName: String -> + val nativeModule = delegate.getLegacyModule(moduleName) + if (nativeModule != null) { + // TurboModuleManagerDelegate.getLegacyModule must never return a TurboModule + require(nativeModule !is TurboModule) { + "NativeModule \"$moduleName\" is a TurboModule" + } + return@ModuleProvider nativeModule + } + null + } + } + + private fun isTurboModule(moduleName: String): Boolean = + delegate?.unstable_isModuleRegistered(moduleName) == true + + private fun isLegacyModule(moduleName: String): Boolean = + delegate?.unstable_isLegacyModuleRegistered(moduleName) == true + + private fun shouldEnableLegacyModuleInterop(): Boolean = + delegate?.unstable_shouldEnableLegacyModuleInterop() == true + + // used from TurboModuleManager.cpp + @Suppress("unused") + @DoNotStrip + private fun getLegacyJavaModule(moduleName: String): NativeModule? { + /* + * This API is invoked from global.nativeModuleProxy. + * Only call getModule if the native module is a legacy module. + */ + if (!isLegacyModule(moduleName)) { + return null + } + + val module = getModule(moduleName) + return if (module !is CxxModuleWrapper && module !is TurboModule) module else null + } + + // used from TurboModuleManager.cpp + @Suppress("unused") + @DoNotStrip + private fun getLegacyCxxModule(moduleName: String): CxxModuleWrapper? { + /* + * This API is invoked from global.nativeModuleProxy. + * Only call getModule if the native module is a legacy module. + */ + if (!isLegacyModule(moduleName)) { + return null + } + + val module = getModule(moduleName) + return if (module is CxxModuleWrapper && module !is TurboModule) module else null + } + + // used from TurboModuleManager.cpp + @Suppress("unused") + @DoNotStrip + private fun getTurboLegacyCxxModule(moduleName: String): CxxModuleWrapper? { + /* + * This API is invoked from global.__turboModuleProxy. + * Only call getModule if the native module is a turbo module. + */ + if (!isTurboModule(moduleName)) { + return null + } + + val module = getModule(moduleName) + return if (module is CxxModuleWrapper && module is TurboModule) module else null + } + + // used from TurboModuleManager.cpp + @Suppress("unused") + @DoNotStrip + private fun getTurboJavaModule(moduleName: String): TurboModule? { + /* + * This API is invoked from global.__turboModuleProxy. + * Only call getModule if the native module is a turbo module. + */ + if (!isTurboModule(moduleName)) { + return null + } + + val module = getModule(moduleName) + return if (module !is CxxModuleWrapper && module is TurboModule) module else null + } + + /** + * Return the NativeModule instance that corresponds to the provided moduleName. + * + * This method: - Creates and initializes the module if it doesn't already exist. - Returns null + * after TurboModuleManager has been torn down. + */ + override fun getModule(moduleName: String): NativeModule? { + val moduleHolder: ModuleHolder? + + synchronized(moduleCleanupLock) { + if (moduleCleanupStarted) { + /* + * Always return null after cleanup has started, so that getNativeModule(moduleName) returns null. + */ + FLog.e( + TAG, + "getModule(): Tried to get module \"%s\", but TurboModuleManager was tearing down (legacy: %b, turbo: %b)", + moduleName, + isLegacyModule(moduleName), + isTurboModule(moduleName)) + return null + } + /* + * TODO(T64619790): Should we populate moduleHolders ahead of time, to avoid having + * * to control concurrent access to it? + */ + if (!moduleHolders.containsKey(moduleName)) { + moduleHolders[moduleName] = ModuleHolder() + } + moduleHolder = moduleHolders[moduleName] + } + + if (moduleHolder == null) { + FLog.e(TAG, "getModule(): Tried to get module \"%s\", but moduleHolder was null", moduleName) + return null + } + + TurboModulePerfLogger.moduleCreateStart(moduleName, moduleHolder.moduleId) + val module = getOrCreateModule(moduleName, moduleHolder, true) + + if (module != null) { + TurboModulePerfLogger.moduleCreateEnd(moduleName, moduleHolder.moduleId) + } else { + TurboModulePerfLogger.moduleCreateFail(moduleName, moduleHolder.moduleId) + } + + return module + } + + /** + * Given a ModuleHolder, and the TurboModule's moduleName, return the TurboModule instance. + * + * Use the ModuleHolder to ensure that if n threads race to create TurboModule x, then only the + * first thread creates x. All n - 1 other threads wait until the x is created and initialized. + */ + private fun getOrCreateModule( + moduleName: String, + moduleHolder: ModuleHolder, + shouldPerfLog: Boolean + ): NativeModule? { + var shouldCreateModule = false + + synchronized(moduleHolder) { + if (moduleHolder.isDoneCreatingModule) { + if (shouldPerfLog) { + TurboModulePerfLogger.moduleCreateCacheHit(moduleName, moduleHolder.moduleId) + } + + return moduleHolder.module + } + if (!moduleHolder.isCreatingModule) { + // Only one thread gets here + shouldCreateModule = true + moduleHolder.startCreatingModule() + } + } + + if (shouldCreateModule) { + TurboModulePerfLogger.moduleCreateConstructStart(moduleName, moduleHolder.moduleId) + var nativeModule = turboModuleProvider.getModule(moduleName) + + if (nativeModule == null) { + nativeModule = legacyModuleProvider.getModule(moduleName) + } + + TurboModulePerfLogger.moduleCreateConstructEnd(moduleName, moduleHolder.moduleId) + TurboModulePerfLogger.moduleCreateSetUpStart(moduleName, moduleHolder.moduleId) + + if (nativeModule != null) { + synchronized(moduleHolder) { moduleHolder.module = nativeModule } + + /* + * TurboModuleManager is initialized after ReactApplicationContext has been set up. + * NativeModules should be initialized after ReactApplicationContext has been set up. + * Therefore, we should initialize on the TurboModule now. + */ + nativeModule.initialize() + } else { + FLog.e( + TAG, + "getOrCreateModule(): Unable to create module \"%s\" (legacy: %b, turbo: %b)", + moduleName, + isLegacyModule(moduleName), + isTurboModule(moduleName)) + } + + TurboModulePerfLogger.moduleCreateSetUpEnd(moduleName, moduleHolder.moduleId) + synchronized(moduleHolder) { + moduleHolder.endCreatingModule() + (moduleHolder as Object).notifyAll() + } + + return nativeModule + } + + synchronized(moduleHolder) { + var wasInterrupted = false + while (moduleHolder.isCreatingModule) { + try { + // Wait until TurboModule is created and initialized + (moduleHolder as Object).wait() + } catch (e: InterruptedException) { + wasInterrupted = true + } + } + + if (wasInterrupted) { + /* + * TurboModules should ideally be quick to create and initialize. Therefore, + * we wait until the TurboModule is done initializing before re-interrupting the + * current thread. + */ + Thread.currentThread().interrupt() + } + return moduleHolder.module + } + } + + public override val modules: Collection + get() { + val holders = synchronized(moduleCleanupLock) { this.moduleHolders.values.toList() } + val moduleList = holders.mapNotNull { holder -> synchronized(holders) { holder.module } } + return moduleList + } + + override fun hasModule(moduleName: String): Boolean { + val moduleHolder = synchronized(moduleCleanupLock) { moduleHolders[moduleName] ?: return false } + return synchronized(moduleHolder) { moduleHolder.module != null } + } + + private external fun initHybrid( + runtimeExecutor: RuntimeExecutor, + jsCallInvokerHolder: CallInvokerHolderImpl, + nativeMethodCallInvoker: NativeMethodCallInvokerHolderImpl, + tmmDelegate: TurboModuleManagerDelegate? + ): HybridData + + private external fun installJSIBindings(shouldCreateLegacyModules: Boolean) + + override fun invalidate() { + /* + * Halt the production of new TurboModules. + * + *

After this point, mModuleHolders will not be accessed by TurboModuleManager. + * Therefore, it won't be modified. + * + *

The ModuleHolders in mModuleHolders, however, can still be populated with newly + * created TurboModules. + */ + synchronized(moduleCleanupLock) { moduleCleanupStarted = true } + + for ((moduleName, moduleHolder) in moduleHolders) { + /** + * ReactNative could start tearing down before this particular TurboModule has been fully + * initialized. In this case, we should wait for initialization to complete, before destroying + * the TurboModule. + */ + val nativeModule = getOrCreateModule(moduleName, moduleHolder, false) + + nativeModule?.invalidate() + } + + moduleHolders.clear() + + // Delete the native part of this hybrid class. + mHybridData.resetNative() + } + + private class ModuleHolder { + @Volatile var module: NativeModule? = null + + @Volatile + var isCreatingModule: Boolean = false + private set + + @Volatile + var isDoneCreatingModule: Boolean = false + private set + + @Volatile + var moduleId: Int + private set + + init { + moduleId = holderCount + holderCount += 1 + } + + fun startCreatingModule() { + isCreatingModule = true + } + + fun endCreatingModule() { + isCreatingModule = false + isDoneCreatingModule = true + } + + companion object { + @Volatile private var holderCount = 0 + } + } + + private fun interface ModuleProvider { + fun getModule(name: String): NativeModule? + } + + public companion object { + private const val TAG = "TurboModuleManager" + + init { + SoLoader.loadLibrary("turbomodulejsijni") + } + + // used from TurboModuleManager.cpp + @JvmStatic + @Suppress("unused") + @DoNotStrip + private fun getMethodDescriptorsFromModule( + module: NativeModule + ): List = + TurboModuleInteropUtils.getMethodDescriptorsFromModule(module) + } +}