diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK index 98b21685a..6f4d57fa6 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/BUCK @@ -13,6 +13,7 @@ android_library( react_native_dep('third-party/java/testing-support-lib:runner'), react_native_target('java/com/facebook/react/bridge:bridge'), react_native_target('java/com/facebook/react/common:common'), + react_native_target('java/com/facebook/react/cxxbridge:bridge'), react_native_target('java/com/facebook/react/devsupport:devsupport'), react_native_target('java/com/facebook/react/modules/core:core'), react_native_target('java/com/facebook/react/modules/debug:debug'), diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java index 37f0a4db3..e3799fda8 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactAppTestActivity.java @@ -25,7 +25,6 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.LifecycleState; import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; import com.facebook.react.ReactInstanceManager; -import com.facebook.react.ReactPackage; import com.facebook.react.ReactRootView; import com.facebook.react.shell.MainReactPackage; import com.facebook.react.uimanager.UIImplementationProvider; diff --git a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java index 45f4efeb7..f75d3f281 100644 --- a/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java +++ b/ReactAndroid/src/androidTest/java/com/facebook/react/testing/ReactTestHelper.java @@ -20,13 +20,14 @@ import android.view.ViewGroup; import com.facebook.react.ReactInstanceManager; import com.facebook.react.bridge.CatalystInstance; -import com.facebook.react.bridge.CatalystInstanceImpl; -import com.facebook.react.bridge.JSBundleLoader; -import com.facebook.react.bridge.JSCJavaScriptExecutor; +import com.facebook.react.cxxbridge.CatalystInstanceImpl; +import com.facebook.react.cxxbridge.JSBundleLoader; +import com.facebook.react.cxxbridge.NativeModuleRegistry; +import com.facebook.react.cxxbridge.JSCJavaScriptExecutor; +import com.facebook.react.cxxbridge.JavaScriptExecutor; import com.facebook.react.bridge.JavaScriptModuleRegistry; import com.facebook.react.bridge.NativeModule; import com.facebook.react.bridge.NativeModuleCallExceptionHandler; -import com.facebook.react.bridge.NativeModuleRegistry; import com.facebook.react.bridge.WritableNativeMap; import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec; @@ -61,9 +62,15 @@ public class ReactTestHelper { @Override public CatalystInstance build() { + JavaScriptExecutor executor = null; + try { + executor = new JSCJavaScriptExecutor.Factory(new WritableNativeMap()).create(); + } catch (Exception e) { + throw new RuntimeException(e); + } return new CatalystInstanceImpl.Builder() .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) - .setJSExecutor(new JSCJavaScriptExecutor(new WritableNativeMap())) + .setJSExecutor(executor) .setRegistry(mNativeModuleRegistryBuilder.build()) .setJSModuleRegistry(mJSModuleRegistryBuilder.build()) .setJSBundleLoader(JSBundleLoader.createFileLoader( diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 4aa08512f..de75fab6e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -202,7 +202,6 @@ public abstract class ReactInstanceManager { protected @Nullable Activity mCurrentActivity; protected @Nullable DefaultHardwareBackBtnHandler mDefaultHardwareBackBtnHandler; protected @Nullable RedBoxHandler mRedBoxHandler; - protected boolean mUseOldBridge; protected Builder() { } @@ -330,11 +329,6 @@ public abstract class ReactInstanceManager { return this; } - public Builder setUseOldBridge(boolean enable) { - mUseOldBridge = enable; - return this; - } - /** * Instantiates a new {@link ReactInstanceManagerImpl}. * Before calling {@code build}, the following must be called: @@ -350,10 +344,6 @@ public abstract class ReactInstanceManager { mApplication, "Application property has not been set with this builder"); - Assertions.assertCondition( - mJSBundleLoader == null || !mUseOldBridge, - "JSBundleLoader can't be used with the old bridge"); - Assertions.assertCondition( mUseDeveloperSupport || mJSBundleFile != null || mJSBundleLoader != null, "JS Bundle File has to be provided when dev support is disabled"); @@ -367,38 +357,21 @@ public abstract class ReactInstanceManager { mUIImplementationProvider = new UIImplementationProvider(); } - if (mUseOldBridge) { - return new ReactInstanceManagerImpl( - mApplication, - mCurrentActivity, - mDefaultHardwareBackBtnHandler, - mJSBundleFile, - mJSMainModuleName, - mPackages, - mUseDeveloperSupport, - mBridgeIdleDebugListener, - Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"), - mUIImplementationProvider, - mNativeModuleCallExceptionHandler, - mJSCConfig, - mRedBoxHandler); - } else { - return new XReactInstanceManagerImpl( - mApplication, - mCurrentActivity, - mDefaultHardwareBackBtnHandler, - (mJSBundleLoader == null && mJSBundleFile != null) ? - JSBundleLoader.createFileLoader(mApplication, mJSBundleFile) : mJSBundleLoader, - mJSMainModuleName, - mPackages, - mUseDeveloperSupport, - mBridgeIdleDebugListener, - Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"), - mUIImplementationProvider, - mNativeModuleCallExceptionHandler, - mJSCConfig, - mRedBoxHandler); - } + return new XReactInstanceManagerImpl( + mApplication, + mCurrentActivity, + mDefaultHardwareBackBtnHandler, + (mJSBundleLoader == null && mJSBundleFile != null) ? + JSBundleLoader.createFileLoader(mApplication, mJSBundleFile) : mJSBundleLoader, + mJSMainModuleName, + mPackages, + mUseDeveloperSupport, + mBridgeIdleDebugListener, + Assertions.assertNotNull(mInitialLifecycleState, "Initial lifecycle state was not set"), + mUIImplementationProvider, + mNativeModuleCallExceptionHandler, + mJSCConfig, + mRedBoxHandler); } } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java deleted file mode 100644 index 30b09dfd6..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java +++ /dev/null @@ -1,942 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react; - -import javax.annotation.Nullable; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; - -import android.app.Activity; -import android.app.Application; -import android.content.Context; -import android.content.Intent; -import android.os.AsyncTask; -import android.os.Bundle; -import android.view.View; -import android.net.Uri; - -import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.CatalystInstance; -import com.facebook.react.bridge.CatalystInstanceImpl; -import com.facebook.react.bridge.JSBundleLoader; -import com.facebook.react.bridge.JSCJavaScriptExecutor; -import com.facebook.react.bridge.JavaJSExecutor; -import com.facebook.react.bridge.JavaScriptExecutor; -import com.facebook.react.bridge.JavaScriptModule; -import com.facebook.react.bridge.JavaScriptModuleRegistry; -import com.facebook.react.bridge.NativeModule; -import com.facebook.react.bridge.NativeModuleCallExceptionHandler; -import com.facebook.react.bridge.NativeModuleRegistry; -import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener; -import com.facebook.react.bridge.ProxyJavaScriptExecutor; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.ReactContext; -import com.facebook.react.bridge.ReactMarker; -import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec; -import com.facebook.react.common.ApplicationHolder; -import com.facebook.react.common.ReactConstants; -import com.facebook.react.common.annotations.VisibleForTesting; -import com.facebook.react.devsupport.DevServerHelper; -import com.facebook.react.devsupport.DevSupportManager; -import com.facebook.react.devsupport.DevSupportManagerFactory; -import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler; -import com.facebook.react.devsupport.RedBoxHandler; -import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler; -import com.facebook.react.modules.core.DeviceEventManagerModule; -import com.facebook.react.views.imagehelper.ResourceDrawableIdHelper; -import com.facebook.react.uimanager.AppRegistry; -import com.facebook.react.uimanager.DisplayMetricsHolder; -import com.facebook.react.uimanager.UIImplementationProvider; -import com.facebook.react.uimanager.UIManagerModule; -import com.facebook.react.uimanager.ViewManager; -import com.facebook.soloader.SoLoader; -import com.facebook.systrace.Systrace; - -import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_NATIVE_MODULE_REGISTRY_END; -import static com.facebook.react.bridge.ReactMarkerConstants.BUILD_NATIVE_MODULE_REGISTRY_START; -import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_CATALYST_INSTANCE_END; -import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_CATALYST_INSTANCE_START; -import static com.facebook.react.bridge.ReactMarkerConstants.CREATE_REACT_CONTEXT_START; -import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_END; -import static com.facebook.react.bridge.ReactMarkerConstants.PROCESS_PACKAGES_START; -import static com.facebook.react.bridge.ReactMarkerConstants.RUN_JS_BUNDLE_START; - -/** - * This class manages instances of {@link CatalystInstance}. It exposes a way to configure - * catalyst instances using {@link ReactPackage} and keeps track of the lifecycle of that - * instance. It also sets up connection between the instance and developers support functionality - * of the framework. - * - * An instance of this manager is required to start JS application in {@link ReactRootView} (see - * {@link ReactRootView#startReactApplication} for more info). - * - * The lifecycle of the instance of {@link ReactInstanceManagerImpl} should be bound to the activity - * that owns the {@link ReactRootView} that is used to render react application using this - * instance manager (see {@link ReactRootView#startReactApplication}). It's required to pass - * owning activity's lifecycle events to the instance manager (see {@link #onHostPause}, - * {@link #onHostDestroy} and {@link #onHostResume}). - * - * To instantiate an instance of this class use {@link #builder}. - */ -/* package */ class ReactInstanceManagerImpl extends ReactInstanceManager { - - /* should only be accessed from main thread (UI thread) */ - private final List mAttachedRootViews = new ArrayList<>(); - private LifecycleState mLifecycleState; - private @Nullable ReactContextInitParams mPendingReactContextInitParams; - private @Nullable ReactContextInitAsyncTask mReactContextInitAsyncTask; - - /* accessed from any thread */ - private @Nullable String mJSBundleFile; /* path to JS bundle on file system */ - private final @Nullable String mJSMainModuleName; /* path to JS bundle root on packager server */ - private final List mPackages; - private final DevSupportManager mDevSupportManager; - private final boolean mUseDeveloperSupport; - private final @Nullable NotThreadSafeBridgeIdleDebugListener mBridgeIdleDebugListener; - private @Nullable volatile ReactContext mCurrentReactContext; - private final Context mApplicationContext; - private @Nullable DefaultHardwareBackBtnHandler mDefaultBackButtonImpl; - private String mSourceUrl; - private @Nullable Activity mCurrentActivity; - private final Collection mReactInstanceEventListeners = - Collections.synchronizedSet(new HashSet()); - private volatile boolean mHasStartedCreatingInitialContext = false; - private final UIImplementationProvider mUIImplementationProvider; - private final MemoryPressureRouter mMemoryPressureRouter; - private final @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; - private final @Nullable JSCConfig mJSCConfig; - private @Nullable RedBoxHandler mRedBoxHandler; - - private final ReactInstanceDevCommandsHandler mDevInterface = - new ReactInstanceDevCommandsHandler() { - - @Override - public void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) { - ReactInstanceManagerImpl.this.onReloadWithJSDebugger(jsExecutorFactory); - } - - @Override - public void onJSBundleLoadedFromServer() { - ReactInstanceManagerImpl.this.onJSBundleLoadedFromServer(); - } - - @Override - public void toggleElementInspector() { - ReactInstanceManagerImpl.this.toggleElementInspector(); - } - }; - - private final DefaultHardwareBackBtnHandler mBackBtnHandler = - new DefaultHardwareBackBtnHandler() { - @Override - public void invokeDefaultOnBackPressed() { - ReactInstanceManagerImpl.this.invokeDefaultOnBackPressed(); - } - }; - - private class ReactContextInitParams { - private final JavaScriptExecutor.Factory mJsExecutorFactory; - private final JSBundleLoader mJsBundleLoader; - - public ReactContextInitParams( - JavaScriptExecutor.Factory jsExecutorFactory, - JSBundleLoader jsBundleLoader) { - mJsExecutorFactory = Assertions.assertNotNull(jsExecutorFactory); - mJsBundleLoader = Assertions.assertNotNull(jsBundleLoader); - } - - public JavaScriptExecutor.Factory getJsExecutorFactory() { - return mJsExecutorFactory; - } - - public JSBundleLoader getJsBundleLoader() { - return mJsBundleLoader; - } - } - - /* - * Task class responsible for (re)creating react context in the background. These tasks can only - * be executing one at time, see {@link #recreateReactContextInBackground()}. - */ - private final class ReactContextInitAsyncTask extends - AsyncTask> { - @Override - protected void onPreExecute() { - if (mCurrentReactContext != null) { - tearDownReactContext(mCurrentReactContext); - mCurrentReactContext = null; - } - } - - @Override - protected Result doInBackground(ReactContextInitParams... params) { - Assertions.assertCondition(params != null && params.length > 0 && params[0] != null); - try { - JavaScriptExecutor jsExecutor = - params[0].getJsExecutorFactory().create( - mJSCConfig == null ? new WritableNativeMap() : mJSCConfig.getConfigMap()); - return Result.of(createReactContext(jsExecutor, params[0].getJsBundleLoader())); - } catch (Exception e) { - // Pass exception to onPostExecute() so it can be handled on the main thread - return Result.of(e); - } - } - - @Override - protected void onPostExecute(Result result) { - try { - setupReactContext(result.get()); - } catch (Exception e) { - mDevSupportManager.handleException(e); - } finally { - mReactContextInitAsyncTask = null; - } - - // Handle enqueued request to re-initialize react context. - if (mPendingReactContextInitParams != null) { - recreateReactContextInBackground( - mPendingReactContextInitParams.getJsExecutorFactory(), - mPendingReactContextInitParams.getJsBundleLoader()); - mPendingReactContextInitParams = null; - } - } - - @Override - protected void onCancelled(Result reactApplicationContextResult) { - try { - mMemoryPressureRouter.destroy(reactApplicationContextResult.get()); - } catch (Exception e) { - FLog.w(ReactConstants.TAG, "Caught exception after cancelling react context init", e); - } finally { - mReactContextInitAsyncTask = null; - } - } - } - - private static class Result { - @Nullable private final T mResult; - @Nullable private final Exception mException; - - public static Result of(U result) { - return new Result(result); - } - - public static Result of(Exception exception) { - return new Result<>(exception); - } - - private Result(T result) { - mException = null; - mResult = result; - } - - private Result(Exception exception) { - mException = exception; - mResult = null; - } - - public T get() throws Exception { - if (mException != null) { - throw mException; - } - - Assertions.assertNotNull(mResult); - - return mResult; - } - } - - /* package */ ReactInstanceManagerImpl( - Context applicationContext, - @Nullable Activity currentActivity, - @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler, - @Nullable String jsBundleFile, - @Nullable String jsMainModuleName, - List packages, - boolean useDeveloperSupport, - @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener, - LifecycleState initialLifecycleState, - UIImplementationProvider uiImplementationProvider, - NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler, - @Nullable JSCConfig jscConfig) { - - this(applicationContext, - currentActivity, - defaultHardwareBackBtnHandler, - jsBundleFile, - jsMainModuleName, - packages, - useDeveloperSupport, - bridgeIdleDebugListener, - initialLifecycleState, - uiImplementationProvider, - nativeModuleCallExceptionHandler, - jscConfig, - null); - } - - /* package */ ReactInstanceManagerImpl( - Context applicationContext, - @Nullable Activity currentActivity, - @Nullable DefaultHardwareBackBtnHandler defaultHardwareBackBtnHandler, - @Nullable String jsBundleFile, - @Nullable String jsMainModuleName, - List packages, - boolean useDeveloperSupport, - @Nullable NotThreadSafeBridgeIdleDebugListener bridgeIdleDebugListener, - LifecycleState initialLifecycleState, - UIImplementationProvider uiImplementationProvider, - NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler, - @Nullable JSCConfig jscConfig, - @Nullable RedBoxHandler redBoxHandler) { - initializeSoLoaderIfNecessary(applicationContext); - - // TODO(9577825): remove this - ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext()); - DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(applicationContext); - - mApplicationContext = applicationContext; - mCurrentActivity = currentActivity; - mDefaultBackButtonImpl = defaultHardwareBackBtnHandler; - mJSBundleFile = jsBundleFile; - mJSMainModuleName = jsMainModuleName; - mPackages = packages; - mUseDeveloperSupport = useDeveloperSupport; - mRedBoxHandler = redBoxHandler; - mDevSupportManager = DevSupportManagerFactory.create( - applicationContext, - mDevInterface, - mJSMainModuleName, - useDeveloperSupport, - mRedBoxHandler); - mBridgeIdleDebugListener = bridgeIdleDebugListener; - mLifecycleState = initialLifecycleState; - mUIImplementationProvider = uiImplementationProvider; - mMemoryPressureRouter = new MemoryPressureRouter(applicationContext); - mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; - mJSCConfig = jscConfig; - } - - @Override - public DevSupportManager getDevSupportManager() { - return mDevSupportManager; - } - - @Override - public MemoryPressureRouter getMemoryPressureRouter() { - return mMemoryPressureRouter; - } - - private static void initializeSoLoaderIfNecessary(Context applicationContext) { - // Call SoLoader.initialize here, this is required for apps that does not use exopackage and - // does not use SoLoader for loading other native code except from the one used by React Native - // This way we don't need to require others to have additional initialization code and to - // subclass android.app.Application. - - // Method SoLoader.init is idempotent, so if you wish to use native exopackage, just call - // SoLoader.init with appropriate args before initializing ReactInstanceManagerImpl - SoLoader.init(applicationContext, /* native exopackage */ false); - } - - /** - * Trigger react context initialization asynchronously in a background async task. This enables - * applications to pre-load the application JS, and execute global code before - * {@link ReactRootView} is available and measured. This should only be called the first time the - * application is set up, which is enforced to keep developers from accidentally creating their - * application multiple times without realizing it. - * - * Called from UI thread. - */ - @Override - public void createReactContextInBackground() { - Assertions.assertCondition( - !mHasStartedCreatingInitialContext, - "createReactContextInBackground should only be called when creating the react " + - "application for the first time. When reloading JS, e.g. from a new file, explicitly " + - "use recreateReactContextInBackground"); - - mHasStartedCreatingInitialContext = true; - recreateReactContextInBackgroundInner(); - } - - /** - * Recreate the react application and context. This should be called if configuration has - * changed or the developer has requested the app to be reloaded. It should only be called after - * an initial call to createReactContextInBackground. - * - * Called from UI thread. - */ - public void recreateReactContextInBackground() { - Assertions.assertCondition( - mHasStartedCreatingInitialContext, - "recreateReactContextInBackground should only be called after the initial " + - "createReactContextInBackground call."); - recreateReactContextInBackgroundInner(); - } - - private void recreateReactContextInBackgroundInner() { - UiThreadUtil.assertOnUiThread(); - - if (mUseDeveloperSupport && mJSMainModuleName != null) { - if (mDevSupportManager.hasUpToDateJSBundleInCache()) { - // If there is a up-to-date bundle downloaded from server, always use that - onJSBundleLoadedFromServer(); - } else if (mJSBundleFile == null) { - mDevSupportManager.handleReloadJS(); - } else { - mDevSupportManager.isPackagerRunning( - new DevServerHelper.PackagerStatusCallback() { - @Override - public void onPackagerStatusFetched(final boolean packagerIsRunning) { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - if (packagerIsRunning) { - mDevSupportManager.handleReloadJS(); - } else { - recreateReactContextInBackgroundFromBundleFile(); - } - } - }); - } - }); - } - return; - } - - recreateReactContextInBackgroundFromBundleFile(); - } - - private void recreateReactContextInBackgroundFromBundleFile() { - recreateReactContextInBackground( - new JSCJavaScriptExecutor.Factory(), - JSBundleLoader.createFileLoader(mApplicationContext, mJSBundleFile)); - } - - /** - * @return whether createReactContextInBackground has been called. Will return false after - * onDestroy until a new initial context has been created. - */ - public boolean hasStartedCreatingInitialContext() { - return mHasStartedCreatingInitialContext; - } - - /** - * This method will give JS the opportunity to consume the back button event. If JS does not - * consume the event, mDefaultBackButtonImpl will be invoked at the end of the round trip to JS. - */ - @Override - public void onBackPressed() { - UiThreadUtil.assertOnUiThread(); - ReactContext reactContext = mCurrentReactContext; - if (mCurrentReactContext == null) { - // Invoke without round trip to JS. - FLog.w(ReactConstants.TAG, "Instance detached from instance manager"); - invokeDefaultOnBackPressed(); - } else { - DeviceEventManagerModule deviceEventManagerModule = - Assertions.assertNotNull(reactContext).getNativeModule(DeviceEventManagerModule.class); - deviceEventManagerModule.emitHardwareBackPressed(); - } - } - - private void invokeDefaultOnBackPressed() { - UiThreadUtil.assertOnUiThread(); - if (mDefaultBackButtonImpl != null) { - mDefaultBackButtonImpl.invokeDefaultOnBackPressed(); - } - } - - @Override - public void onNewIntent(Intent intent) { - if (mCurrentReactContext == null) { - FLog.w(ReactConstants.TAG, "Instance detached from instance manager"); - } else { - String action = intent.getAction(); - Uri uri = intent.getData(); - - if (Intent.ACTION_VIEW.equals(action) && uri != null) { - DeviceEventManagerModule deviceEventManagerModule = - Assertions.assertNotNull(mCurrentReactContext).getNativeModule(DeviceEventManagerModule.class); - deviceEventManagerModule.emitNewIntentReceived(uri); - } - - mCurrentReactContext.onNewIntent(mCurrentActivity, intent); - } - } - - private void toggleElementInspector() { - if (mCurrentReactContext != null) { - mCurrentReactContext - .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) - .emit("toggleElementInspector", null); - } - } - - @Override - public void onHostPause() { - UiThreadUtil.assertOnUiThread(); - - mDefaultBackButtonImpl = null; - if (mUseDeveloperSupport) { - mDevSupportManager.setDevSupportEnabled(false); - } - - moveToBeforeResumeLifecycleState(); - mCurrentActivity = null; - } - - /** - * Use this method when the activity resumes to enable invoking the back button directly from JS. - * - * This method retains an instance to provided mDefaultBackButtonImpl. Thus it's - * important to pass from the activity instance that owns this particular instance of {@link - * ReactInstanceManagerImpl}, so that once this instance receive {@link #onHostDestroy} event it will - * clear the reference to that defaultBackButtonImpl. - * - * @param defaultBackButtonImpl a {@link DefaultHardwareBackBtnHandler} from an Activity that owns - * this instance of {@link ReactInstanceManagerImpl}. - */ - @Override - public void onHostResume(Activity activity, DefaultHardwareBackBtnHandler defaultBackButtonImpl) { - UiThreadUtil.assertOnUiThread(); - - mDefaultBackButtonImpl = defaultBackButtonImpl; - if (mUseDeveloperSupport) { - mDevSupportManager.setDevSupportEnabled(true); - } - - mCurrentActivity = activity; - moveToResumedLifecycleState(false); - } - - @Override - public void onHostDestroy() { - UiThreadUtil.assertOnUiThread(); - - if (mUseDeveloperSupport) { - mDevSupportManager.setDevSupportEnabled(false); - } - - moveToBeforeCreateLifecycleState(); - mCurrentActivity = null; - } - - @Override - public void destroy() { - UiThreadUtil.assertOnUiThread(); - - if (mUseDeveloperSupport) { - mDevSupportManager.setDevSupportEnabled(false); - } - - moveToBeforeCreateLifecycleState(); - - if (mReactContextInitAsyncTask != null) { - mReactContextInitAsyncTask.cancel(true); - } - - mMemoryPressureRouter.destroy(mApplicationContext); - - if (mCurrentReactContext != null) { - mCurrentReactContext.destroy(); - mCurrentReactContext = null; - mHasStartedCreatingInitialContext = false; - } - mCurrentActivity = null; - - ResourceDrawableIdHelper.getInstance().clear(); - } - - private void moveToResumedLifecycleState(boolean force) { - if (mCurrentReactContext != null) { - // we currently don't have an onCreate callback so we call onResume for both transitions - if (force || - mLifecycleState == LifecycleState.BEFORE_RESUME || - mLifecycleState == LifecycleState.BEFORE_CREATE) { - mCurrentReactContext.onHostResume(mCurrentActivity); - } - } - mLifecycleState = LifecycleState.RESUMED; - } - - private void moveToBeforeResumeLifecycleState() { - if (mCurrentReactContext != null) { - if (mLifecycleState == LifecycleState.BEFORE_CREATE) { - mCurrentReactContext.onHostResume(mCurrentActivity); - mCurrentReactContext.onHostPause(); - } else if (mLifecycleState == LifecycleState.RESUMED) { - mCurrentReactContext.onHostPause(); - } - } - mLifecycleState = LifecycleState.BEFORE_RESUME; - } - - private void moveToBeforeCreateLifecycleState() { - if (mCurrentReactContext != null) { - if (mLifecycleState == LifecycleState.RESUMED) { - mCurrentReactContext.onHostPause(); - mLifecycleState = LifecycleState.BEFORE_RESUME; - } - if (mLifecycleState == LifecycleState.BEFORE_RESUME) { - mCurrentReactContext.onHostDestroy(); - } - } - mLifecycleState = LifecycleState.BEFORE_CREATE; - } - - public LifecycleState getLifecycleState() { - return mLifecycleState; - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (mCurrentReactContext != null) { - mCurrentReactContext.onActivityResult(requestCode, resultCode, data); - } - } - - @Override - public void showDevOptionsDialog() { - UiThreadUtil.assertOnUiThread(); - mDevSupportManager.showDevOptionsDialog(); - } - - /** - * Get the URL where the last bundle was loaded from. - */ - @Override - public String getSourceUrl() { - return Assertions.assertNotNull(mSourceUrl); - } - - @Override - public @Nullable String getJSBundleFile() { - return mJSBundleFile; - } - - /** - * Attach given {@param rootView} to a catalyst instance manager and start JS application using - * JS module provided by {@link ReactRootView#getJSModuleName}. If the react context is currently - * being (re)-created, or if react context has not been created yet, the JS application associated - * with the provided root view will be started asynchronously, i.e this method won't block. - * This view will then be tracked by this manager and in case of catalyst instance restart it will - * be re-attached. - */ - @Override - public void attachMeasuredRootView(ReactRootView rootView) { - UiThreadUtil.assertOnUiThread(); - mAttachedRootViews.add(rootView); - - // If react context is being created in the background, JS application will be started - // automatically when creation completes, as root view is part of the attached root view list. - if (mReactContextInitAsyncTask == null && mCurrentReactContext != null) { - attachMeasuredRootViewToInstance(rootView, mCurrentReactContext.getCatalystInstance()); - } - } - - /** - * Detach given {@param rootView} from current catalyst instance. It's safe to call this method - * multiple times on the same {@param rootView} - in that case view will be detached with the - * first call. - */ - @Override - public void detachRootView(ReactRootView rootView) { - UiThreadUtil.assertOnUiThread(); - if (mAttachedRootViews.remove(rootView)) { - if (mCurrentReactContext != null && mCurrentReactContext.hasActiveCatalystInstance()) { - detachViewFromInstance(rootView, mCurrentReactContext.getCatalystInstance()); - } - } - } - - /** - * Uses configured {@link ReactPackage} instances to create all view managers - */ - @Override - public List createAllViewManagers( - ReactApplicationContext catalystApplicationContext) { - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createAllViewManagers"); - try { - List allViewManagers = new ArrayList<>(); - for (ReactPackage reactPackage : mPackages) { - allViewManagers.addAll(reactPackage.createViewManagers(catalystApplicationContext)); - } - return allViewManagers; - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - - @Override - public void addReactInstanceEventListener(ReactInstanceEventListener listener) { - mReactInstanceEventListeners.add(listener); - } - - @Override - public void removeReactInstanceEventListener(ReactInstanceEventListener listener) { - mReactInstanceEventListeners.remove(listener); - } - - @VisibleForTesting - @Override - public @Nullable ReactContext getCurrentReactContext() { - return mCurrentReactContext; - } - - private void onReloadWithJSDebugger(JavaJSExecutor.Factory jsExecutorFactory) { - recreateReactContextInBackground( - new ProxyJavaScriptExecutor.Factory(jsExecutorFactory), - JSBundleLoader.createRemoteDebuggerBundleLoader( - mDevSupportManager.getJSBundleURLForRemoteDebugging(), - mDevSupportManager.getSourceUrl())); - } - - private void onJSBundleLoadedFromServer() { - recreateReactContextInBackground( - new JSCJavaScriptExecutor.Factory(), - JSBundleLoader.createCachedBundleFromNetworkLoader( - mDevSupportManager.getSourceUrl(), - mDevSupportManager.getDownloadedJSBundleFile())); - } - - private void recreateReactContextInBackground( - JavaScriptExecutor.Factory jsExecutorFactory, - JSBundleLoader jsBundleLoader) { - UiThreadUtil.assertOnUiThread(); - - ReactContextInitParams initParams = - new ReactContextInitParams(jsExecutorFactory, jsBundleLoader); - if (mReactContextInitAsyncTask == null) { - // No background task to create react context is currently running, create and execute one. - mReactContextInitAsyncTask = new ReactContextInitAsyncTask(); - mReactContextInitAsyncTask.execute(initParams); - } else { - // Background task is currently running, queue up most recent init params to recreate context - // once task completes. - mPendingReactContextInitParams = initParams; - } - } - - private void setupReactContext(ReactApplicationContext reactContext) { - UiThreadUtil.assertOnUiThread(); - Assertions.assertCondition(mCurrentReactContext == null); - mCurrentReactContext = Assertions.assertNotNull(reactContext); - CatalystInstance catalystInstance = - Assertions.assertNotNull(reactContext.getCatalystInstance()); - - catalystInstance.initialize(); - mDevSupportManager.onNewReactContextCreated(reactContext); - mMemoryPressureRouter.addMemoryPressureListener(catalystInstance); - moveReactContextToCurrentLifecycleState(); - - for (ReactRootView rootView : mAttachedRootViews) { - attachMeasuredRootViewToInstance(rootView, catalystInstance); - } - - ReactInstanceEventListener[] listeners = - new ReactInstanceEventListener[mReactInstanceEventListeners.size()]; - listeners = mReactInstanceEventListeners.toArray(listeners); - - for (ReactInstanceEventListener listener : listeners) { - listener.onReactContextInitialized(reactContext); - } - } - - private void attachMeasuredRootViewToInstance( - ReactRootView rootView, - CatalystInstance catalystInstance) { - UiThreadUtil.assertOnUiThread(); - - // Reset view content as it's going to be populated by the application content from JS - rootView.removeAllViews(); - rootView.setId(View.NO_ID); - - UIManagerModule uiManagerModule = catalystInstance.getNativeModule(UIManagerModule.class); - int rootTag = uiManagerModule.addMeasuredRootView(rootView); - rootView.setRootViewTag(rootTag); - @Nullable Bundle launchOptions = rootView.getLaunchOptions(); - WritableMap initialProps = launchOptions != null - ? Arguments.fromBundle(launchOptions) - : Arguments.createMap(); - String jsAppModuleName = rootView.getJSModuleName(); - - WritableNativeMap appParams = new WritableNativeMap(); - appParams.putDouble("rootTag", rootTag); - appParams.putMap("initialProps", initialProps); - catalystInstance.getJSModule(AppRegistry.class).runApplication(jsAppModuleName, appParams); - } - - private void detachViewFromInstance( - ReactRootView rootView, - CatalystInstance catalystInstance) { - UiThreadUtil.assertOnUiThread(); - catalystInstance.getJSModule(AppRegistry.class) - .unmountApplicationComponentAtRootTag(rootView.getId()); - } - - private void tearDownReactContext(ReactContext reactContext) { - UiThreadUtil.assertOnUiThread(); - if (mLifecycleState == LifecycleState.RESUMED) { - reactContext.onHostPause(); - } - for (ReactRootView rootView : mAttachedRootViews) { - detachViewFromInstance(rootView, reactContext.getCatalystInstance()); - } - reactContext.destroy(); - mDevSupportManager.onReactInstanceDestroyed(reactContext); - mMemoryPressureRouter.removeMemoryPressureListener(reactContext.getCatalystInstance()); - } - - /** - * @return instance of {@link ReactContext} configured a {@link CatalystInstance} set - */ - private ReactApplicationContext createReactContext( - JavaScriptExecutor jsExecutor, - JSBundleLoader jsBundleLoader) { - FLog.i(ReactConstants.TAG, "Creating react context."); - ReactMarker.logMarker(CREATE_REACT_CONTEXT_START); - // CREATE_REACT_CONTEXT_END is in JSCExecutor.cpp - mSourceUrl = jsBundleLoader.getSourceUrl(); - NativeModuleRegistry.Builder nativeRegistryBuilder = new NativeModuleRegistry.Builder(); - JavaScriptModuleRegistry.Builder jsModulesBuilder = new JavaScriptModuleRegistry.Builder(); - - final ReactApplicationContext reactContext = new ReactApplicationContext(mApplicationContext); - if (mUseDeveloperSupport) { - reactContext.setNativeModuleCallExceptionHandler(mDevSupportManager); - } - - ReactMarker.logMarker(PROCESS_PACKAGES_START); - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "createAndProcessCoreModulesPackage"); - try { - CoreModulesPackage coreModulesPackage = - new CoreModulesPackage(this, mBackBtnHandler, mUIImplementationProvider); - processPackage(coreModulesPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - - // TODO(6818138): Solve use-case of native/js modules overriding - for (ReactPackage reactPackage : mPackages) { - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "createAndProcessCustomReactPackage"); - try { - processPackage(reactPackage, reactContext, nativeRegistryBuilder, jsModulesBuilder); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - ReactMarker.logMarker(PROCESS_PACKAGES_END); - - ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_START); - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "buildNativeModuleRegistry"); - NativeModuleRegistry nativeModuleRegistry; - try { - nativeModuleRegistry = nativeRegistryBuilder.build(); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - ReactMarker.logMarker(BUILD_NATIVE_MODULE_REGISTRY_END); - } - - NativeModuleCallExceptionHandler exceptionHandler = mNativeModuleCallExceptionHandler != null - ? mNativeModuleCallExceptionHandler - : mDevSupportManager; - CatalystInstanceImpl.Builder catalystInstanceBuilder = new CatalystInstanceImpl.Builder() - .setReactQueueConfigurationSpec(ReactQueueConfigurationSpec.createDefault()) - .setJSExecutor(jsExecutor) - .setRegistry(nativeModuleRegistry) - .setJSModuleRegistry(jsModulesBuilder.build()) - .setJSBundleLoader(jsBundleLoader) - .setNativeModuleCallExceptionHandler(exceptionHandler); - - ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_START); - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "createCatalystInstance"); - final CatalystInstance catalystInstance; - try { - catalystInstance = catalystInstanceBuilder.build(); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - ReactMarker.logMarker(CREATE_CATALYST_INSTANCE_END); - } - - if (mBridgeIdleDebugListener != null) { - catalystInstance.addBridgeIdleDebugListener(mBridgeIdleDebugListener); - } - - try { - catalystInstance.getReactQueueConfiguration().getJSQueueThread().callOnQueue( - new Callable() { - @Override - public Void call() { - // We want to ensure that any code that checks ReactContext#hasActiveCatalystInstance - // can be sure that it's safe to call a JS module function. As JS module function calls - // execute on the JS thread, and this Runnable runs on the JS thread, at this point we - // know that no JS module function calls will be executed until after this Runnable completes. - // - // This means it is now safe to say the instance is initialized. - // - // The reason we call this here instead of after this Runnable completes is so that we can - // reduce the amount of time until the React instance is able to start accepting JS calls, - // and so that any native module calls that result from runJSBundle can access JS modules. - reactContext.initializeWithInstance(catalystInstance); - - ReactMarker.logMarker(RUN_JS_BUNDLE_START); - // RUN_JS_BUNDLE_END is in JSCExecutor.cpp - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "runJSBundle"); - try { - catalystInstance.runJSBundle(); - } finally { - // This will actually finish when `JSCExecutor#loadApplicationScript()` finishes - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - return null; - } - }).get(); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - - return reactContext; - } - - private void processPackage( - ReactPackage reactPackage, - ReactApplicationContext reactContext, - NativeModuleRegistry.Builder nativeRegistryBuilder, - JavaScriptModuleRegistry.Builder jsModulesBuilder) { - for (NativeModule nativeModule : reactPackage.createNativeModules(reactContext)) { - nativeRegistryBuilder.add(nativeModule); - } - for (Class jsModuleClass : reactPackage.createJSModules()) { - jsModulesBuilder.add(jsModuleClass); - } - } - - private void moveReactContextToCurrentLifecycleState() { - if (mLifecycleState == LifecycleState.RESUMED) { - moveToResumedLifecycleState(true); - } - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java deleted file mode 100644 index 7e4683a37..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/CatalystInstanceImpl.java +++ /dev/null @@ -1,568 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import javax.annotation.Nullable; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.Collection; -import java.util.concurrent.Callable; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.atomic.AtomicInteger; - -import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.queue.ReactQueueConfiguration; -import com.facebook.react.bridge.queue.ReactQueueConfigurationImpl; -import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec; -import com.facebook.react.bridge.queue.QueueThreadExceptionHandler; -import com.facebook.react.common.ReactConstants; -import com.facebook.react.common.annotations.VisibleForTesting; -import com.facebook.react.common.futures.SimpleSettableFuture; -import com.facebook.systrace.Systrace; -import com.facebook.systrace.TraceListener; - -/** - * This provides an implementation of the public CatalystInstance instance. It is public because - * it is built by ReactInstanceManager which is in a different package. - */ -@DoNotStrip -public class CatalystInstanceImpl implements CatalystInstance { - - private static final AtomicInteger sNextInstanceIdForTrace = new AtomicInteger(1); - - // Access from any thread - private final ReactQueueConfigurationImpl mReactQueueConfiguration; - private final CopyOnWriteArrayList mBridgeIdleListeners; - private final AtomicInteger mPendingJSCalls = new AtomicInteger(0); - private final String mJsPendingCallsTitleForTrace = - "pending_js_calls_instance" + sNextInstanceIdForTrace.getAndIncrement(); - private volatile boolean mIsBeingDestroyed = false; - private volatile boolean mDestroyed = false; - private final TraceListener mTraceListener; - private final JavaScriptModuleRegistry mJSModuleRegistry; - private final JSBundleLoader mJSBundleLoader; - private @Nullable ExecutorToken mMainExecutorToken; - - // These locks prevent additional calls from going JS<->Java after the bridge has been torn down. - // There are separate ones for each direction because a JS to Java call can trigger a Java to JS - // call: this would cause a deadlock with a traditional mutex (maybe we should be using a reader- - // writer lock but then we'd have to worry about starving the destroy call). - private final Object mJSToJavaCallsTeardownLock = new Object(); - private final Object mJavaToJSCallsTeardownLock = new Object(); - - // Access from native modules thread - private final NativeModuleRegistry mJavaRegistry; - private final NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; - private boolean mInitialized = false; - - // Access from JS thread - private final ReactBridge mBridge; - private boolean mJSBundleHasLoaded; - - private CatalystInstanceImpl( - final ReactQueueConfigurationSpec ReactQueueConfigurationSpec, - final JavaScriptExecutor jsExecutor, - final NativeModuleRegistry registry, - final JavaScriptModuleRegistry jsModuleRegistry, - final JSBundleLoader jsBundleLoader, - NativeModuleCallExceptionHandler nativeModuleCallExceptionHandler) { - FLog.d(ReactConstants.TAG, "Initializing React Bridge."); - mReactQueueConfiguration = ReactQueueConfigurationImpl.create( - ReactQueueConfigurationSpec, - new NativeExceptionHandler()); - mBridgeIdleListeners = new CopyOnWriteArrayList<>(); - mJavaRegistry = registry; - mJSModuleRegistry = jsModuleRegistry; - mJSBundleLoader = jsBundleLoader; - mNativeModuleCallExceptionHandler = nativeModuleCallExceptionHandler; - mTraceListener = new JSProfilerTraceListener(); - - try { - mBridge = mReactQueueConfiguration.getJSQueueThread().callOnQueue( - new Callable() { - @Override - public ReactBridge call() throws Exception { - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "initializeBridge"); - try { - return initializeBridge(jsExecutor); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - }).get(); - } catch (Exception t) { - throw new RuntimeException("Failed to initialize bridge", t); - } - } - - private ReactBridge initializeBridge(JavaScriptExecutor jsExecutor) { - mReactQueueConfiguration.getJSQueueThread().assertIsOnThread(); - Assertions.assertCondition(mBridge == null, "initializeBridge should be called once"); - - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "ReactBridgeCtor"); - ReactBridge bridge; - try { - bridge = new ReactBridge( - jsExecutor, - new NativeModulesReactCallback(), - mReactQueueConfiguration.getNativeModulesQueueThread()); - mMainExecutorToken = bridge.getMainExecutorToken(); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "setBatchedBridgeConfig"); - try { - bridge.setGlobalVariable( - "__fbBatchedBridgeConfig", - buildModulesConfigJSONProperty(mJavaRegistry)); - bridge.setGlobalVariable( - "__RCTProfileIsProfiling", - Systrace.isTracing(Systrace.TRACE_TAG_REACT_APPS) ? "true" : "false"); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - - mJavaRegistry.notifyReactBridgeInitialized(bridge); - return bridge; - } - - @Override - public void runJSBundle() { - mReactQueueConfiguration.getJSQueueThread().assertIsOnThread(); - Assertions.assertCondition(!mJSBundleHasLoaded, "JS bundle was already loaded!"); - - incrementPendingJSCalls(); - - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "loadJSScript"); - try { - mJSBundleLoader.loadScript(mBridge); - - // This is registered after JS starts since it makes a JS call - Systrace.registerListener(mTraceListener); - } catch (JSExecutionException e) { - mNativeModuleCallExceptionHandler.handleException(e); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - - mJSBundleHasLoaded = true; - } - - @Override - public void callFunction( - ExecutorToken executorToken, - String module, - String method, - NativeArray arguments) { - if (mIsBeingDestroyed) { - FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed."); - return; - } - synchronized (mJavaToJSCallsTeardownLock) { - if (mDestroyed) { - FLog.w(ReactConstants.TAG, "Calling JS function after bridge has been destroyed."); - return; - } - - incrementPendingJSCalls(); - - Assertions.assertNotNull(mBridge).callFunction( - executorToken, - module, - method, arguments); - } - } - - // This is called from java code, so it won't be stripped anyway, but proguard will rename it, - // which this prevents. - @DoNotStrip - @Override - public void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments) { - if (mIsBeingDestroyed) { - FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed."); - return; - } - synchronized (mJavaToJSCallsTeardownLock) { - if (mDestroyed) { - FLog.w(ReactConstants.TAG, "Invoking JS callback after bridge has been destroyed."); - return; - } - - incrementPendingJSCalls(); - - Assertions.assertNotNull(mBridge).invokeCallback(executorToken, callbackID, arguments); - } - } - - /** - * Destroys this catalyst instance, waiting for any other threads in ReactQueueConfiguration - * (besides the UI thread) to finish running. Must be called from the UI thread so that we can - * fully shut down other threads. - */ - @Override - public void destroy() { - UiThreadUtil.assertOnUiThread(); - - // This ordering is important. A JS to Java call that triggers a Java to JS call will also - // acquire these locks in the same order - mIsBeingDestroyed = true; - synchronized (mJSToJavaCallsTeardownLock) { - synchronized (mJavaToJSCallsTeardownLock) { - if (mDestroyed) { - return; - } - - // TODO: tell all APIs to shut down - mDestroyed = true; - mJavaRegistry.notifyCatalystInstanceDestroy(); - - Systrace.unregisterListener(mTraceListener); - - synchronouslyDisposeBridgeOnJSThread(); - } - } - - mReactQueueConfiguration.destroy(); - - boolean wasIdle = (mPendingJSCalls.getAndSet(0) == 0); - if (!wasIdle && !mBridgeIdleListeners.isEmpty()) { - for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) { - listener.onTransitionToBridgeIdle(); - } - } - } - - private void synchronouslyDisposeBridgeOnJSThread() { - final SimpleSettableFuture bridgeDisposeFuture = new SimpleSettableFuture<>(); - mReactQueueConfiguration.getJSQueueThread().runOnQueue( - new Runnable() { - @Override - public void run() { - mBridge.destroy(); - mBridge.dispose(); - bridgeDisposeFuture.set(null); - } - }); - bridgeDisposeFuture.getOrThrow(); - } - - @Override - public boolean isDestroyed() { - return mDestroyed; - } - - /** - * Initialize all the native modules - */ - @VisibleForTesting - @Override - public void initialize() { - UiThreadUtil.assertOnUiThread(); - Assertions.assertCondition( - !mInitialized, - "This catalyst instance has already been initialized"); - mInitialized = true; - mJavaRegistry.notifyCatalystInstanceInitialized(); - } - - @Override - public ReactQueueConfiguration getReactQueueConfiguration() { - return mReactQueueConfiguration; - } - - @Override - public T getJSModule(Class jsInterface) { - return getJSModule(Assertions.assertNotNull(mMainExecutorToken), jsInterface); - } - - @Override - public T getJSModule(ExecutorToken executorToken, Class jsInterface) { - return Assertions.assertNotNull(mJSModuleRegistry) - .getJavaScriptModule(this, executorToken, jsInterface); - } - - @Override - public boolean hasNativeModule(Class nativeModuleInterface) { - return mJavaRegistry.hasModule(nativeModuleInterface); - } - - @Override - public T getNativeModule(Class nativeModuleInterface) { - return mJavaRegistry.getModule(nativeModuleInterface); - } - - @Override - public Collection getNativeModules() { - return mJavaRegistry.getAllModules(); - } - - @Override - public void handleMemoryPressure(final MemoryPressure level) { - mReactQueueConfiguration.getJSQueueThread().runOnQueue( - new Runnable() { - @Override - public void run() { - Assertions.assertNotNull(mBridge).handleMemoryPressure(level); - } - }); - } - - /** - * Adds a idle listener for this Catalyst instance. The listener will receive notifications - * whenever the bridge transitions from idle to busy and vice-versa, where the busy state is - * defined as there being some non-zero number of calls to JS that haven't resolved via a - * onBatchCompleted call. The listener should be purely passive and not affect application logic. - */ - @Override - public void addBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) { - mBridgeIdleListeners.add(listener); - } - - /** - * Removes a NotThreadSafeBridgeIdleDebugListener previously added with - * {@link #addBridgeIdleDebugListener} - */ - @Override - public void removeBridgeIdleDebugListener(NotThreadSafeBridgeIdleDebugListener listener) { - mBridgeIdleListeners.remove(listener); - } - - @Override - public boolean supportsProfiling() { - return mBridge.supportsProfiling(); - } - - @Override - public void startProfiler(String title) { - mBridge.startProfiler(title); - } - - @Override - public void stopProfiler(String title, String filename) { - mBridge.stopProfiler(title, filename); - } - - @VisibleForTesting - @Override - public void setGlobalVariable(String propName, String jsonValue) { - mBridge.setGlobalVariable(propName, jsonValue); - } - - private String buildModulesConfigJSONProperty(NativeModuleRegistry nativeModuleRegistry) { - StringWriter stringWriter = new StringWriter(); - JsonWriter writer = new JsonWriter(stringWriter); - try { - writer.beginObject(); - writer.name("remoteModuleConfig"); - nativeModuleRegistry.writeModuleDescriptions(writer); - writer.endObject(); - return stringWriter.toString(); - } catch (IOException ioe) { - throw new RuntimeException("Unable to serialize JavaScript module declaration", ioe); - } finally { - try { - writer.close(); - } catch (IOException ignored) { - } - } - } - - private void incrementPendingJSCalls() { - int oldPendingCalls = mPendingJSCalls.getAndIncrement(); - boolean wasIdle = oldPendingCalls == 0; - Systrace.traceCounter( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - mJsPendingCallsTitleForTrace, - oldPendingCalls + 1); - if (wasIdle && !mBridgeIdleListeners.isEmpty()) { - for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) { - listener.onTransitionToBridgeBusy(); - } - } - } - - private void decrementPendingJSCalls() { - int newPendingCalls = mPendingJSCalls.decrementAndGet(); - // TODO(9604406): handle case of web workers injecting messages to main thread - //Assertions.assertCondition(newPendingCalls >= 0); - boolean isNowIdle = newPendingCalls == 0; - Systrace.traceCounter( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - mJsPendingCallsTitleForTrace, - newPendingCalls); - - if (isNowIdle && !mBridgeIdleListeners.isEmpty()) { - for (NotThreadSafeBridgeIdleDebugListener listener : mBridgeIdleListeners) { - listener.onTransitionToBridgeIdle(); - } - } - } - - @Override - protected void finalize() throws Throwable { - Assertions.assertCondition(mDestroyed, "Bridge was not destroyed before finalizer!"); - super.finalize(); - } - - private class NativeModulesReactCallback implements ReactCallback { - - @Override - public void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters) { - mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread(); - - if (mIsBeingDestroyed) { - return; - } - synchronized (mJSToJavaCallsTeardownLock) { - // Suppress any callbacks if destroyed - will only lead to sadness. - if (mDestroyed) { - return; - } - mJavaRegistry.call(CatalystInstanceImpl.this, executorToken, moduleId, methodId, parameters); - } - } - - @Override - public void onBatchComplete() { - mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread(); - - // The bridge may have been destroyed due to an exception during the batch. In that case - // native modules could be in a bad state so we don't want to call anything on them. We - // still want to trigger the debug listener since it allows instrumentation tests to end and - // check their assertions without waiting for a timeout. - if (mIsBeingDestroyed) { - return; - } - synchronized (mJSToJavaCallsTeardownLock) { - if (mDestroyed) { - return; - } - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onBatchComplete"); - try { - mJavaRegistry.onBatchComplete(); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - - decrementPendingJSCalls(); - } - - @Override - public void onExecutorUnregistered(ExecutorToken executorToken) { - mReactQueueConfiguration.getNativeModulesQueueThread().assertIsOnThread(); - - // Since onCatalystInstanceDestroy happens on the UI thread, we don't want to also execute - // this callback on the native modules thread at the same time. Longer term, onCatalystInstanceDestroy - // should probably be executed on the native modules thread as well instead. - if (mIsBeingDestroyed) { - return; - } - synchronized (mJSToJavaCallsTeardownLock) { - if (mDestroyed) { - return; - } - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "onExecutorUnregistered"); - try { - mJavaRegistry.onExecutorUnregistered(executorToken); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - } - } - - private class NativeExceptionHandler implements QueueThreadExceptionHandler { - - @Override - public void handleException(Exception e) { - // Any Exception caught here is because of something in JS. Even if it's a bug in the - // framework/native code, it was triggered by JS and theoretically since we were able - // to set up the bridge, JS could change its logic, reload, and not trigger that crash. - mNativeModuleCallExceptionHandler.handleException(e); - mReactQueueConfiguration.getUIQueueThread().runOnQueue( - new Runnable() { - @Override - public void run() { - destroy(); - } - }); - } - } - - private class JSProfilerTraceListener implements TraceListener { - @Override - public void onTraceStarted() { - getJSModule(Assertions.assertNotNull(mMainExecutorToken), com.facebook.react.bridge.Systrace.class).setEnabled( - true); - } - - @Override - public void onTraceStopped() { - getJSModule(Assertions.assertNotNull(mMainExecutorToken), com.facebook.react.bridge.Systrace.class).setEnabled(false); - } - } - - public static class Builder { - - private @Nullable ReactQueueConfigurationSpec mReactQueueConfigurationSpec; - private @Nullable JSBundleLoader mJSBundleLoader; - private @Nullable NativeModuleRegistry mRegistry; - private @Nullable JavaScriptModuleRegistry mJSModuleRegistry; - private @Nullable JavaScriptExecutor mJSExecutor; - private @Nullable NativeModuleCallExceptionHandler mNativeModuleCallExceptionHandler; - - public Builder setReactQueueConfigurationSpec( - ReactQueueConfigurationSpec ReactQueueConfigurationSpec) { - mReactQueueConfigurationSpec = ReactQueueConfigurationSpec; - return this; - } - - public Builder setRegistry(NativeModuleRegistry registry) { - mRegistry = registry; - return this; - } - - public Builder setJSModuleRegistry(JavaScriptModuleRegistry jsModuleRegistry) { - mJSModuleRegistry = jsModuleRegistry; - return this; - } - - public Builder setJSBundleLoader(JSBundleLoader jsBundleLoader) { - mJSBundleLoader = jsBundleLoader; - return this; - } - - public Builder setJSExecutor(JavaScriptExecutor jsExecutor) { - mJSExecutor = jsExecutor; - return this; - } - - public Builder setNativeModuleCallExceptionHandler( - NativeModuleCallExceptionHandler handler) { - mNativeModuleCallExceptionHandler = handler; - return this; - } - - public CatalystInstanceImpl build() { - return new CatalystInstanceImpl( - Assertions.assertNotNull(mReactQueueConfigurationSpec), - Assertions.assertNotNull(mJSExecutor), - Assertions.assertNotNull(mRegistry), - Assertions.assertNotNull(mJSModuleRegistry), - Assertions.assertNotNull(mJSBundleLoader), - Assertions.assertNotNull(mNativeModuleCallExceptionHandler)); - } - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java deleted file mode 100644 index 6722cb83c..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSBundleLoader.java +++ /dev/null @@ -1,93 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import android.content.Context; - -/** - * A class that stores JS bundle information and allows {@link CatalystInstance} to load a correct - * bundle through {@link ReactBridge}. - */ -public abstract class JSBundleLoader { - - /** - * This loader is recommended one for release version of your app. In that case local JS executor - * should be used. JS bundle will be read from assets directory in native code to save on passing - * large strings from java to native memory. - */ - public static JSBundleLoader createFileLoader( - final Context context, - final String fileName) { - return new JSBundleLoader() { - @Override - public void loadScript(ReactBridge bridge) { - if (fileName.startsWith("assets://")) { - bridge.loadScriptFromAssets(context.getAssets(), fileName.replaceFirst("assets://", "")); - } else { - bridge.loadScriptFromFile(fileName, "file://" + fileName); - } - } - - @Override - public String getSourceUrl() { - return (fileName.startsWith("assets://") ? "" : "file://") + fileName; - } - }; - } - - /** - * This loader is used when bundle gets reloaded from dev server. In that case loader expect JS - * bundle to be prefetched and stored in local file. We do that to avoid passing large strings - * between java and native code and avoid allocating memory in java to fit whole JS bundle in it. - * Providing correct {@param sourceURL} of downloaded bundle is required for JS stacktraces to - * work correctly and allows for source maps to correctly symbolize those. - */ - public static JSBundleLoader createCachedBundleFromNetworkLoader( - final String sourceURL, - final String cachedFileLocation) { - return new JSBundleLoader() { - @Override - public void loadScript(ReactBridge bridge) { - bridge.loadScriptFromFile(cachedFileLocation, sourceURL); - } - - @Override - public String getSourceUrl() { - return sourceURL; - } - }; - } - - /** - * This loader is used when proxy debugging is enabled. In that case there is no point in fetching - * the bundle from device as remote executor will have to do it anyway. - * - * @param proxySourceURL the URL to load the JS bundle from in the JavaScript proxy - * @param realSourceURL the URL to report as the source URL, e.g. for asset loading - */ - public static JSBundleLoader createRemoteDebuggerBundleLoader( - final String proxySourceURL, - final String realSourceURL) { - return new JSBundleLoader() { - @Override - public void loadScript(ReactBridge bridge) { - bridge.loadScriptFromFile(null, proxySourceURL); - } - - @Override - public String getSourceUrl() { - return realSourceURL; - } - }; - } - - public abstract void loadScript(ReactBridge bridge); - public abstract String getSourceUrl(); -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java deleted file mode 100644 index 4f895abf3..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSCJavaScriptExecutor.java +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.soloader.SoLoader; - -@DoNotStrip -public class JSCJavaScriptExecutor extends JavaScriptExecutor { - static { - ReactBridge.staticInit(); - } - - public static class Factory implements JavaScriptExecutor.Factory { - @Override - public JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception { - return new JSCJavaScriptExecutor(jscConfig); - } - } - - public JSCJavaScriptExecutor(WritableNativeMap jscConfig) { - initialize(jscConfig); - } - - private native void initialize(WritableNativeMap jscConfig); - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSExecutionException.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JSExecutionException.java deleted file mode 100644 index 96e8f1544..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JSExecutionException.java +++ /dev/null @@ -1,17 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -package com.facebook.react.bridge; - -import com.facebook.proguard.annotations.DoNotStrip; - -/** - * Exception thrown when there is an error evaluating JS, e.g. a syntax error. - */ -@DoNotStrip -public class JSExecutionException extends RuntimeException { - - @DoNotStrip - public JSExecutionException(String detailMessage) { - super(detailMessage); - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java deleted file mode 100644 index 92499d314..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/JavaScriptExecutor.java +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import com.facebook.jni.Countable; -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public abstract class JavaScriptExecutor extends Countable { - public interface Factory { - JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception; - } - - /** - * Close this executor and cleanup any resources that it was using. No further calls are - * expected after this. - */ - public void close() { - } - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java deleted file mode 100644 index e6e0f80a2..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/NativeModuleRegistry.java +++ /dev/null @@ -1,235 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.facebook.react.common.MapBuilder; -import com.facebook.infer.annotation.Assertions; -import com.facebook.systrace.Systrace; - -/** - * A set of Java APIs to expose to a particular JavaScript instance. - */ -public class NativeModuleRegistry { - - private final List mModuleTable; - private final Map, NativeModule> mModuleInstances; - private final ArrayList mBatchCompleteListenerModules; - private final ArrayList mOnExecutorUnregisteredListenerModules; - - private NativeModuleRegistry( - List moduleTable, - Map, NativeModule> moduleInstances) { - mModuleTable = moduleTable; - mModuleInstances = moduleInstances; - - mBatchCompleteListenerModules = new ArrayList<>(mModuleTable.size()); - mOnExecutorUnregisteredListenerModules = new ArrayList<>(mModuleTable.size()); - for (int i = 0; i < mModuleTable.size(); i++) { - ModuleDefinition definition = mModuleTable.get(i); - if (definition.target instanceof OnBatchCompleteListener) { - mBatchCompleteListenerModules.add((OnBatchCompleteListener) definition.target); - } - if (definition.target instanceof OnExecutorUnregisteredListener) { - mOnExecutorUnregisteredListenerModules.add((OnExecutorUnregisteredListener) definition.target); - } - } - } - - /* package */ void call( - CatalystInstance catalystInstance, - ExecutorToken executorToken, - int moduleId, - int methodId, - ReadableNativeArray parameters) { - ModuleDefinition definition = mModuleTable.get(moduleId); - if (definition == null) { - throw new RuntimeException("Call to unknown module: " + moduleId); - } - definition.call(catalystInstance, executorToken, methodId, parameters); - } - - /* package */ void writeModuleDescriptions(JsonWriter writer) throws IOException { - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateJSON"); - try { - writer.beginObject(); - for (ModuleDefinition moduleDef : mModuleTable) { - writer.name(moduleDef.name).beginObject(); - writer.name("moduleID").value(moduleDef.id); - writer.name("supportsWebWorkers").value(moduleDef.target.supportsWebWorkers()); - writer.name("methods").beginObject(); - for (int i = 0; i < moduleDef.methods.size(); i++) { - MethodRegistration method = moduleDef.methods.get(i); - writer.name(method.name).beginObject(); - writer.name("methodID").value(i); - writer.name("type").value(method.method.getType()); - writer.endObject(); - } - writer.endObject(); - moduleDef.target.writeConstantsField(writer, "constants"); - writer.endObject(); - } - writer.endObject(); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - - /* package */ void notifyCatalystInstanceDestroy() { - UiThreadUtil.assertOnUiThread(); - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "NativeModuleRegistry_notifyCatalystInstanceDestroy"); - try { - for (NativeModule nativeModule : mModuleInstances.values()) { - nativeModule.onCatalystInstanceDestroy(); - } - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - - /* package */ void notifyCatalystInstanceInitialized() { - UiThreadUtil.assertOnUiThread(); - - ReactMarker.logMarker("NativeModule_start"); - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "NativeModuleRegistry_notifyCatalystInstanceInitialized"); - try { - for (NativeModule nativeModule : mModuleInstances.values()) { - nativeModule.initialize(); - } - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - ReactMarker.logMarker("NativeModule_end"); - } - } - - /* package */ void notifyReactBridgeInitialized(ReactBridge bridge) { - Systrace.beginSection( - Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, - "NativeModuleRegistry_notifyReactBridgeInitialized"); - try { - for (NativeModule nativeModule : mModuleInstances.values()) { - nativeModule.onReactBridgeInitialized(bridge); - } - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - - public void onBatchComplete() { - for (int i = 0; i < mBatchCompleteListenerModules.size(); i++) { - mBatchCompleteListenerModules.get(i).onBatchComplete(); - } - } - - public void onExecutorUnregistered(ExecutorToken executorToken) { - for (int i = 0; i < mOnExecutorUnregisteredListenerModules.size(); i++) { - mOnExecutorUnregisteredListenerModules.get(i).onExecutorDestroyed(executorToken); - } - } - - public boolean hasModule(Class moduleInterface) { - return mModuleInstances.containsKey(moduleInterface); - } - - public T getModule(Class moduleInterface) { - return (T) Assertions.assertNotNull(mModuleInstances.get(moduleInterface)); - } - - public Collection getAllModules() { - return mModuleInstances.values(); - } - - private static class ModuleDefinition { - public final int id; - public final String name; - public final NativeModule target; - public final ArrayList methods; - - public ModuleDefinition(int id, String name, NativeModule target) { - this.id = id; - this.name = name; - this.target = target; - this.methods = new ArrayList(); - - for (Map.Entry entry : target.getMethods().entrySet()) { - this.methods.add( - new MethodRegistration( - entry.getKey(), "NativeCall__" + target.getName() + "_" + entry.getKey(), - entry.getValue())); - } - } - - public void call( - CatalystInstance catalystInstance, - ExecutorToken executorToken, - int methodId, - ReadableNativeArray parameters) { - MethodRegistration method = this.methods.get(methodId); - Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, method.tracingName); - try { - this.methods.get(methodId).method.invoke(catalystInstance, executorToken, parameters); - } finally { - Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); - } - } - } - - private static class MethodRegistration { - public MethodRegistration(String name, String tracingName, NativeModule.NativeMethod method) { - this.name = name; - this.tracingName = tracingName; - this.method = method; - } - - public String name; - public String tracingName; - public NativeModule.NativeMethod method; - } - - public static class Builder { - - private final HashMap mModules = MapBuilder.newHashMap(); - - public Builder add(NativeModule module) { - NativeModule existing = mModules.get(module.getName()); - if (existing != null && !module.canOverrideExistingModule()) { - throw new IllegalStateException("Native module " + module.getClass().getSimpleName() + - " tried to override " + existing.getClass().getSimpleName() + " for module name " + - module.getName() + ". If this was your intention, return true from " + - module.getClass().getSimpleName() + "#canOverrideExistingModule()"); - } - mModules.put(module.getName(), module); - return this; - } - - public NativeModuleRegistry build() { - List moduleTable = new ArrayList<>(); - Map, NativeModule> moduleInstances = new HashMap<>(); - - int idx = 0; - for (NativeModule module : mModules.values()) { - ModuleDefinition moduleDef = new ModuleDefinition(idx++, module.getName(), module); - moduleTable.add(moduleDef); - moduleInstances.put(module.getClass(), module); - } - return new NativeModuleRegistry(moduleTable, moduleInstances); - } - } -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java deleted file mode 100644 index 6ebf4dc0d..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ProxyJavaScriptExecutor.java +++ /dev/null @@ -1,66 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import javax.annotation.Nullable; - -import com.facebook.soloader.SoLoader; -import com.facebook.proguard.annotations.DoNotStrip; - -/** - * JavaScript executor that delegates JS calls processed by native code back to a java version - * of the native executor interface. - * - * When set as a executor with {@link CatalystInstance.Builder}, catalyst native code will delegate - * low level javascript calls to the implementation of {@link JavaJSExecutor} interface provided - * with the constructor of this class. - */ -@DoNotStrip -public class ProxyJavaScriptExecutor extends JavaScriptExecutor { - static { - ReactBridge.staticInit(); - } - - public static class Factory implements JavaScriptExecutor.Factory { - private final JavaJSExecutor.Factory mJavaJSExecutorFactory; - - public Factory(JavaJSExecutor.Factory javaJSExecutorFactory) { - mJavaJSExecutorFactory = javaJSExecutorFactory; - } - - @Override - public JavaScriptExecutor create(WritableNativeMap jscConfig) throws Exception { - return new ProxyJavaScriptExecutor(mJavaJSExecutorFactory.create()); - } - } - - private @Nullable JavaJSExecutor mJavaJSExecutor; - - /** - * Create {@link ProxyJavaScriptExecutor} instance - * @param executor implementation of {@link JavaJSExecutor} which will be responsible for handling - * javascript calls - */ - public ProxyJavaScriptExecutor(JavaJSExecutor executor) { - mJavaJSExecutor = executor; - initialize(executor); - } - - @Override - public void close() { - if (mJavaJSExecutor != null) { - mJavaJSExecutor.close(); - mJavaJSExecutor = null; - } - } - - private native void initialize(JavaJSExecutor executor); - -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java index d966ce2ff..3758b7e88 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java +++ b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactBridge.java @@ -9,20 +9,9 @@ package com.facebook.react.bridge; -import javax.annotation.Nullable; - -import android.content.res.AssetManager; - -import com.facebook.react.bridge.queue.MessageQueueThread; -import com.facebook.jni.Countable; -import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.soloader.SoLoader; -/** - * Interface to the JS execution environment and means of transport for messages Java<->JS. - */ -@DoNotStrip -public class ReactBridge extends Countable { +public class ReactBridge { private static final String REACT_NATIVE_LIB = "reactnativejni"; private static final String XREACT_NATIVE_LIB = "reactnativejnifb"; @@ -31,81 +20,8 @@ public class ReactBridge extends Countable { staticInit(); } - private final ReactCallback mCallback; - private final JavaScriptExecutor mJSExecutor; - private final MessageQueueThread mNativeModulesQueueThread; - public static void staticInit() { SoLoader.loadLibrary(REACT_NATIVE_LIB); SoLoader.loadLibrary(XREACT_NATIVE_LIB); } - - /** - * @param jsExecutor the JS executor to use to run JS - * @param callback the callback class used to invoke native modules - * @param nativeModulesQueueThread the MessageQueueThread the callbacks should be invoked on - */ - public ReactBridge( - JavaScriptExecutor jsExecutor, - ReactCallback callback, - MessageQueueThread nativeModulesQueueThread) { - mJSExecutor = jsExecutor; - mCallback = callback; - mNativeModulesQueueThread = nativeModulesQueueThread; - initialize(jsExecutor, callback, mNativeModulesQueueThread); - } - - @Override - public void dispose() { - mJSExecutor.close(); - mJSExecutor.dispose(); - super.dispose(); - } - - public void handleMemoryPressure(MemoryPressure level) { - switch (level) { - case UI_HIDDEN: - handleMemoryPressureUiHidden(); - break; - case MODERATE: - handleMemoryPressureModerate(); - break; - case CRITICAL: - handleMemoryPressureCritical(); - break; - default: - throw new IllegalArgumentException("Unknown level: " + level); - } - } - - private native void initialize( - JavaScriptExecutor jsExecutor, - ReactCallback callback, - MessageQueueThread nativeModulesQueueThread); - - /** - * All native functions are not thread safe and appropriate queues should be used - */ - public native void loadScriptFromAssets(AssetManager assetManager, String assetName); - public native void loadScriptFromFile(@Nullable String fileName, @Nullable String sourceURL); - public native void callFunction(ExecutorToken executorToken, String module, String method, NativeArray arguments); - public native void invokeCallback(ExecutorToken executorToken, int callbackID, NativeArray arguments); - public native void setGlobalVariable(String propertyName, String jsonEncodedArgument); - public native boolean supportsProfiling(); - public native void startProfiler(String title); - public native void stopProfiler(String title, String filename); - public native ExecutorToken getMainExecutorToken(); - private native void handleMemoryPressureUiHidden(); - private native void handleMemoryPressureModerate(); - private native void handleMemoryPressureCritical(); - public native void destroy(); - - /** - * This method will return a long representing the underlying JSGlobalContextRef pointer or - * 0 (representing NULL) when in Chrome debug mode, and is only useful if passed back through - * the JNI to native code that will use it with the JavaScriptCore C API. - * **WARNING:** This method is *experimental* and should only be used when no other option is - * available. It will likely change in a future release! - */ - public native long getJavaScriptContextNativePtrExperimental(); } diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java deleted file mode 100644 index 3e5c36be1..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/ReactCallback.java +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import com.facebook.proguard.annotations.DoNotStrip; - -@DoNotStrip -public interface ReactCallback { - - @DoNotStrip - void call(ExecutorToken executorToken, int moduleId, int methodId, ReadableNativeArray parameters); - - @DoNotStrip - void onBatchComplete(); - - @DoNotStrip - void onExecutorUnregistered(ExecutorToken executorToken); -} diff --git a/ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java b/ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java deleted file mode 100644 index e0e3a20ee..000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/bridge/webworkers/WebWorkers.java +++ /dev/null @@ -1,76 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge.webworkers; - -import java.io.File; -import java.io.IOException; - -import com.facebook.proguard.annotations.DoNotStrip; -import com.facebook.react.bridge.queue.MessageQueueThread; -import com.facebook.react.bridge.queue.MessageQueueThreadImpl; -import com.facebook.react.bridge.queue.ProxyQueueThreadExceptionHandler; -import com.facebook.react.common.build.ReactBuildConfig; - -import okhttp3.OkHttpClient; -import okhttp3.Request; -import okhttp3.Response; -import okio.Okio; -import okio.Sink; - -@DoNotStrip -public class WebWorkers { - - /** - * Creates a new MessageQueueThread for a background web worker owned by the JS thread with the - * given MessageQueueThread. - */ - @DoNotStrip - public static MessageQueueThread createWebWorkerThread(int id, MessageQueueThread ownerThread) { - return MessageQueueThreadImpl.startNewBackgroundThread( - "web-worker-" + id, - new ProxyQueueThreadExceptionHandler(ownerThread)); - } - - /** - * Utility method used to help develop web workers on debug builds. In release builds, worker - * scripts need to be packaged with the app, but in dev mode we want to fetch/reload the worker - * script on the fly from the packager. This method fetches the given URL *synchronously* and - * writes it to the specified temp file. - * - * This is exposed from Java only because we don't want to add a C++ networking library dependency - * - * NB: The caller is responsible for deleting the file specified by outFileName when they're done - * with it. - * NB: We write to a temp file instead of returning a String because, depending on the size of the - * worker script, allocating the full script string on the Java heap can cause an OOM. - */ - public static void downloadScriptToFileSync(String url, String outFileName) { - if (!ReactBuildConfig.DEBUG) { - throw new RuntimeException( - "For security reasons, downloading scripts is only allowed in debug builds."); - } - - OkHttpClient client = new OkHttpClient(); - final File out = new File(outFileName); - - Request request = new Request.Builder() - .url(url) - .build(); - - try { - Response response = client.newCall(request).execute(); - - Sink output = Okio.sink(out); - Okio.buffer(response.body().source()).readAll(output); - } catch (IOException e) { - throw new RuntimeException("Exception downloading web worker script to file", e); - } - } -} diff --git a/ReactAndroid/src/main/jni/react/Android.mk b/ReactAndroid/src/main/jni/react/Android.mk deleted file mode 100644 index 311dff6b3..000000000 --- a/ReactAndroid/src/main/jni/react/Android.mk +++ /dev/null @@ -1,33 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_MODULE := libreactnative - -LOCAL_SRC_FILES := \ - Bridge.cpp \ - JSCExecutor.cpp \ - JSCHelpers.cpp \ - MethodCall.cpp \ - Platform.cpp \ - Value.cpp \ - -LOCAL_C_INCLUDES := $(LOCAL_PATH)/.. -LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES) - -LOCAL_CFLAGS := \ - -DLOG_TAG=\"ReactNative\" - -LOCAL_CFLAGS += -Wall -Werror -fexceptions -frtti -CXX11_FLAGS := -std=c++11 -LOCAL_CFLAGS += $(CXX11_FLAGS) -LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS) - -LOCAL_SHARED_LIBRARIES := libfb libfolly_json libjsc libglog - -include $(BUILD_STATIC_LIBRARY) - -$(call import-module,fb) -$(call import-module,folly) -$(call import-module,jsc) -$(call import-module,glog) diff --git a/ReactAndroid/src/main/jni/react/BUCK b/ReactAndroid/src/main/jni/react/BUCK deleted file mode 100644 index e8908b8cb..000000000 --- a/ReactAndroid/src/main/jni/react/BUCK +++ /dev/null @@ -1,78 +0,0 @@ -include_defs('//ReactAndroid/DEFS') - -# We depend on JSC, support the same platforms -SUPPORTED_PLATFORMS = '^android-(armv7|x86)$' - -DEPS = [ - '//native/third-party/android-ndk:android', - '//xplat/fbsystrace:fbsystrace', - '//xplat/folly:molly', - '//xplat/third-party/glog:glog', -] - -PREPROCESSOR_FLAGS = [ - '-DLOG_TAG="ReactNative"', - '-DWITH_JSC_EXTRA_TRACING=1', - '-DWITH_FBSYSTRACE=1', - '-DWITH_REACT_INTERNAL_SETTINGS=1', -] - -def react_library(**kwargs): - cxx_library( - name = 'react', - visibility = [ - react_native_target('jni/react/jni:jni'), - ], - deps = DEPS + JSC_DEPS, - preprocessor_flags = PREPROCESSOR_FLAGS + [ - '-DWITH_FB_MEMORY_PROFILING=1', - ], - **kwargs - ) - -react_library( - soname = 'libreactnative.so', - header_namespace = 'react', - supported_platforms_regex = SUPPORTED_PLATFORMS, - force_static = True, - srcs = [ - 'Bridge.cpp', - 'Value.cpp', - 'MethodCall.cpp', - 'JSCHelpers.cpp', - 'JSCExecutor.cpp', - 'JSCPerfStats.cpp', - 'JSCTracing.cpp', - 'JSCMemory.cpp', - 'JSCLegacyProfiler.cpp', - 'Platform.cpp', - ], - headers = [ - 'JSCTracing.h', - 'JSCLegacyProfiler.h', - 'JSCMemory.h', - 'JSCPerfStats.h', - ], - exported_headers = [ - 'Bridge.h', - 'ExecutorToken.h', - 'ExecutorTokenFactory.h', - 'Executor.h', - 'JSCExecutor.h', - 'JSCHelpers.h', - 'MessageQueueThread.h', - 'MethodCall.h', - 'JSModulesUnbundle.h', - 'Value.h', - 'Platform.h', - 'noncopyable.h', - ], - compiler_flags = [ - '-Wall', - '-std=c++11', - '-fexceptions', - '-fvisibility=hidden', - '-frtti', - '-Wno-pessimizing-move', - ], -) diff --git a/ReactAndroid/src/main/jni/react/Bridge.cpp b/ReactAndroid/src/main/jni/react/Bridge.cpp deleted file mode 100644 index 8940b86fd..000000000 --- a/ReactAndroid/src/main/jni/react/Bridge.cpp +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "Bridge.h" - -#ifdef WITH_FBSYSTRACE -#include -using fbsystrace::FbSystraceSection; -using fbsystrace::FbSystraceAsyncFlow; -#endif -#include - -#include "Platform.h" - -namespace facebook { -namespace react { - -Bridge::Bridge( - JSExecutorFactory* jsExecutorFactory, - std::unique_ptr executorTokenFactory, - std::unique_ptr callback) : - m_callback(std::move(callback)), - m_destroyed(std::make_shared(false)), - m_executorTokenFactory(std::move(executorTokenFactory)) { - std::unique_ptr mainExecutor = jsExecutorFactory->createJSExecutor(this); - // cached to avoid locked map lookup in the common case - m_mainExecutor = mainExecutor.get(); - m_mainExecutorToken = folly::make_unique(registerExecutor( - std::move(mainExecutor), - MessageQueues::getCurrentMessageQueueThread())); -} - -// This must be called on the same thread on which the constructor was called. -Bridge::~Bridge() { - CHECK(m_destroyed->load(std::memory_order_acquire)) << "Bridge::destroy() must be called before deallocating the Bridge!"; -} - -void Bridge::loadApplicationScript(const std::string& script, const std::string& sourceURL) { - m_mainExecutor->loadApplicationScript(script, sourceURL); -} - -void Bridge::loadApplicationUnbundle( - std::unique_ptr unbundle, - const std::string& startupCode, - const std::string& sourceURL) { - m_mainExecutor->loadApplicationUnbundle(std::move(unbundle), startupCode, sourceURL); -} - -void Bridge::callFunction( - ExecutorToken executorToken, - const std::string& moduleId, - const std::string& methodId, - const folly::dynamic& arguments) { - #ifdef WITH_FBSYSTRACE - int systraceCookie = m_systraceCookie++; - std::string tracingName = fbsystrace_is_tracing(TRACE_TAG_REACT_CXX_BRIDGE) ? - folly::to("JSCall__", moduleId, '_', methodId) : std::string(); - FbSystraceAsyncFlow::begin( - TRACE_TAG_REACT_CXX_BRIDGE, - tracingName.c_str(), - systraceCookie); - #endif - - #ifdef WITH_FBSYSTRACE - runOnExecutorQueue(executorToken, [moduleId, methodId, arguments, tracingName = std::move(tracingName), systraceCookie] (JSExecutor* executor) { - FbSystraceAsyncFlow::end( - TRACE_TAG_REACT_CXX_BRIDGE, - tracingName.c_str(), - systraceCookie); - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, tracingName.c_str()); - #else - runOnExecutorQueue(executorToken, [moduleId, methodId, arguments] (JSExecutor* executor) { - #endif - // This is safe because we are running on the executor's thread: it won't - // destruct until after it's been unregistered (which we check above) and - // that will happen on this thread - executor->callFunction(moduleId, methodId, arguments); - }); -} - -void Bridge::invokeCallback(ExecutorToken executorToken, const double callbackId, const folly::dynamic& arguments) { - #ifdef WITH_FBSYSTRACE - int systraceCookie = m_systraceCookie++; - FbSystraceAsyncFlow::begin( - TRACE_TAG_REACT_CXX_BRIDGE, - "", - systraceCookie); - #endif - - #ifdef WITH_FBSYSTRACE - runOnExecutorQueue(executorToken, [callbackId, arguments, systraceCookie] (JSExecutor* executor) { - FbSystraceAsyncFlow::end( - TRACE_TAG_REACT_CXX_BRIDGE, - "", - systraceCookie); - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "Bridge.invokeCallback"); - #else - runOnExecutorQueue(executorToken, [callbackId, arguments] (JSExecutor* executor) { - #endif - executor->invokeCallback(callbackId, arguments); - }); -} - -void Bridge::setGlobalVariable(const std::string& propName, const std::string& jsonValue) { - runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) { - executor->setGlobalVariable(propName, jsonValue); - }); -} - -void* Bridge::getJavaScriptContext() { - // TODO(cjhopman): this seems unsafe unless we require that it is only called on the main js queue. - return m_mainExecutor->getJavaScriptContext(); -} - -bool Bridge::supportsProfiling() { - // Intentionally doesn't post to jsqueue. supportsProfiling() can be called from any thread. - return m_mainExecutor->supportsProfiling(); -} - -void Bridge::startProfiler(const std::string& title) { - runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) { - executor->startProfiler(title); - }); -} - -void Bridge::stopProfiler(const std::string& title, const std::string& filename) { - runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) { - executor->stopProfiler(title, filename); - }); -} - -void Bridge::handleMemoryPressureUiHidden() { - runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) { - executor->handleMemoryPressureUiHidden(); - }); -} - -void Bridge::handleMemoryPressureModerate() { - runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) { - executor->handleMemoryPressureModerate(); - }); -} - -void Bridge::handleMemoryPressureCritical() { - runOnExecutorQueue(*m_mainExecutorToken, [=] (JSExecutor* executor) { - executor->handleMemoryPressureCritical(); - }); -} - -void Bridge::callNativeModules(JSExecutor& executor, const std::string& callJSON, bool isEndOfBatch) { - m_callback->onCallNativeModules(getTokenForExecutor(executor), callJSON, isEndOfBatch); -} - -ExecutorToken Bridge::getMainExecutorToken() const { - return *m_mainExecutorToken.get(); -} - -ExecutorToken Bridge::registerExecutor( - std::unique_ptr executor, - std::shared_ptr messageQueueThread) { - auto token = m_executorTokenFactory->createExecutorToken(); - - std::lock_guard registrationGuard(m_registrationMutex); - - CHECK(m_executorTokenMap.find(executor.get()) == m_executorTokenMap.end()) - << "Trying to register an already registered executor!"; - - m_executorTokenMap.emplace(executor.get(), token); - m_executorMap.emplace( - token, - folly::make_unique(std::move(executor), std::move(messageQueueThread))); - - return token; -} - -std::unique_ptr Bridge::unregisterExecutor(ExecutorToken executorToken) { - std::unique_ptr executor; - - { - std::lock_guard registrationGuard(m_registrationMutex); - - auto it = m_executorMap.find(executorToken); - CHECK(it != m_executorMap.end()) - << "Trying to unregister an executor that was never registered!"; - - executor = std::move(it->second->executor_); - m_executorMap.erase(it); - m_executorTokenMap.erase(executor.get()); - } - - m_callback->onExecutorUnregistered(executorToken); - - return executor; -} - -MessageQueueThread* Bridge::getMessageQueueThread(const ExecutorToken& executorToken) { - std::lock_guard registrationGuard(m_registrationMutex); - auto it = m_executorMap.find(executorToken); - if (it == m_executorMap.end()) { - return nullptr; - } - return it->second->messageQueueThread_.get(); -} - -JSExecutor* Bridge::getExecutor(const ExecutorToken& executorToken) { - std::lock_guard registrationGuard(m_registrationMutex); - auto it = m_executorMap.find(executorToken); - if (it == m_executorMap.end()) { - return nullptr; - } - return it->second->executor_.get(); -} - -ExecutorToken Bridge::getTokenForExecutor(JSExecutor& executor) { - std::lock_guard registrationGuard(m_registrationMutex); - return m_executorTokenMap.at(&executor); -} - -void Bridge::destroy() { - m_destroyed->store(true, std::memory_order_release); - m_mainExecutor = nullptr; - std::unique_ptr mainExecutor = unregisterExecutor(*m_mainExecutorToken); - mainExecutor->destroy(); -} - -void Bridge::runOnExecutorQueue(ExecutorToken executorToken, std::function task) { - if (m_destroyed->load(std::memory_order_acquire)) { - return; - } - - auto executorMessageQueueThread = getMessageQueueThread(executorToken); - if (executorMessageQueueThread == nullptr) { - LOG(WARNING) << "Dropping JS action for executor that has been unregistered..."; - return; - } - - std::shared_ptr isDestroyed = m_destroyed; - executorMessageQueueThread->runOnQueue([this, isDestroyed, executorToken, task=std::move(task)] { - if (isDestroyed->load(std::memory_order_acquire)) { - return; - } - - JSExecutor *executor = getExecutor(executorToken); - if (executor == nullptr) { - LOG(WARNING) << "Dropping JS call for executor that has been unregistered..."; - return; - } - - // The executor is guaranteed to be valid for the duration of the task because: - // 1. the executor is only destroyed after it is unregistered - // 2. the executor is unregistered on this queue - // 3. we just confirmed that the executor hasn't been unregistered above - task(executor); - }); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/Bridge.h b/ReactAndroid/src/main/jni/react/Bridge.h deleted file mode 100644 index 3920fdd7d..000000000 --- a/ReactAndroid/src/main/jni/react/Bridge.h +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include - -#include "ExecutorToken.h" -#include "ExecutorTokenFactory.h" -#include "Executor.h" -#include "MessageQueueThread.h" -#include "MethodCall.h" -#include "JSModulesUnbundle.h" -#include "Value.h" - -namespace folly { - -struct dynamic; - -} - -namespace facebook { -namespace react { - -class BridgeCallback { -public: - virtual ~BridgeCallback() {}; - - virtual void onCallNativeModules( - ExecutorToken executorToken, - const std::string& callJSON, - bool isEndOfBatch) = 0; - - virtual void onExecutorUnregistered(ExecutorToken executorToken) = 0; -}; - -class Bridge; -class ExecutorRegistration { -public: - ExecutorRegistration( - std::unique_ptr executor, - std::shared_ptr executorMessageQueueThread) : - executor_(std::move(executor)), - messageQueueThread_(executorMessageQueueThread) {} - - std::unique_ptr executor_; - std::shared_ptr messageQueueThread_; -}; - -class Bridge { -public: - /** - * This must be called on the main JS thread. - */ - Bridge( - JSExecutorFactory* jsExecutorFactory, - std::unique_ptr executorTokenFactory, - std::unique_ptr callback); - virtual ~Bridge(); - - /** - * Executes a function with the module ID and method ID and any additional - * arguments in JS. - */ - void callFunction( - ExecutorToken executorToken, - const std::string& module, - const std::string& method, - const folly::dynamic& args); - - /** - * Invokes a callback with the cbID, and optional additional arguments in JS. - */ - void invokeCallback(ExecutorToken executorToken, const double callbackId, const folly::dynamic& args); - - /** - * Starts the JS application from an "bundle", i.e. a JavaScript file that - * contains code for all modules and a runtime that resolves and - * executes modules. - */ - void loadApplicationScript(const std::string& script, const std::string& sourceURL); - - /** - * Starts the JS application from an "unbundle", i.e. a backend that stores - * and injects each module as individual file. - */ - void loadApplicationUnbundle( - std::unique_ptr unbundle, - const std::string& startupCode, - const std::string& sourceURL); - void setGlobalVariable(const std::string& propName, const std::string& jsonValue); - void* getJavaScriptContext(); - bool supportsProfiling(); - void startProfiler(const std::string& title); - void stopProfiler(const std::string& title, const std::string& filename); - void handleMemoryPressureUiHidden(); - void handleMemoryPressureModerate(); - void handleMemoryPressureCritical(); - - /** - * Invokes a set of native module calls on behalf of the given executor. - * - * TODO: get rid of isEndOfBatch - */ - void callNativeModules(JSExecutor& executor, const std::string& callJSON, bool isEndOfBatch); - - /** - * Returns the ExecutorToken corresponding to the main JSExecutor. - */ - ExecutorToken getMainExecutorToken() const; - - /** - * Registers the given JSExecutor which runs on the given MessageQueueThread - * with the Bridge. Part of this registration is transfering ownership of this - * JSExecutor to the Bridge for the duration of the registration. - * - * Returns a ExecutorToken which can be used to refer to this JSExecutor - * in the Bridge. - */ - ExecutorToken registerExecutor( - std::unique_ptr executor, - std::shared_ptr executorMessageQueueThread); - - /** - * Unregisters a JSExecutor that was previously registered with this Bridge - * using registerExecutor. Use the ExecutorToken returned from this - * registerExecutor call. This method will return ownership of the unregistered - * executor to the caller for it to retain or tear down. - * - * Returns ownership of the unregistered executor. - */ - std::unique_ptr unregisterExecutor(ExecutorToken executorToken); - - /** - * Synchronously tears down the bridge and the main executor. - */ - void destroy(); -private: - void runOnExecutorQueue(ExecutorToken token, std::function task); - std::unique_ptr m_callback; - // This is used to avoid a race condition where a proxyCallback gets queued after ~Bridge(), - // on the same thread. In that case, the callback will try to run the task on m_callback which - // will have been destroyed within ~Bridge(), thus causing a SIGSEGV. - std::shared_ptr m_destroyed; - JSExecutor* m_mainExecutor; - std::unique_ptr m_mainExecutorToken; - std::unique_ptr m_executorTokenFactory; - std::unordered_map m_executorTokenMap; - std::unordered_map> m_executorMap; - std::mutex m_registrationMutex; - #ifdef WITH_FBSYSTRACE - std::atomic_uint_least32_t m_systraceCookie = ATOMIC_VAR_INIT(); - #endif - - MessageQueueThread* getMessageQueueThread(const ExecutorToken& executorToken); - JSExecutor* getExecutor(const ExecutorToken& executorToken); - inline ExecutorToken getTokenForExecutor(JSExecutor& executor); -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/Executor.h b/ReactAndroid/src/main/jni/react/Executor.h deleted file mode 100644 index c161547b1..000000000 --- a/ReactAndroid/src/main/jni/react/Executor.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -#include "JSModulesUnbundle.h" - -namespace folly { - -struct dynamic; - -} - -namespace facebook { -namespace react { - -class Bridge; -class JSExecutor; -class JSExecutorFactory { -public: - virtual std::unique_ptr createJSExecutor(Bridge *bridge) = 0; - virtual ~JSExecutorFactory() {}; -}; - -class JSExecutor { -public: - /** - * Execute an application script bundle in the JS context. - */ - virtual void loadApplicationScript( - const std::string& script, - const std::string& sourceURL) = 0; - - /** - * Add an application "unbundle" file - */ - virtual void loadApplicationUnbundle( - std::unique_ptr bundle, - const std::string& startupCode, - const std::string& sourceURL) = 0; - - /** - * Executes BatchedBridge.callFunctionReturnFlushedQueue with the module ID, - * method ID and optional additional arguments in JS. The executor is responsible - * for using Bridge->callNativeModules to invoke any necessary native modules methods. - */ - virtual void callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) = 0; - - /** - * Executes BatchedBridge.invokeCallbackAndReturnFlushedQueue with the cbID, - * and optional additional arguments in JS and returns the next queue. The executor - * is responsible for using Bridge->callNativeModules to invoke any necessary - * native modules methods. - */ - virtual void invokeCallback(const double callbackId, const folly::dynamic& arguments) = 0; - - virtual void setGlobalVariable( - const std::string& propName, - const std::string& jsonValue) = 0; - virtual void* getJavaScriptContext() { - return nullptr; - }; - virtual bool supportsProfiling() { - return false; - }; - virtual void startProfiler(const std::string &titleString) {}; - virtual void stopProfiler(const std::string &titleString, const std::string &filename) {}; - virtual void handleMemoryPressureUiHidden() {}; - virtual void handleMemoryPressureModerate() {}; - virtual void handleMemoryPressureCritical() { - handleMemoryPressureModerate(); - }; - virtual void destroy() {}; - virtual ~JSExecutor() {}; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/ExecutorToken.h b/ReactAndroid/src/main/jni/react/ExecutorToken.h deleted file mode 100644 index a630e90d3..000000000 --- a/ReactAndroid/src/main/jni/react/ExecutorToken.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include "Executor.h" - -namespace facebook { -namespace react { - -/** - * This class exists so that we have a type for the shared_ptr on ExecutorToken - * that implements a virtual destructor. - */ -class PlatformExecutorToken { -public: - virtual ~PlatformExecutorToken() {} -}; - -/** - * Class corresponding to a JS VM that can call into native modules. This is - * passed to native modules to allow their JS module calls/callbacks to be - * routed back to the proper JS VM on the proper thread. - */ -class ExecutorToken { -public: - /** - * This should only be used by the implementation of the platform ExecutorToken. - * Do not use as a client of ExecutorToken. - */ - explicit ExecutorToken(std::shared_ptr platformToken) : - platformToken_(platformToken) {} - - std::shared_ptr getPlatformExecutorToken() const { - return platformToken_; - } - - bool operator==(const ExecutorToken& other) const { - return platformToken_.get() == other.platformToken_.get(); - } - -private: - std::shared_ptr platformToken_; -}; - -} } - -namespace std { - template<> - struct hash { - const size_t operator()(const facebook::react::ExecutorToken& token) const { - return (size_t) token.getPlatformExecutorToken().get(); - } - }; -} diff --git a/ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h b/ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h deleted file mode 100644 index 5d2d42179..000000000 --- a/ReactAndroid/src/main/jni/react/ExecutorTokenFactory.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include "ExecutorToken.h" -#include "Executor.h" - -namespace facebook { -namespace react { - -/** - * Class that knows how to create the platform-specific implementation - * of ExecutorToken. - */ -class ExecutorTokenFactory { -public: - virtual ~ExecutorTokenFactory() {} - - /** - * Creates a new ExecutorToken. - */ - virtual ExecutorToken createExecutorToken() const = 0; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp deleted file mode 100644 index c76c24ed1..000000000 --- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp +++ /dev/null @@ -1,709 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSCExecutor.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Bridge.h" -#include "JSCHelpers.h" -#include "Platform.h" -#include "Value.h" - -#ifdef WITH_JSC_EXTRA_TRACING -#include "JSCTracing.h" -#include "JSCLegacyProfiler.h" -#include -#endif - -#ifdef WITH_JSC_MEMORY_PRESSURE -#include -#endif - -#ifdef WITH_FBSYSTRACE -#include -using fbsystrace::FbSystraceSection; -#endif - -#ifdef WITH_FB_MEMORY_PROFILING -#include "JSCMemory.h" -#endif - -#ifdef WITH_FB_JSC_TUNING -#include -#endif - -#ifdef JSC_HAS_PERF_STATS_API -#include "JSCPerfStats.h" -#endif - -static const int64_t NANOSECONDS_IN_SECOND = 1000000000LL; -static const int64_t NANOSECONDS_IN_MILLISECOND = 1000000LL; - -namespace facebook { -namespace react { - -static std::unordered_map s_globalContextRefToJSCExecutor; - -static JSValueRef nativePerformanceNow( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); -static JSValueRef nativeInjectHMRUpdate( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); - -std::unique_ptr JSCExecutorFactory::createJSExecutor(Bridge *bridge) { - return std::unique_ptr(new JSCExecutor(bridge, cacheDir_, m_jscConfig)); -} - -JSCExecutor::JSCExecutor(Bridge *bridge, const std::string& cacheDir, const folly::dynamic& jscConfig) : - m_bridge(bridge), - m_deviceCacheDir(cacheDir), - m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()), - m_jscConfig(jscConfig) { - initOnJSVMThread(); -} - -JSCExecutor::JSCExecutor( - Bridge *bridge, - int workerId, - JSCExecutor *owner, - const std::string& script, - const std::unordered_map& globalObjAsJSON, - const folly::dynamic& jscConfig) : - m_bridge(bridge), - m_workerId(workerId), - m_owner(owner), - m_deviceCacheDir(owner->m_deviceCacheDir), - m_messageQueueThread(MessageQueues::getCurrentMessageQueueThread()), - m_jscConfig(jscConfig) { - // We post initOnJSVMThread here so that the owner doesn't have to wait for - // initialization on its own thread - m_messageQueueThread->runOnQueue([this, script, globalObjAsJSON] () { - initOnJSVMThread(); - - installGlobalFunction(m_context, "postMessage", nativePostMessage); - - for (auto& it : globalObjAsJSON) { - setGlobalVariable(it.first, it.second); - } - - // Try to load the script from the network if script is a URL - // NB: For security, this will only work in debug builds - std::string scriptSrc; - if (script.find("http://") == 0 || script.find("https://") == 0) { - std::stringstream outfileBuilder; - outfileBuilder << m_deviceCacheDir << "/workerScript" << m_workerId << ".js"; - scriptSrc = WebWorkerUtil::loadScriptFromNetworkSync(script, outfileBuilder.str()); - } else { - // TODO(9604438): Protect against script does not exist - scriptSrc = WebWorkerUtil::loadScriptFromAssets(script); - } - - // TODO(9994180): Throw on error - loadApplicationScript(scriptSrc, script); - }); -} - -JSCExecutor::~JSCExecutor() { - CHECK(*m_isDestroyed) << "JSCExecutor::destroy() must be called before its destructor!"; -} - -void JSCExecutor::destroy() { - *m_isDestroyed = true; - if (m_messageQueueThread->isOnThread()) { - terminateOnJSVMThread(); - } else { - m_messageQueueThread->runOnQueueSync([this] () { - terminateOnJSVMThread(); - }); - } -} - -void JSCExecutor::initOnJSVMThread() { - #if defined(WITH_FB_JSC_TUNING) - configureJSCForAndroid(m_jscConfig); - #endif - m_context = JSGlobalContextCreateInGroup(nullptr, nullptr); - s_globalContextRefToJSCExecutor[m_context] = this; - installGlobalFunction(m_context, "nativeFlushQueueImmediate", nativeFlushQueueImmediate); - installGlobalFunction(m_context, "nativePerformanceNow", nativePerformanceNow); - installGlobalFunction(m_context, "nativeStartWorker", nativeStartWorker); - installGlobalFunction(m_context, "nativePostMessageToWorker", nativePostMessageToWorker); - installGlobalFunction(m_context, "nativeTerminateWorker", nativeTerminateWorker); - installGlobalFunction(m_context, "nativeInjectHMRUpdate", nativeInjectHMRUpdate); - - installGlobalFunction(m_context, "nativeLoggingHook", JSLogging::nativeHook); - - #ifdef WITH_JSC_EXTRA_TRACING - addNativeTracingHooks(m_context); - addNativeProfilingHooks(m_context); - PerfLogging::installNativeHooks(m_context); - #endif - - #ifdef WITH_FB_MEMORY_PROFILING - addNativeMemoryHooks(m_context); - #endif - - #ifdef JSC_HAS_PERF_STATS_API - addJSCPerfStatsHooks(m_context); - #endif - - #if defined(WITH_FB_JSC_TUNING) - configureJSContextForAndroid(m_context, m_jscConfig, m_deviceCacheDir); - #endif -} - -void JSCExecutor::terminateOnJSVMThread() { - // terminateOwnedWebWorker mutates m_ownedWorkers so collect all the workers - // to terminate first - std::vector workerIds; - for (auto& it : m_ownedWorkers) { - workerIds.push_back(it.first); - } - for (int workerId : workerIds) { - terminateOwnedWebWorker(workerId); - } - - m_batchedBridge.reset(); - m_flushedQueueObj.reset(); - m_callFunctionObj.reset(); - m_invokeCallbackObj.reset(); - - s_globalContextRefToJSCExecutor.erase(m_context); - JSGlobalContextRelease(m_context); - m_context = nullptr; -} - -// Checks if the user is in the pre-parsing cache & StringRef QE. -// Should be removed when these features are no longer gated. -bool JSCExecutor::usePreparsingAndStringRef(){ - return m_jscConfig.getDefault("PreparsingStringRef", true).getBool(); -} - -void JSCExecutor::loadApplicationScript( - const std::string& script, - const std::string& sourceURL) { - ReactMarker::logMarker("loadApplicationScript_startStringConvert"); -#if WITH_FBJSCEXTENSIONS - JSStringRef jsScriptRef; - if (usePreparsingAndStringRef()){ - jsScriptRef = JSStringCreateWithUTF8CStringExpectAscii(script.c_str(), script.size()); - } else { - jsScriptRef = JSStringCreateWithUTF8CString(script.c_str()); - } - - String jsScript = String::adopt(jsScriptRef); -#else - String jsScript = String::createExpectingAscii(script); -#endif - - ReactMarker::logMarker("loadApplicationScript_endStringConvert"); - - String jsSourceURL(sourceURL.c_str()); - #ifdef WITH_FBSYSTRACE - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor::loadApplicationScript", - "sourceURL", sourceURL); - #endif - evaluateScript(m_context, jsScript, jsSourceURL); - flush(); - ReactMarker::logMarker("RUN_JS_BUNDLE_END"); - ReactMarker::logMarker("CREATE_REACT_CONTEXT_END"); -} - -void JSCExecutor::loadApplicationUnbundle( - std::unique_ptr unbundle, - const std::string& startupCode, - const std::string& sourceURL) { - if (!m_unbundle) { - installGlobalFunction(m_context, "nativeRequire", nativeRequire); - } - m_unbundle = std::move(unbundle); - loadApplicationScript(startupCode, sourceURL); -} - -bool JSCExecutor::ensureBatchedBridgeObject() { - if (m_batchedBridge) { - return true; - } - - Value batchedBridgeValue = Object::getGlobalObject(m_context).getProperty("__fbBatchedBridge"); - if (batchedBridgeValue.isUndefined()) { - return false; - } - m_batchedBridge = folly::make_unique(batchedBridgeValue.asObject()); - m_flushedQueueObj = folly::make_unique(m_batchedBridge->getProperty("flushedQueue").asObject()); - m_callFunctionObj = folly::make_unique(m_batchedBridge->getProperty("callFunctionReturnFlushedQueue").asObject()); - m_invokeCallbackObj = folly::make_unique(m_batchedBridge->getProperty("invokeCallbackAndReturnFlushedQueue").asObject()); - return true; -} - -void JSCExecutor::flush() { - #ifdef WITH_FBSYSTRACE - FbSystraceSection s( - TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.flush"); - #endif - - if (!ensureBatchedBridgeObject()) { - throwJSExecutionException( - "Could not connect to development server.\n" - "Try the following to fix the issue:\n" - "Ensure that the packager server is running\n" - "Ensure that your device/emulator is connected to your machine and has USB debugging enabled - run 'adb devices' to see a list of connected devices\n" - "If you're on a physical device connected to the same machine, run 'adb reverse tcp:8081 tcp:8081' to forward requests from your device\n" - "If your device is on the same Wi-Fi network, set 'Debug server host & port for device' in 'Dev settings' to your machine's IP address and the port of the local dev server - e.g. 10.0.1.1:8081"); - } - - std::string calls = m_flushedQueueObj->callAsFunction().toJSONString(); - m_bridge->callNativeModules(*this, calls, true); -} - -void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) { -#ifdef WITH_FBSYSTRACE - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.callFunction"); -#endif - - if (!ensureBatchedBridgeObject()) { - throwJSExecutionException( - "Couldn't call JS module %s, method %s: bridge configuration isn't available. This " - "probably means you're calling a JS module method before bridge setup has completed or without a JS bundle loaded.", - moduleId.c_str(), - methodId.c_str()); - } - - String argsString = String(folly::toJson(std::move(arguments)).c_str()); - String moduleIdStr(moduleId.c_str()); - String methodIdStr(methodId.c_str()); - JSValueRef args[] = { - JSValueMakeString(m_context, moduleIdStr), - JSValueMakeString(m_context, methodIdStr), - Value::fromJSON(m_context, argsString) - }; - auto result = m_callFunctionObj->callAsFunction(3, args); - m_bridge->callNativeModules(*this, result.toJSONString(), true); -} - -void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) { -#ifdef WITH_FBSYSTRACE - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.invokeCallback"); -#endif - - if (!ensureBatchedBridgeObject()) { - throwJSExecutionException( - "Couldn't invoke JS callback %d: bridge configuration isn't available. This shouldn't be possible. Congratulations.", (int) callbackId); - } - - String argsString = String(folly::toJson(std::move(arguments)).c_str()); - JSValueRef args[] = { - JSValueMakeNumber(m_context, callbackId), - Value::fromJSON(m_context, argsString) - }; - auto result = m_invokeCallbackObj->callAsFunction(2, args); - m_bridge->callNativeModules(*this, result.toJSONString(), true); -} - -void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) { - auto globalObject = JSContextGetGlobalObject(m_context); - String jsPropertyName(propName.c_str()); - - String jsValueJSON(jsonValue.c_str()); - auto valueToInject = JSValueMakeFromJSONString(m_context, jsValueJSON); - - JSObjectSetProperty(m_context, globalObject, jsPropertyName, valueToInject, 0, NULL); -} - -void* JSCExecutor::getJavaScriptContext() { - return m_context; -} - -bool JSCExecutor::supportsProfiling() { - #ifdef WITH_FBSYSTRACE - return true; - #else - return false; - #endif -} - -void JSCExecutor::startProfiler(const std::string &titleString) { - #ifdef WITH_JSC_EXTRA_TRACING - JSStringRef title = JSStringCreateWithUTF8CString(titleString.c_str()); - #if WITH_REACT_INTERNAL_SETTINGS - JSStartProfiling(m_context, title, false); - #else - JSStartProfiling(m_context, title); - #endif - JSStringRelease(title); - #endif -} - -void JSCExecutor::stopProfiler(const std::string &titleString, const std::string& filename) { - #ifdef WITH_JSC_EXTRA_TRACING - JSStringRef title = JSStringCreateWithUTF8CString(titleString.c_str()); - facebook::react::stopAndOutputProfilingFile(m_context, title, filename.c_str()); - JSStringRelease(title); - #endif -} - -void JSCExecutor::handleMemoryPressureUiHidden() { - #ifdef WITH_JSC_MEMORY_PRESSURE - JSHandleMemoryPressure(this, m_context, JSMemoryPressure::UI_HIDDEN); - #endif -} - -void JSCExecutor::handleMemoryPressureModerate() { - #ifdef WITH_JSC_MEMORY_PRESSURE - JSHandleMemoryPressure(this, m_context, JSMemoryPressure::MODERATE); - #endif -} - -void JSCExecutor::handleMemoryPressureCritical() { - #ifdef WITH_JSC_MEMORY_PRESSURE - JSHandleMemoryPressure(this, m_context, JSMemoryPressure::CRITICAL); - #endif -} - -void JSCExecutor::flushQueueImmediate(std::string queueJSON) { - m_bridge->callNativeModules(*this, queueJSON, false); -} - -void JSCExecutor::loadModule(uint32_t moduleId) { - auto module = m_unbundle->getModule(moduleId); - auto sourceUrl = String::createExpectingAscii(module.name); - auto source = String::createExpectingAscii(module.code); - evaluateScript(m_context, source, sourceUrl); -} - -int JSCExecutor::addWebWorker( - const std::string& script, - JSValueRef workerRef, - JSValueRef globalObjRef) { - static std::atomic_int nextWorkerId(1); - int workerId = nextWorkerId++; - - Object globalObj = Value(m_context, globalObjRef).asObject(); - - auto workerJscConfig = m_jscConfig; - workerJscConfig["isWebWorker"] = true; - - auto workerMQT = WebWorkerUtil::createWebWorkerThread(workerId, m_messageQueueThread.get()); - std::unique_ptr worker; - workerMQT->runOnQueueSync([this, &worker, &script, &globalObj, workerId, &workerJscConfig] () { - worker.reset(new JSCExecutor(m_bridge, workerId, this, script, globalObj.toJSONMap(), workerJscConfig)); - }); - - Object workerObj = Value(m_context, workerRef).asObject(); - workerObj.makeProtected(); - - JSCExecutor *workerPtr = worker.get(); - std::shared_ptr sharedMessageQueueThread = worker->m_messageQueueThread; - ExecutorToken token = m_bridge->registerExecutor( - std::move(worker), - std::move(sharedMessageQueueThread)); - - m_ownedWorkers.emplace( - std::piecewise_construct, - std::forward_as_tuple(workerId), - std::forward_as_tuple(workerPtr, token, std::move(workerObj))); - - return workerId; -} - -void JSCExecutor::postMessageToOwnedWebWorker(int workerId, JSValueRef message, JSValueRef *exn) { - auto worker = m_ownedWorkers.at(workerId).executor; - std::string msgString = Value(m_context, message).toJSONString(); - - std::shared_ptr isWorkerDestroyed = worker->m_isDestroyed; - worker->m_messageQueueThread->runOnQueue([isWorkerDestroyed, worker, msgString] () { - if (*isWorkerDestroyed) { - return; - } - worker->receiveMessageFromOwner(msgString); - }); -} - -void JSCExecutor::postMessageToOwner(JSValueRef msg) { - std::string msgString = Value(m_context, msg).toJSONString(); - std::shared_ptr ownerIsDestroyed = m_owner->m_isDestroyed; - m_owner->m_messageQueueThread->runOnQueue([workerId=m_workerId, owner=m_owner, ownerIsDestroyed, msgString] () { - if (*ownerIsDestroyed) { - return; - } - owner->receiveMessageFromOwnedWebWorker(workerId, msgString); - }); -} - -void JSCExecutor::receiveMessageFromOwnedWebWorker(int workerId, const std::string& json) { - Object* workerObj; - try { - workerObj = &m_ownedWorkers.at(workerId).jsObj; - } catch (std::out_of_range& e) { - // Worker was already terminated - return; - } - - Value onmessageValue = workerObj->getProperty("onmessage"); - if (onmessageValue.isUndefined()) { - return; - } - - JSValueRef args[] = { createMessageObject(json) }; - onmessageValue.asObject().callAsFunction(1, args); - - flush(); -} - -void JSCExecutor::receiveMessageFromOwner(const std::string& msgString) { - CHECK(m_owner) << "Received message in a Executor that doesn't have an owner!"; - - JSValueRef args[] = { createMessageObject(msgString) }; - Value onmessageValue = Object::getGlobalObject(m_context).getProperty("onmessage"); - onmessageValue.asObject().callAsFunction(1, args); -} - -void JSCExecutor::terminateOwnedWebWorker(int workerId) { - auto& workerRegistration = m_ownedWorkers.at(workerId); - std::shared_ptr workerMQT = workerRegistration.executor->m_messageQueueThread; - ExecutorToken workerExecutorToken = workerRegistration.executorToken; - m_ownedWorkers.erase(workerId); - - std::unique_ptr worker = m_bridge->unregisterExecutor(workerExecutorToken); - worker->destroy(); - worker.reset(); - workerMQT->quitSynchronous(); -} - -Object JSCExecutor::createMessageObject(const std::string& msgJson) { - Value rebornJSMsg = Value::fromJSON(m_context, String(msgJson.c_str())); - Object messageObject = Object::create(m_context); - messageObject.setProperty("data", rebornJSMsg); - return messageObject; -} - -// Native JS hooks -JSValueRef JSCExecutor::nativePostMessage( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - if (argumentCount != 1) { - *exception = makeJSCException(ctx, "postMessage got wrong number of arguments"); - return JSValueMakeUndefined(ctx); - } - JSValueRef msg = arguments[0]; - JSCExecutor *webWorker = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx)); - - webWorker->postMessageToOwner(msg); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef makeInvalidModuleIdJSCException( - JSContextRef ctx, - const JSValueRef id, - JSValueRef *exception) { - std::string message = "Received invalid module ID: "; - message += String::adopt(JSValueToStringCopy(ctx, id, exception)).str(); - return makeJSCException(ctx, message.c_str()); -} - -JSValueRef JSCExecutor::nativeRequire( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - - if (argumentCount != 1) { - *exception = makeJSCException(ctx, "Got wrong number of args"); - return JSValueMakeUndefined(ctx); - } - - JSCExecutor *executor; - try { - executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx)); - } catch (std::out_of_range& e) { - *exception = makeJSCException(ctx, "Global JS context didn't map to a valid executor"); - return JSValueMakeUndefined(ctx); - } - - double moduleId = JSValueToNumber(ctx, arguments[0], exception); - if (moduleId <= (double) std::numeric_limits::max() && moduleId >= 0.0) { - try { - executor->loadModule(moduleId); - } catch (JSModulesUnbundle::ModuleNotFound&) { - *exception = makeInvalidModuleIdJSCException(ctx, arguments[0], exception); - } - } else { - *exception = makeInvalidModuleIdJSCException(ctx, arguments[0], exception); - } - return JSValueMakeUndefined(ctx); -} - -static JSValueRef createErrorString(JSContextRef ctx, const char *msg) { - return JSValueMakeString(ctx, String(msg)); -} - -JSValueRef JSCExecutor::nativeFlushQueueImmediate( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - if (argumentCount != 1) { - *exception = createErrorString(ctx, "Got wrong number of args"); - return JSValueMakeUndefined(ctx); - } - - JSCExecutor *executor; - try { - executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx)); - } catch (std::out_of_range& e) { - *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor"); - return JSValueMakeUndefined(ctx); - } - - std::string resStr = Value(ctx, arguments[0]).toJSONString(); - - executor->flushQueueImmediate(resStr); - - return JSValueMakeUndefined(ctx); -} - -JSValueRef JSCExecutor::nativeStartWorker( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - if (argumentCount != 3) { - *exception = createErrorString(ctx, "Got wrong number of args"); - return JSValueMakeUndefined(ctx); - } - - std::string scriptFile = Value(ctx, arguments[0]).toString().str(); - - JSValueRef worker = arguments[1]; - JSValueRef globalObj = arguments[2]; - - JSCExecutor *executor; - try { - executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx)); - } catch (std::out_of_range& e) { - *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor"); - return JSValueMakeUndefined(ctx); - } - - int workerId = executor->addWebWorker(scriptFile, worker, globalObj); - - return JSValueMakeNumber(ctx, workerId); -} - -JSValueRef JSCExecutor::nativePostMessageToWorker( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - if (argumentCount != 2) { - *exception = createErrorString(ctx, "Got wrong number of args"); - return JSValueMakeUndefined(ctx); - } - - double workerDouble = JSValueToNumber(ctx, arguments[0], exception); - if (workerDouble != workerDouble) { - *exception = createErrorString(ctx, "Got invalid worker id"); - return JSValueMakeUndefined(ctx); - } - - JSCExecutor *executor; - try { - executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx)); - } catch (std::out_of_range& e) { - *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor"); - return JSValueMakeUndefined(ctx); - } - - executor->postMessageToOwnedWebWorker((int) workerDouble, arguments[1], exception); - - return JSValueMakeUndefined(ctx); -} - -JSValueRef JSCExecutor::nativeTerminateWorker( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception) { - if (argumentCount != 1) { - *exception = createErrorString(ctx, "Got wrong number of args"); - return JSValueMakeUndefined(ctx); - } - - double workerDouble = JSValueToNumber(ctx, arguments[0], exception); - if (workerDouble != workerDouble) { - *exception = createErrorString(ctx, "Got invalid worker id"); - return JSValueMakeUndefined(ctx); - } - - JSCExecutor *executor; - try { - executor = s_globalContextRefToJSCExecutor.at(JSContextGetGlobalContext(ctx)); - } catch (std::out_of_range& e) { - *exception = createErrorString(ctx, "Global JS context didn't map to a valid executor"); - return JSValueMakeUndefined(ctx); - } - - executor->terminateOwnedWebWorker((int) workerDouble); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativePerformanceNow( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) { - // This is equivalent to android.os.SystemClock.elapsedRealtime() in native - struct timespec now; - clock_gettime(CLOCK_MONOTONIC_RAW, &now); - int64_t nano = now.tv_sec * NANOSECONDS_IN_SECOND + now.tv_nsec; - return JSValueMakeNumber(ctx, (nano / (double)NANOSECONDS_IN_MILLISECOND)); -} - -static JSValueRef nativeInjectHMRUpdate( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) { - String execJSString = Value(ctx, arguments[0]).toString(); - String jsURL = Value(ctx, arguments[1]).toString(); - evaluateScript(ctx, execJSString, jsURL); - return JSValueMakeUndefined(ctx); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.h b/ReactAndroid/src/main/jni/react/JSCExecutor.h deleted file mode 100644 index 5faca08ba..000000000 --- a/ReactAndroid/src/main/jni/react/JSCExecutor.h +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include -#include - -#include "ExecutorToken.h" -#include "Executor.h" -#include "JSCHelpers.h" -#include "Value.h" - -namespace facebook { -namespace react { - -class MessageQueueThread; - -class JSCExecutorFactory : public JSExecutorFactory { -public: - JSCExecutorFactory(const std::string& cacheDir, const folly::dynamic& jscConfig) : - cacheDir_(cacheDir), - m_jscConfig(jscConfig) {} - virtual std::unique_ptr createJSExecutor(Bridge *bridge) override; -private: - std::string cacheDir_; - folly::dynamic m_jscConfig; -}; - -class JSCExecutor; -class WorkerRegistration : public noncopyable { -public: - explicit WorkerRegistration(JSCExecutor* executor, ExecutorToken executorToken, Object jsObj) : - executor(executor), - executorToken(executorToken), - jsObj(std::move(jsObj)) {} - - JSCExecutor *executor; - ExecutorToken executorToken; - Object jsObj; -}; - -class JSCExecutor : public JSExecutor { -public: - /** - * Must be invoked from thread this Executor will run on. - */ - explicit JSCExecutor(Bridge *bridge, const std::string& cacheDir, const folly::dynamic& jscConfig); - ~JSCExecutor() override; - - virtual void loadApplicationScript( - const std::string& script, - const std::string& sourceURL) override; - virtual void loadApplicationUnbundle( - std::unique_ptr unbundle, - const std::string& startupCode, - const std::string& sourceURL) override; - virtual void callFunction( - const std::string& moduleId, - const std::string& methodId, - const folly::dynamic& arguments) override; - virtual void invokeCallback( - const double callbackId, - const folly::dynamic& arguments) override; - virtual void setGlobalVariable( - const std::string& propName, - const std::string& jsonValue) override; - virtual void* getJavaScriptContext() override; - virtual bool supportsProfiling() override; - virtual void startProfiler(const std::string &titleString) override; - virtual void stopProfiler(const std::string &titleString, const std::string &filename) override; - virtual void handleMemoryPressureUiHidden() override; - virtual void handleMemoryPressureModerate() override; - virtual void handleMemoryPressureCritical() override; - virtual void destroy() override; - - void installNativeHook(const char *name, JSObjectCallAsFunctionCallback callback); - -private: - JSGlobalContextRef m_context; - Bridge *m_bridge; - int m_workerId = 0; // if this is a worker executor, this is non-zero - JSCExecutor *m_owner = nullptr; // if this is a worker executor, this is non-null - std::shared_ptr m_isDestroyed = std::shared_ptr(new bool(false)); - std::unordered_map m_ownedWorkers; - std::string m_deviceCacheDir; - std::shared_ptr m_messageQueueThread; - std::unique_ptr m_unbundle; - folly::dynamic m_jscConfig; - std::unique_ptr m_batchedBridge; - std::unique_ptr m_flushedQueueObj; - std::unique_ptr m_callFunctionObj; - std::unique_ptr m_invokeCallbackObj; - - /** - * WebWorker constructor. Must be invoked from thread this Executor will run on. - */ - explicit JSCExecutor( - Bridge *bridge, - int workerId, - JSCExecutor *owner, - const std::string& script, - const std::unordered_map& globalObjAsJSON, - const folly::dynamic& jscConfig); - - void initOnJSVMThread(); - void terminateOnJSVMThread(); - void flush(); - void flushQueueImmediate(std::string queueJSON); - void loadModule(uint32_t moduleId); - bool ensureBatchedBridgeObject(); - - int addWebWorker(const std::string& script, JSValueRef workerRef, JSValueRef globalObjRef); - void postMessageToOwnedWebWorker(int worker, JSValueRef message, JSValueRef *exn); - void postMessageToOwner(JSValueRef result); - void receiveMessageFromOwnedWebWorker(int workerId, const std::string& message); - void receiveMessageFromOwner(const std::string &msgString); - void terminateOwnedWebWorker(int worker); - Object createMessageObject(const std::string& msgData); - bool usePreparsingAndStringRef(); - - static JSValueRef nativeStartWorker( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); - static JSValueRef nativePostMessageToWorker( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); - static JSValueRef nativeTerminateWorker( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); - static JSValueRef nativePostMessage( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); - static JSValueRef nativeRequire( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); - static JSValueRef nativeFlushQueueImmediate( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef *exception); -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp b/ReactAndroid/src/main/jni/react/JSCHelpers.cpp deleted file mode 100644 index 687c775db..000000000 --- a/ReactAndroid/src/main/jni/react/JSCHelpers.cpp +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSCHelpers.h" - -#include -#include - -#include "Value.h" - -#if WITH_FBJSCEXTENSIONS -#include -#endif - -namespace facebook { -namespace react { - -void installGlobalFunction( - JSGlobalContextRef ctx, - const char* name, - JSObjectCallAsFunctionCallback callback) { - JSStringRef jsName = JSStringCreateWithUTF8CString(name); - JSObjectRef functionObj = JSObjectMakeFunctionWithCallback( - ctx, jsName, callback); - JSObjectRef globalObject = JSContextGetGlobalObject(ctx); - JSObjectSetProperty(ctx, globalObject, jsName, functionObj, 0, NULL); - JSStringRelease(jsName); -} - -JSValueRef makeJSCException( - JSContextRef ctx, - const char* exception_text) { - JSStringRef message = JSStringCreateWithUTF8CString(exception_text); - JSValueRef exceptionString = JSValueMakeString(ctx, message); - JSStringRelease(message); - return JSValueToObject(ctx, exceptionString, NULL); -} - -JSValueRef evaluateScript(JSContextRef context, JSStringRef script, JSStringRef source) { - JSValueRef exn, result; - result = JSEvaluateScript(context, script, NULL, source, 0, &exn); - if (result == nullptr) { - Value exception = Value(context, exn); - std::string exceptionText = exception.toString().str(); - LOG(ERROR) << "Got JS Exception: " << exceptionText; - auto line = exception.asObject().getProperty("line"); - - std::ostringstream locationInfo; - std::string file = source != nullptr ? String::ref(source).str() : ""; - locationInfo << "(" << (file.length() ? file : ""); - if (line != nullptr && line.isNumber()) { - locationInfo << ":" << line.asInteger(); - } - locationInfo << ")"; - throwJSExecutionException("%s %s", exceptionText.c_str(), locationInfo.str().c_str()); - } - return result; -} - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCHelpers.h b/ReactAndroid/src/main/jni/react/JSCHelpers.h deleted file mode 100644 index 31f1f615f..000000000 --- a/ReactAndroid/src/main/jni/react/JSCHelpers.h +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -#include -#include -#include - -namespace facebook { -namespace react { - -struct JsException : std::runtime_error { - using std::runtime_error::runtime_error; -}; - -inline void throwJSExecutionException(const char* msg) { - throw JsException(msg); -} - -template -inline void throwJSExecutionException(const char* fmt, Args... args) { - int msgSize = snprintf(nullptr, 0, fmt, args...); - msgSize = std::min(512, msgSize + 1); - char *msg = (char*) alloca(msgSize); - snprintf(msg, msgSize, fmt, args...); - throw JsException(msg); -} - -void installGlobalFunction( - JSGlobalContextRef ctx, - const char* name, - JSObjectCallAsFunctionCallback callback); - -JSValueRef makeJSCException( - JSContextRef ctx, - const char* exception_text); - -JSValueRef evaluateScript( - JSContextRef ctx, - JSStringRef script, - JSStringRef sourceURL); - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp deleted file mode 100644 index a147b57a9..000000000 --- a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.cpp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include -#include -#include -#include -#include "JSCHelpers.h" -#include "JSCLegacyProfiler.h" -#include "Value.h" - -static JSValueRef nativeProfilerStart( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (argumentCount < 1) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "nativeProfilerStart: requires at least 1 argument"); - } - return JSValueMakeUndefined(ctx); - } - - JSStringRef title = JSValueToStringCopy(ctx, arguments[0], exception); - #if WITH_REACT_INTERNAL_SETTINGS - JSStartProfiling(ctx, title, false); - #else - JSStartProfiling(ctx, title); - #endif - JSStringRelease(title); - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeProfilerEnd( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (argumentCount < 1) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "nativeProfilerEnd: requires at least 1 argument"); - } - return JSValueMakeUndefined(ctx); - } - - std::string writeLocation("/sdcard/"); - if (argumentCount > 1) { - JSStringRef fileName = JSValueToStringCopy(ctx, arguments[1], exception); - writeLocation += facebook::react::String::ref(fileName).str(); - JSStringRelease(fileName); - } else { - writeLocation += "profile.json"; - } - JSStringRef title = JSValueToStringCopy(ctx, arguments[0], exception); - JSEndProfilingAndRender(ctx, title, writeLocation.c_str()); - JSStringRelease(title); - return JSValueMakeUndefined(ctx); -} - -namespace facebook { -namespace react { - -void stopAndOutputProfilingFile( - JSContextRef ctx, - JSStringRef title, - const char *filename) { - JSEndProfilingAndRender(ctx, title, filename); -} - -void addNativeProfilingHooks(JSGlobalContextRef ctx) { - JSEnableByteCodeProfiling(); - installGlobalFunction(ctx, "nativeProfilerStart", nativeProfilerStart); - installGlobalFunction(ctx, "nativeProfilerEnd", nativeProfilerEnd); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.h b/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.h deleted file mode 100644 index d85e6d88b..000000000 --- a/ReactAndroid/src/main/jni/react/JSCLegacyProfiler.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -namespace facebook { -namespace react { - -void addNativeProfilingHooks(JSGlobalContextRef ctx); -void stopAndOutputProfilingFile( - JSContextRef ctx, - JSStringRef title, - const char *filename); - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.cpp b/ReactAndroid/src/main/jni/react/JSCMemory.cpp deleted file mode 100644 index 4ca7d6ea5..000000000 --- a/ReactAndroid/src/main/jni/react/JSCMemory.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include -#include -#include -#include "JSCHelpers.h" - -#include "Value.h" - -#ifdef WITH_FB_MEMORY_PROFILING - -static JSValueRef nativeCaptureHeap( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (argumentCount < 1) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "nativeCaptureHeap requires the path to save the capture"); - } - return JSValueMakeUndefined(ctx); - } - - JSStringRef outputFilename = JSValueToStringCopy(ctx, arguments[0], exception); - std::string finalFilename = facebook::react::String::ref(outputFilename).str(); - JSCaptureHeap(ctx, finalFilename.c_str(), exception); - JSStringRelease(outputFilename); - return JSValueMakeUndefined(ctx); -} - -#endif // WITH_FB_MEMORY_PROFILING - -namespace facebook { -namespace react { - -void addNativeMemoryHooks(JSGlobalContextRef ctx) { -#ifdef WITH_FB_MEMORY_PROFILING - installGlobalFunction(ctx, "nativeCaptureHeap", nativeCaptureHeap); -#endif // WITH_FB_MEMORY_PROFILING - -} - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.h b/ReactAndroid/src/main/jni/react/JSCMemory.h deleted file mode 100644 index 6e05bba70..000000000 --- a/ReactAndroid/src/main/jni/react/JSCMemory.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -namespace facebook { -namespace react { - -void addNativeMemoryHooks(JSGlobalContextRef ctx); - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCPerfStats.cpp b/ReactAndroid/src/main/jni/react/JSCPerfStats.cpp deleted file mode 100644 index 9ef341c9e..000000000 --- a/ReactAndroid/src/main/jni/react/JSCPerfStats.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSCPerfStats.h" - -#ifdef JSC_HAS_PERF_STATS_API - -#include -#include - -#include "JSCHelpers.h" -#include "Value.h" - -static JSValueRef nativeGetHeapStats( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - JSHeapStats heapStats = {0}; - JSGetHeapStats(ctx, &heapStats); - - auto result = facebook::react::Object::create(ctx); - result.setProperty("size", {ctx, JSValueMakeNumber(ctx, heapStats.size)}); - result.setProperty("extra_size", {ctx, JSValueMakeNumber(ctx, heapStats.extraSize)}); - result.setProperty("capacity", {ctx, JSValueMakeNumber(ctx, heapStats.capacity)}); - result.setProperty("object_count", {ctx, JSValueMakeNumber(ctx, heapStats.objectCount)}); - - return (JSObjectRef) result; -} - -static JSValueRef nativeGetGCStats( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - JSGCStats gcStats = {0}; - JSGetGCStats(ctx, &gcStats); - - auto result = facebook::react::Object::create(ctx); - result.setProperty( - "last_full_gc_length", - {ctx, JSValueMakeNumber(ctx, gcStats.lastFullGCLength)}); - result.setProperty( - "last_eden_gc_length", - {ctx, JSValueMakeNumber(ctx, gcStats.lastEdenGCLength)}); - - return (JSObjectRef) result; -} - -#endif - -namespace facebook { -namespace react { - -void addJSCPerfStatsHooks(JSGlobalContextRef ctx) { -#ifdef JSC_HAS_PERF_STATS_API - installGlobalFunction(ctx, "nativeGetHeapStats", nativeGetHeapStats); - installGlobalFunction(ctx, "nativeGetGCStats", nativeGetGCStats); -#endif -} - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCPerfStats.h b/ReactAndroid/src/main/jni/react/JSCPerfStats.h deleted file mode 100644 index 73ca29e8b..000000000 --- a/ReactAndroid/src/main/jni/react/JSCPerfStats.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include - -namespace facebook { -namespace react { - -void addJSCPerfStatsHooks(JSGlobalContextRef ctx); - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCTracing.cpp b/ReactAndroid/src/main/jni/react/JSCTracing.cpp deleted file mode 100644 index 24354eccb..000000000 --- a/ReactAndroid/src/main/jni/react/JSCTracing.cpp +++ /dev/null @@ -1,478 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include -#include -#include -#include -#include -#include "JSCHelpers.h" - -using std::min; - -static const char *ENABLED_FBSYSTRACE_PROFILE_NAME = "__fbsystrace__"; - -static uint64_t tagFromJSValue( - JSContextRef ctx, - JSValueRef value, - JSValueRef* exception) { - // XXX validate that this is a lossless conversion. - // XXX should we just have separate functions for bridge, infra, and apps, - // then drop this argument to save time? - (void)exception; - uint64_t tag = (uint64_t) JSValueToNumber(ctx, value, NULL); - return tag; -} - -static int64_t int64FromJSValue( - JSContextRef ctx, - JSValueRef value, - JSValueRef* exception) { - (void)exception; - int64_t num = (int64_t) JSValueToNumber(ctx, value, NULL); - return num; -} - -static size_t copyTruncatedAsciiChars( - char* buf, - size_t bufLen, - JSContextRef ctx, - JSValueRef value, - size_t maxLen) { - JSStringRef jsString = JSValueToStringCopy(ctx, value, NULL); - size_t stringLen = JSStringGetLength(jsString); - // Unlike the Java version, we truncate from the end of the string, - // rather than the beginning. - size_t toWrite = min(stringLen, min(bufLen, maxLen)); - - const char *startBuf = buf; - const JSChar* chars = JSStringGetCharactersPtr(jsString); - while (toWrite-- > 0) { - *(buf++) = (char)*(chars++); - } - - JSStringRelease(jsString); - - // Return the number of bytes written - return buf - startBuf; -} - -static size_t copyArgsToBuffer( - char* buf, - size_t bufLen, - size_t pos, - JSContextRef ctx, - size_t argumentCount, - const JSValueRef arguments[]) { - char separator = '|'; - for ( - size_t idx = 0; - idx + 1 < argumentCount; // Make sure key and value are present. - idx += 2) { - JSValueRef key = arguments[idx]; - JSValueRef value = arguments[idx+1]; - - buf[pos++] = separator; - separator = ';'; - if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; } - pos += copyTruncatedAsciiChars( - buf + pos, bufLen - pos, ctx, key, FBSYSTRACE_MAX_MESSAGE_LENGTH); - if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; } - buf[pos++] = '='; - if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; } - pos += copyTruncatedAsciiChars( - buf + pos, bufLen - pos, ctx, value, FBSYSTRACE_MAX_MESSAGE_LENGTH); - if (FBSYSTRACE_UNLIKELY(pos >= bufLen)) { break; } - } - return pos; -} - -static JSValueRef nativeTraceBeginSection( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_UNLIKELY(argumentCount < 2)) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "nativeTraceBeginSection: requires at least 2 arguments"); - } - return JSValueMakeUndefined(ctx); - } - - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - - char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH]; - size_t pos = 0; - - pos += snprintf(buf + pos, sizeof(buf) - pos, "B|%d|", getpid()); - // Skip the overflow check here because the int will be small. - pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH); - // Skip the overflow check here because the section name will be small-ish. - - pos = copyArgsToBuffer(buf, sizeof(buf), pos, ctx, argumentCount - 2, arguments + 2); - if (FBSYSTRACE_UNLIKELY(pos >= sizeof(buf))) { - goto flush; - } - -flush: - fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1)); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeTraceEndSection( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_UNLIKELY(argumentCount < 1)) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "nativeTraceEndSection: requires at least 1 argument"); - } - return JSValueMakeUndefined(ctx); - } - - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - - if (FBSYSTRACE_LIKELY(argumentCount == 1)) { - fbsystrace_end_section(tag); - } else { - char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH]; - size_t pos = 0; - - buf[pos++] = 'E'; - buf[pos++] = '|'; - buf[pos++] = '|'; - pos = copyArgsToBuffer(buf, sizeof(buf), pos, ctx, argumentCount - 1, arguments + 1); - if (FBSYSTRACE_UNLIKELY(pos >= sizeof(buf))) { - goto flush; - } - -flush: - fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1)); - } - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef beginOrEndAsync( - bool isEnd, - bool isFlow, - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "beginOrEndAsync: requires at least 3 arguments"); - } - return JSValueMakeUndefined(ctx); - } - - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - - char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH]; - size_t pos = 0; - - // This uses an if-then-else instruction in ARMv7, which should be cheaper - // than a full branch. - buf[pos++] = ((isFlow) ? (isEnd ? 'f' : 's') : (isEnd ? 'F' : 'S')); - pos += snprintf(buf + pos, sizeof(buf) - pos, "|%d|", getpid()); - // Skip the overflow check here because the int will be small. - pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH); - // Skip the overflow check here because the section name will be small-ish. - - // I tried some trickery to avoid a branch here, but gcc did not cooperate. - // We could consider changing the implementation to be lest branchy in the - // future. - // This is not required for flow use an or to avoid introducing another branch - if (!(isEnd | isFlow)) { - buf[pos++] = '<'; - buf[pos++] = '0'; - buf[pos++] = '>'; - } - buf[pos++] = '|'; - - // Append the cookie. It should be an integer, but copyTruncatedAsciiChars - // will automatically convert it to a string. We might be able to get more - // performance by just getting the number and doing to string - // conversion ourselves. We truncate to FBSYSTRACE_MAX_SECTION_NAME_LENGTH - // just to make sure we can avoid the overflow check even if the caller - // passes in something bad. - pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[2], FBSYSTRACE_MAX_SECTION_NAME_LENGTH); - - pos = copyArgsToBuffer(buf, sizeof(buf), pos, ctx, argumentCount - 3, arguments + 3); - if (FBSYSTRACE_UNLIKELY(pos >= sizeof(buf))) { - goto flush; - } - -flush: - fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1)); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef stageAsync( - bool isFlow, - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_UNLIKELY(argumentCount < 4)) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "stageAsync: requires at least 4 arguments"); - } - return JSValueMakeUndefined(ctx); - } - - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - - char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH]; - size_t pos = 0; - - buf[pos++] = (isFlow ? 't' : 'T'); - pos += snprintf(buf + pos, sizeof(buf) - pos, "|%d", getpid()); - // Skip the overflow check here because the int will be small. - - // Arguments are section name, cookie, and stage name. - // All added together, they still cannot cause an overflow. - for (int i = 1; i < 4; i++) { - buf[pos++] = '|'; - pos += copyTruncatedAsciiChars(buf + pos, sizeof(buf) - pos, ctx, arguments[i], FBSYSTRACE_MAX_SECTION_NAME_LENGTH); - } - - fbsystrace_trace_raw(buf, min(pos, sizeof(buf)-1)); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeTraceBeginAsyncSection( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - return beginOrEndAsync( - false /* isEnd */, - false /* isFlow */, - ctx, - function, - thisObject, - argumentCount, - arguments, - exception); -} - -static JSValueRef nativeTraceEndAsyncSection( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - return beginOrEndAsync( - true /* isEnd */, - false /* isFlow */, - ctx, - function, - thisObject, - argumentCount, - arguments, - exception); -} - -static JSValueRef nativeTraceAsyncSectionStage( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - return stageAsync( - false /* isFlow */, - ctx, - function, - thisObject, - argumentCount, - arguments, - exception); -} - -static JSValueRef nativeTraceBeginAsyncFlow( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - return beginOrEndAsync( - false /* isEnd */, - true /* isFlow */, - ctx, - function, - thisObject, - argumentCount, - arguments, - exception); -} - -static JSValueRef nativeTraceEndAsyncFlow( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - return beginOrEndAsync( - true /* isEnd */, - true /* isFlow */, - ctx, - function, - thisObject, - argumentCount, - arguments, - exception); -} - -static JSValueRef nativeTraceAsyncFlowStage( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - return stageAsync( - true /* isFlow */, - ctx, - function, - thisObject, - argumentCount, - arguments, - exception); -} - -static JSValueRef nativeTraceCounter( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_UNLIKELY(argumentCount < 3)) { - if (exception) { - *exception = facebook::react::makeJSCException( - ctx, - "nativeTraceCounter: requires at least 3 arguments"); - } - return JSValueMakeUndefined(ctx); - } - - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - - char buf[FBSYSTRACE_MAX_MESSAGE_LENGTH]; - size_t len = copyTruncatedAsciiChars(buf, sizeof(buf), ctx, - arguments[1], FBSYSTRACE_MAX_SECTION_NAME_LENGTH); - buf[min(len,(FBSYSTRACE_MAX_MESSAGE_LENGTH-1))] = 0; - int64_t value = int64FromJSValue(ctx, arguments[2], exception); - - fbsystrace_counter(tag, buf, value); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeTraceBeginLegacy( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_LIKELY(argumentCount >= 1)) { - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - } - - JSStringRef title = JSStringCreateWithUTF8CString(ENABLED_FBSYSTRACE_PROFILE_NAME); - #if WITH_REACT_INTERNAL_SETTINGS - JSStartProfiling(ctx, title, true); - #else - JSStartProfiling(ctx, title); - #endif - JSStringRelease(title); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeTraceEndLegacy( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (FBSYSTRACE_LIKELY(argumentCount >= 1)) { - uint64_t tag = tagFromJSValue(ctx, arguments[0], exception); - if (!fbsystrace_is_tracing(tag)) { - return JSValueMakeUndefined(ctx); - } - } - - JSStringRef title = JSStringCreateWithUTF8CString(ENABLED_FBSYSTRACE_PROFILE_NAME); - JSEndProfiling(ctx, title); - JSStringRelease(title); - - return JSValueMakeUndefined(ctx); -} - -namespace facebook { -namespace react { - -void addNativeTracingHooks(JSGlobalContextRef ctx) { - installGlobalFunction(ctx, "nativeTraceBeginSection", nativeTraceBeginSection); - installGlobalFunction(ctx, "nativeTraceEndSection", nativeTraceEndSection); - installGlobalFunction(ctx, "nativeTraceBeginLegacy", nativeTraceBeginLegacy); - installGlobalFunction(ctx, "nativeTraceEndLegacy", nativeTraceEndLegacy); - installGlobalFunction(ctx, "nativeTraceBeginAsyncSection", nativeTraceBeginAsyncSection); - installGlobalFunction(ctx, "nativeTraceEndAsyncSection", nativeTraceEndAsyncSection); - installGlobalFunction(ctx, "nativeTraceAsyncSectionStage", nativeTraceAsyncSectionStage); - installGlobalFunction(ctx, "nativeTraceBeginAsyncFlow", nativeTraceBeginAsyncFlow); - installGlobalFunction(ctx, "nativeTraceEndAsyncFlow", nativeTraceEndAsyncFlow); - installGlobalFunction(ctx, "nativeTraceAsyncFlowStage", nativeTraceAsyncFlowStage); - installGlobalFunction(ctx, "nativeTraceCounter", nativeTraceCounter); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/JSCTracing.h b/ReactAndroid/src/main/jni/react/JSCTracing.h deleted file mode 100644 index 70fd50c92..000000000 --- a/ReactAndroid/src/main/jni/react/JSCTracing.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -namespace facebook { -namespace react { - -void addNativeTracingHooks(JSGlobalContextRef ctx); - -} } diff --git a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h deleted file mode 100644 index d1c2f1254..000000000 --- a/ReactAndroid/src/main/jni/react/JSModulesUnbundle.h +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -#include "noncopyable.h" - -namespace facebook { -namespace react { - -class JSModulesUnbundle : noncopyable { - /** - * Represents the set of JavaScript modules that the application consists of. - * The source code of each module can be retrieved by module ID. - * - * The class is non-copyable because copying instances might involve copying - * several megabytes of memory. - */ -public: - class ModuleNotFound : public std::out_of_range { - using std::out_of_range::out_of_range; - }; - struct Module { - std::string name; - std::string code; - }; - virtual ~JSModulesUnbundle() {} - virtual Module getModule(uint32_t moduleId) const = 0; -}; - -} -} diff --git a/ReactAndroid/src/main/jni/react/MessageQueueThread.h b/ReactAndroid/src/main/jni/react/MessageQueueThread.h deleted file mode 100644 index f6352ab0d..000000000 --- a/ReactAndroid/src/main/jni/react/MessageQueueThread.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -namespace facebook { -namespace react { - -class MessageQueueThread { - public: - virtual ~MessageQueueThread() {} - virtual void runOnQueue(std::function&&) = 0; - virtual bool isOnThread() = 0; - // quitSynchronous() should synchronously ensure that no further tasks will run on the queue. - virtual void quitSynchronous() = 0; - - void runOnQueueSync(std::function&& runnable) { - std::mutex signalMutex; - std::condition_variable signalCv; - bool runnableComplete = false; - - runOnQueue([&] () mutable { - std::lock_guard lock(signalMutex); - - runnable(); - runnableComplete = true; - - signalCv.notify_one(); - }); - - std::unique_lock lock(signalMutex); - signalCv.wait(lock, [&runnableComplete] { return runnableComplete; }); - } -}; - -}} diff --git a/ReactAndroid/src/main/jni/react/MethodCall.cpp b/ReactAndroid/src/main/jni/react/MethodCall.cpp deleted file mode 100644 index 2782e05b6..000000000 --- a/ReactAndroid/src/main/jni/react/MethodCall.cpp +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "MethodCall.h" - -#include -#include - -namespace facebook { -namespace react { - -#define REQUEST_MODULE_IDS 0 -#define REQUEST_METHOD_IDS 1 -#define REQUEST_PARAMSS 2 -#define REQUEST_CALLID 3 - -std::vector parseMethodCalls(const std::string& json) { - folly::dynamic jsonData = folly::parseJson(json); - - if (jsonData.isNull()) { - return {}; - } - - if (!jsonData.isArray()) { - throw std::invalid_argument( - folly::to("Did not get valid calls back from JS: ", jsonData.typeName())); - } - - if (jsonData.size() < REQUEST_PARAMSS + 1) { - throw std::invalid_argument( - folly::to("Did not get valid calls back from JS: size == ", jsonData.size())); - } - - auto moduleIds = jsonData[REQUEST_MODULE_IDS]; - auto methodIds = jsonData[REQUEST_METHOD_IDS]; - auto params = jsonData[REQUEST_PARAMSS]; - int callId = -1; - - if (!moduleIds.isArray() || !methodIds.isArray() || !params.isArray()) { - throw std::invalid_argument( - folly::to("Did not get valid calls back from JS: ", json.c_str())); - } - - if (jsonData.size() > REQUEST_CALLID) { - if (!jsonData[REQUEST_CALLID].isInt()) { - throw std::invalid_argument( - folly::to("Did not get valid calls back from JS: %s", json.c_str())); - } else { - callId = jsonData[REQUEST_CALLID].getInt(); - } - } - - std::vector methodCalls; - for (size_t i = 0; i < moduleIds.size(); i++) { - auto paramsValue = params[i]; - if (!paramsValue.isArray()) { - throw std::invalid_argument( - folly::to("Call argument isn't an array")); - } - - methodCalls.emplace_back( - moduleIds[i].getInt(), - methodIds[i].getInt(), - std::move(params[i]), - callId); - - // only incremement callid if contains valid callid as callid is optional - callId += (callId != -1) ? 1 : 0; - } - - return methodCalls; -} - -}} - diff --git a/ReactAndroid/src/main/jni/react/MethodCall.h b/ReactAndroid/src/main/jni/react/MethodCall.h deleted file mode 100644 index 02e86eb98..000000000 --- a/ReactAndroid/src/main/jni/react/MethodCall.h +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -#include - -namespace facebook { -namespace react { - -struct MethodCall { - int moduleId; - int methodId; - folly::dynamic arguments; - int callId; - - MethodCall(int mod, int meth, folly::dynamic args, int cid) - : moduleId(mod) - , methodId(meth) - , arguments(std::move(args)) - , callId(cid) {} -}; - -std::vector parseMethodCalls(const std::string& json); - -} } diff --git a/ReactAndroid/src/main/jni/react/Platform.cpp b/ReactAndroid/src/main/jni/react/Platform.cpp deleted file mode 100644 index 270764440..000000000 --- a/ReactAndroid/src/main/jni/react/Platform.cpp +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "Platform.h" - -namespace facebook { -namespace react { - -namespace ReactMarker { -LogMarker logMarker; -}; - -namespace MessageQueues { -GetCurrentMessageQueueThread getCurrentMessageQueueThread; -}; - -namespace WebWorkerUtil { -WebWorkerQueueFactory createWebWorkerThread; -LoadScriptFromAssets loadScriptFromAssets; -LoadScriptFromNetworkSync loadScriptFromNetworkSync; -}; - -namespace PerfLogging { -InstallNativeHooks installNativeHooks; -}; - -namespace JSLogging { -JSCNativeHook nativeHook = nullptr; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/Platform.h b/ReactAndroid/src/main/jni/react/Platform.h deleted file mode 100644 index da214ee85..000000000 --- a/ReactAndroid/src/main/jni/react/Platform.h +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -#include "MessageQueueThread.h" - -#include - -namespace facebook { -namespace react { - -namespace ReactMarker { -using LogMarker = std::function; -extern LogMarker logMarker; -}; - -namespace MessageQueues { -using GetCurrentMessageQueueThread = std::function()>; -extern GetCurrentMessageQueueThread getCurrentMessageQueueThread; -}; - -namespace WebWorkerUtil { -using WebWorkerQueueFactory = std::function(int id, MessageQueueThread* ownerMessageQueue)>; -extern WebWorkerQueueFactory createWebWorkerThread; - -using LoadScriptFromAssets = std::function; -extern LoadScriptFromAssets loadScriptFromAssets; - -using LoadScriptFromNetworkSync = std::function; -extern LoadScriptFromNetworkSync loadScriptFromNetworkSync; -}; - -namespace PerfLogging { -using InstallNativeHooks = std::function; -extern InstallNativeHooks installNativeHooks; -}; - -namespace JSLogging { - using JSCNativeHook = JSValueRef (*) ( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception); - extern JSCNativeHook nativeHook; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/Value.cpp b/ReactAndroid/src/main/jni/react/Value.cpp deleted file mode 100644 index 5c2c92a43..000000000 --- a/ReactAndroid/src/main/jni/react/Value.cpp +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "Value.h" - -#include "JSCHelpers.h" - -namespace facebook { -namespace react { - -Value::Value(JSContextRef context, JSValueRef value) : - m_context(context), - m_value(value) -{ -} - -Value::Value(Value&& other) : - m_context(other.m_context), - m_value(other.m_value) -{ - other.m_value = nullptr; -} - -JSContextRef Value::context() const { - return m_context; -} - -std::string Value::toJSONString(unsigned indent) const { - JSValueRef exn; - auto stringToAdopt = JSValueCreateJSONString(m_context, m_value, indent, &exn); - if (stringToAdopt == nullptr) { - std::string exceptionText = Value(m_context, exn).toString().str(); - throwJSExecutionException("Exception creating JSON string: %s", exceptionText.c_str()); - } - return String::adopt(stringToAdopt).str(); -} - -/* static */ -Value Value::fromJSON(JSContextRef ctx, const String& json) { - auto result = JSValueMakeFromJSONString(ctx, json); - if (!result) { - throwJSExecutionException("Failed to create String from JSON"); - } - return Value(ctx, result); -} - -Object Value::asObject() { - JSValueRef exn; - JSObjectRef jsObj = JSValueToObject(context(), m_value, &exn); - if (!jsObj) { - std::string exceptionText = Value(m_context, exn).toString().str(); - throwJSExecutionException("Failed to convert to object: %s", exceptionText.c_str()); - } - Object ret = Object(context(), jsObj); - m_value = nullptr; - return std::move(ret); -} - -Object::operator Value() const { - return Value(m_context, m_obj); -} - -Value Object::callAsFunction(int nArgs, JSValueRef args[]) { - JSValueRef exn; - JSValueRef result = JSObjectCallAsFunction(m_context, m_obj, NULL, nArgs, args, &exn); - if (!result) { - std::string exceptionText = Value(m_context, exn).toString().str(); - throwJSExecutionException("Exception calling JS function: %s", exceptionText.c_str()); - } - return Value(m_context, result); -} - -Value Object::callAsFunction() { - JSValueRef args[0]; - return callAsFunction(0, args); -} - -Value Object::getProperty(const String& propName) const { - JSValueRef exn; - JSValueRef property = JSObjectGetProperty(m_context, m_obj, propName, &exn); - if (!property) { - std::string exceptionText = Value(m_context, exn).toString().str(); - throwJSExecutionException("Failed to get property: %s", exceptionText.c_str()); - } - return Value(m_context, property); -} - -Value Object::getPropertyAtIndex(unsigned index) const { - JSValueRef exn; - JSValueRef property = JSObjectGetPropertyAtIndex(m_context, m_obj, index, &exn); - if (!property) { - std::string exceptionText = Value(m_context, exn).toString().str(); - throwJSExecutionException("Failed to get property at index %u: %s", index, exceptionText.c_str()); - } - return Value(m_context, property); -} - -Value Object::getProperty(const char *propName) const { - return getProperty(String(propName)); -} - -void Object::setProperty(const String& propName, const Value& value) const { - JSValueRef exn = NULL; - JSObjectSetProperty(m_context, m_obj, propName, value, kJSPropertyAttributeNone, &exn); - if (exn) { - std::string exceptionText = Value(m_context, exn).toString().str(); - throwJSExecutionException("Failed to set property: %s", exceptionText.c_str()); - } -} - -void Object::setProperty(const char *propName, const Value& value) const { - setProperty(String(propName), value); -} - -std::vector Object::getPropertyNames() const { - std::vector names; - auto namesRef = JSObjectCopyPropertyNames(m_context, m_obj); - size_t count = JSPropertyNameArrayGetCount(namesRef); - for (size_t i = 0; i < count; i++) { - auto string = String::ref(JSPropertyNameArrayGetNameAtIndex(namesRef, i)); - names.emplace_back(string.str()); - } - JSPropertyNameArrayRelease(namesRef); - return names; -} - -std::unordered_map Object::toJSONMap() const { - std::unordered_map map; - auto namesRef = JSObjectCopyPropertyNames(m_context, m_obj); - size_t count = JSPropertyNameArrayGetCount(namesRef); - for (size_t i = 0; i < count; i++) { - auto key = String::ref(JSPropertyNameArrayGetNameAtIndex(namesRef, i)); - map.emplace(key.str(), getProperty(key).toJSONString()); - } - JSPropertyNameArrayRelease(namesRef); - return map; -} - -/* static */ -Object Object::create(JSContextRef ctx) { - JSObjectRef newObj = JSObjectMake( - ctx, - NULL, // create instance of default object class - NULL); // no private data - return Object(ctx, newObj); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/Value.h b/ReactAndroid/src/main/jni/react/Value.h deleted file mode 100644 index 58b214419..000000000 --- a/ReactAndroid/src/main/jni/react/Value.h +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "noncopyable.h" - -#if WITH_FBJSCEXTENSIONS -#include -#endif - -namespace facebook { -namespace react { - -class Value; -class Context; - -class String : public noncopyable { -public: - explicit String(const char* utf8) : - m_string(Adopt, JSStringCreateWithUTF8CString(utf8)) - {} - - String(String&& other) : - m_string(Adopt, other.m_string.leakRef()) - {} - - String(const String& other) : - m_string(other.m_string) - {} - - operator JSStringRef() const { - return m_string.get(); - } - - // Length in characters - size_t length() const { - return JSStringGetLength(m_string.get()); - } - - // Length in bytes of a null-terminated utf8 encoded value - size_t utf8Size() const { - return JSStringGetMaximumUTF8CStringSize(m_string.get()); - } - - std::string str() const { - size_t reserved = utf8Size(); - char* bytes = new char[reserved]; - size_t length = JSStringGetUTF8CString(m_string.get(), bytes, reserved) - 1; - std::unique_ptr retainedBytes(bytes); - return std::string(bytes, length); - } - - // Assumes that utf8 is null terminated - bool equals(const char* utf8) { - return JSStringIsEqualToUTF8CString(m_string.get(), utf8); - } - - static String createExpectingAscii(std::string const &utf8) { - #if WITH_FBJSCEXTENSIONS - return String(Adopt, JSStringCreateWithUTF8CStringExpectAscii(utf8.c_str(), utf8.size())); - #else - return String(Adopt, JSStringCreateWithUTF8CString(utf8.c_str())); - #endif - } - - static String ref(JSStringRef string) { - return String(string); - } - - static String adopt(JSStringRef string) { - return String(Adopt, string); - } - -private: - explicit String(JSStringRef string) : - m_string(string) - {} - - String(AdoptTag tag, JSStringRef string) : - m_string(tag, string) - {} - - JSRetainPtr m_string; -}; - -class Object : public noncopyable { -public: - Object(JSContextRef context, JSObjectRef obj) : - m_context(context), - m_obj(obj) - {} - - Object(Object&& other) : - m_context(other.m_context), - m_obj(other.m_obj), - m_isProtected(other.m_isProtected) { - other.m_obj = nullptr; - other.m_isProtected = false; - } - - ~Object() { - if (m_isProtected && m_obj) { - JSValueUnprotect(m_context, m_obj); - } - } - - operator JSObjectRef() const { - return m_obj; - } - - operator Value() const; - - bool isFunction() const { - return JSObjectIsFunction(m_context, m_obj); - } - - Value callAsFunction(int nArgs, JSValueRef args[]); - Value callAsFunction(); - - Value getProperty(const String& propName) const; - Value getProperty(const char *propName) const; - Value getPropertyAtIndex(unsigned index) const; - void setProperty(const String& propName, const Value& value) const; - void setProperty(const char *propName, const Value& value) const; - std::vector getPropertyNames() const; - std::unordered_map toJSONMap() const; - - void makeProtected() { - if (!m_isProtected && m_obj) { - JSValueProtect(m_context, m_obj); - m_isProtected = true; - } - } - - static Object getGlobalObject(JSContextRef ctx) { - auto globalObj = JSContextGetGlobalObject(ctx); - return Object(ctx, globalObj); - } - - /** - * Creates an instance of the default object class. - */ - static Object create(JSContextRef ctx); - -private: - JSContextRef m_context; - JSObjectRef m_obj; - bool m_isProtected = false; -}; - -class Value : public noncopyable { -public: - Value(JSContextRef context, JSValueRef value); - Value(Value&&); - - operator JSValueRef() const { - return m_value; - } - - bool isBoolean() const { - return JSValueIsBoolean(context(), m_value); - } - - bool asBoolean() const { - return JSValueToBoolean(context(), m_value); - } - - bool isNumber() const { - return JSValueIsNumber(context(), m_value); - } - - bool isNull() const { - return JSValueIsNull(context(), m_value); - } - - bool isUndefined() const { - return JSValueIsUndefined(context(), m_value); - } - - double asNumber() const { - if (isNumber()) { - return JSValueToNumber(context(), m_value, nullptr); - } else { - return 0.0f; - } - } - - int32_t asInteger() const { - return static_cast(asNumber()); - } - - uint32_t asUnsignedInteger() const { - return static_cast(asNumber()); - } - - bool isObject() const { - return JSValueIsObject(context(), m_value); - } - - Object asObject(); - - bool isString() const { - return JSValueIsString(context(), m_value); - } - - String toString() { - return String::adopt(JSValueToStringCopy(context(), m_value, nullptr)); - } - - std::string toJSONString(unsigned indent = 0) const; - static Value fromJSON(JSContextRef ctx, const String& json); -protected: - JSContextRef context() const; - JSContextRef m_context; - JSValueRef m_value; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/Android.mk b/ReactAndroid/src/main/jni/react/jni/Android.mk index 06266de37..25b44eab7 100644 --- a/ReactAndroid/src/main/jni/react/jni/Android.mk +++ b/ReactAndroid/src/main/jni/react/jni/Android.mk @@ -5,14 +5,7 @@ include $(CLEAR_VARS) LOCAL_MODULE := libreactnativejni LOCAL_SRC_FILES := \ - JExecutorToken.cpp \ - JMessageQueueThread.cpp \ - JSCPerfLogging.cpp \ - JSLoader.cpp \ - JSLogging.cpp \ - JniJSModulesUnbundle.cpp \ - OnLoad.cpp \ - ProxyExecutor.cpp \ + Dummy.cpp \ LOCAL_C_INCLUDES := $(LOCAL_PATH) LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)/../.. $(LOCAL_PATH)/.. @@ -23,15 +16,9 @@ LOCAL_CFLAGS += $(CXX11_FLAGS) LOCAL_EXPORT_CPPFLAGS := $(CXX11_FLAGS) LOCAL_LDLIBS += -landroid -LOCAL_SHARED_LIBRARIES := libfolly_json libfb libjsc libglog_init libreactnativejnifb -LOCAL_STATIC_LIBRARIES := libreactnative +LOCAL_SHARED_LIBRARIES := libreactnativejnifb +LOCAL_STATIC_LIBRARIES := include $(BUILD_SHARED_LIBRARY) -$(call import-module,react) -$(call import-module,jsc) -$(call import-module,folly) -$(call import-module,fbgloginit) -$(call import-module,fb) -$(call import-module,jsc) $(call import-module,xreact/jni) diff --git a/ReactAndroid/src/main/jni/react/jni/BUCK b/ReactAndroid/src/main/jni/react/jni/BUCK index e210b9dd9..2a5c242bf 100644 --- a/ReactAndroid/src/main/jni/react/jni/BUCK +++ b/ReactAndroid/src/main/jni/react/jni/BUCK @@ -3,66 +3,20 @@ include_defs('//ReactAndroid/DEFS') # We depend on JSC, support the same platforms SUPPORTED_PLATFORMS = '^android-(armv7|x86)$' -DEPS = [ - FBGLOGINIT_TARGET, - '//native/fb:fb', - '//native/third-party/android-ndk:android', - '//xplat/folly:molly', -] - -def jni_library(**kwargs): - cxx_library( - name='jni', - visibility = [ - 'PUBLIC', - ], - deps = DEPS + JSC_DEPS + [ - react_native_target('jni/react:react'), - react_native_target('jni/xreact/jni:jni'), - ], - **kwargs - ) - -jni_library( +# TODO(cjhopman): Remove this target (or move the xreact target to this directory). +cxx_library( + name='jni', soname = 'libreactnativejni.so', header_namespace = 'react/jni', supported_platforms_regex = SUPPORTED_PLATFORMS, srcs = [ - 'JExecutorToken.cpp', - 'JMessageQueueThread.cpp', - 'JSCPerfLogging.cpp', - 'JSLoader.cpp', - 'JSLogging.cpp', - 'JniJSModulesUnbundle.cpp', - 'OnLoad.cpp', - 'ProxyExecutor.cpp', + 'Dummy.cpp', ], - headers = [ - 'JSLoader.h', - 'JExecutorToken.h', - 'JExecutorTokenFactory.h', - 'JMessageQueueThread.h', - 'JNativeRunnable.h', - 'JniJSModulesUnbundle.h', - 'JSCPerfLogging.h', - 'JSLogging.h', - 'ProxyExecutor.h', - 'WebWorkers.h', + deps = [ + react_native_target('jni/xreact/jni:jni'), ], - exported_headers = [ - ], - preprocessor_flags = [ - '-DLOG_TAG="ReactNativeJNI"', - '-DWITH_FBSYSTRACE=1', - '-DWITH_FBJSCEXTENSIONS=1', - ], - compiler_flags = [ - '-Wall', - '-Werror', - '-fexceptions', - '-std=c++11', - '-fvisibility=hidden', - '-frtti', + visibility = [ + 'PUBLIC', ], ) diff --git a/ReactAndroid/src/main/jni/react/jni/Dummy.cpp b/ReactAndroid/src/main/jni/react/jni/Dummy.cpp new file mode 100644 index 000000000..f51f98f1c --- /dev/null +++ b/ReactAndroid/src/main/jni/react/jni/Dummy.cpp @@ -0,0 +1,7 @@ +// Copyright 2004-present Facebook. All Rights Reserved. +namespace facebook { +namespace react { + void ThisWhatsLeftOfTheOldBridge() { + } +} +} diff --git a/ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp b/ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp deleted file mode 100644 index 97e80948b..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JExecutorToken.cpp +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JExecutorToken.h" - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -ExecutorToken JExecutorToken::getExecutorToken(alias_ref jobj) { - std::lock_guard guard(createTokenGuard_); - auto sharedOwner = owner_.lock(); - if (!sharedOwner) { - sharedOwner = std::shared_ptr(new JExecutorTokenHolder(jobj)); - owner_ = sharedOwner; - } - return ExecutorToken(sharedOwner); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JExecutorToken.h b/ReactAndroid/src/main/jni/react/jni/JExecutorToken.h deleted file mode 100644 index 0cd69ca06..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JExecutorToken.h +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include - -#include - -#include - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -class JExecutorTokenHolder; -class JExecutorToken : public HybridClass { -public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/ExecutorToken;"; - - ExecutorToken getExecutorToken(alias_ref jobj); - -private: - friend HybridBase; - friend JExecutorTokenHolder; - - JExecutorToken() {} - - std::weak_ptr owner_; - std::mutex createTokenGuard_; -}; - -/** - * Wrapper class to hold references to both the c++ and Java parts of the - * ExecutorToken object. The goal is to allow a reference to a token from either - * c++ or Java to keep both the Java object and c++ hybrid part alive. For c++ - * references, we accomplish this by having JExecutorTokenHolder keep a reference - * to the Java object (which has a reference to the JExecutorToken hybrid part). - * For Java references, we allow the JExecutorTokenHolder to be deallocated if there - * are no references to it in c++ from a PlatformExecutorToken, but will dynamically - * create a new one in JExecutorToken.getExecutorToken if needed. - */ -class JExecutorTokenHolder : public PlatformExecutorToken, public noncopyable { -public: - explicit JExecutorTokenHolder(alias_ref jobj) : - jobj_(make_global(jobj)), - impl_(cthis(jobj)) { - } - - JExecutorToken::javaobject getJobj() { - return jobj_.get(); - } - -private: - global_ref jobj_; - JExecutorToken *impl_; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h b/ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h deleted file mode 100644 index 9e158eee7..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JExecutorTokenFactory.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include - -#include "JExecutorToken.h" - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -class JExecutorTokenFactory : public ExecutorTokenFactory { -public: - virtual ExecutorToken createExecutorToken() const override { - auto jExecutorToken = JExecutorToken::newObjectCxxArgs(); - auto jExecutorTokenNativePart = cthis(jExecutorToken); - return jExecutorTokenNativePart->getExecutorToken(jExecutorToken); - } -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp deleted file mode 100644 index 88e587e63..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.cpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JMessageQueueThread.h" - -#include -#include -#include - -#include "JNativeRunnable.h" - -namespace facebook { -namespace react { - -JMessageQueueThread::JMessageQueueThread(alias_ref jobj) : - m_jobj(make_global(jobj)) { -} - -void JMessageQueueThread::runOnQueue(std::function&& runnable) { - static auto method = JavaMessageQueueThread::javaClassStatic()-> - getMethod("runOnQueue"); - method(m_jobj, JNativeRunnable::newObjectCxxArgs(runnable).get()); -} - -bool JMessageQueueThread::isOnThread() { - static auto method = JavaMessageQueueThread::javaClassStatic()-> - getMethod("isOnThread"); - return method(m_jobj); -} - -void JMessageQueueThread::quitSynchronous() { - static auto method = JavaMessageQueueThread::javaClassStatic()-> - getMethod("quitSynchronous"); - method(m_jobj); -} - -/* static */ -std::unique_ptr JMessageQueueThread::currentMessageQueueThread() { - static auto method = MessageQueueThreadRegistry::javaClassStatic()-> - getStaticMethod("myMessageQueueThread"); - return folly::make_unique(method(MessageQueueThreadRegistry::javaClassStatic())); -} - -} } - diff --git a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h b/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h deleted file mode 100644 index a04bcb376..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JMessageQueueThread.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include - -#include - -#include - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -class JavaMessageQueueThread : public jni::JavaClass { -public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/queue/MessageQueueThread;"; -}; - -class JMessageQueueThread : public MessageQueueThread { -public: - JMessageQueueThread(alias_ref jobj); - - /** - * Enqueues the given function to run on this MessageQueueThread. - */ - void runOnQueue(std::function&& runnable) override; - - /** - * Returns whether the currently executing thread is this MessageQueueThread. - */ - bool isOnThread() override; - - /** - * Synchronously quits the current MessageQueueThread. Can be called from any thread, but will - * block if not called on this MessageQueueThread. - */ - void quitSynchronous() override; - - JavaMessageQueueThread::javaobject jobj() { - return m_jobj.get(); - } - - /** - * Returns the current MessageQueueThread that owns this thread. - */ - static std::unique_ptr currentMessageQueueThread(); -private: - global_ref m_jobj; -}; - -class MessageQueueThreadRegistry : public jni::JavaClass { -public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/queue/MessageQueueThreadRegistry;"; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h b/ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h deleted file mode 100644 index 5550af342..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JNativeRunnable.h +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include - -#include - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -class Runnable : public JavaClass { -public: - static constexpr auto kJavaDescriptor = "Ljava/lang/Runnable;"; -}; - -/** - * The c++ interface for the Java NativeRunnable class - */ -class JNativeRunnable : public HybridClass { -public: - static auto constexpr kJavaDescriptor = "Lcom/facebook/react/bridge/queue/NativeRunnable;"; - - void run() { - m_runnable(); - } - - static void registerNatives() { - javaClassStatic()->registerNatives({ - makeNativeMethod("run", JNativeRunnable::run), - }); - } -private: - friend HybridBase; - - JNativeRunnable(std::function runnable) - : m_runnable(std::move(runnable)) {} - - std::function m_runnable; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp b/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp deleted file mode 100644 index 1b7b5e688..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSCPerfLogging.h" - -#include -#include -#include - -using namespace facebook::jni; - -struct _jqplProvider : _jobject {}; -using jqplProvider = _jqplProvider*; - -struct _jqpl : _jobject {}; -using jqpl = _jqpl*; - -namespace facebook { namespace jni { - - -template<> -class JObjectWrapper : public JObjectWrapper { - - public: - static constexpr const char* kJavaDescriptor = "Lcom/facebook/quicklog/QuickPerformanceLogger;"; - - using JObjectWrapper::JObjectWrapper; - - void markerStart(int markerId, int instanceKey, long timestamp) { - static auto markerStartMethod = - qplClass()->getMethod("markerStart"); - markerStartMethod(this_, markerId, instanceKey, timestamp); - } - - void markerEnd(int markerId, int instanceKey, short actionId, long timestamp) { - static auto markerEndMethod = - qplClass()->getMethod("markerEnd"); - markerEndMethod(this_, markerId, instanceKey, actionId, timestamp); - } - - void markerNote(int markerId, int instanceKey, short actionId, long timestamp) { - static auto markerNoteMethod = - qplClass()->getMethod("markerNote"); - markerNoteMethod(this_, markerId, instanceKey, actionId, timestamp); - } - - void markerCancel(int markerId, int instanceKey) { - static auto markerCancelMethod = - qplClass()->getMethod("markerCancel"); - markerCancelMethod(this_, markerId, instanceKey); - } - - int64_t currentMonotonicTimestamp() { - static auto currentTimestampMethod = - qplClass()->getMethod("currentMonotonicTimestamp"); - return currentTimestampMethod(this_); - } - - private: - - static alias_ref qplClass() { - static auto cls = findClassStatic("com/facebook/quicklog/QuickPerformanceLogger"); - return cls; - } - -}; -using JQuickPerformanceLogger = JObjectWrapper; - - -template<> -class JObjectWrapper : public JObjectWrapper { - public: - static constexpr const char* kJavaDescriptor = - "Lcom/facebook/quicklog/QuickPerformanceLoggerProvider;"; - - using JObjectWrapper::JObjectWrapper; - - static global_ref get() { - static auto getQPLInstMethod = qplProviderClass()->getStaticMethod("getQPLInstance"); - static global_ref theQpl = make_global(getQPLInstMethod(qplProviderClass().get())); - return theQpl; - } - - static bool check() { - static auto getQPLInstMethod = qplProviderClass()->getStaticMethod("getQPLInstance"); - auto theQpl = getQPLInstMethod(qplProviderClass().get()); - return (theQpl.get() != nullptr); - } - - private: - - static alias_ref qplProviderClass() { - static auto cls = findClassStatic("com/facebook/quicklog/QuickPerformanceLoggerProvider"); - return cls; - } -}; -using JQuickPerformanceLoggerProvider = JObjectWrapper; - -}} - -static bool isReady() { - static bool ready = false; - if (!ready) { - try { - findClassStatic("com/facebook/quicklog/QuickPerformanceLoggerProvider"); - } catch(...) { - // Swallow this exception - we don't want to crash the app, an error is enough. - FBLOGE("Calling QPL from JS before class has been loaded in Java. Ignored."); - return false; - } - if (JQuickPerformanceLoggerProvider::check()) { - ready = true; - } else { - FBLOGE("Calling QPL from JS before it has been initialized in Java. Ignored."); - return false; - } - } - return ready; -} - -// After having read the implementation of PNaN that is returned from JSValueToNumber, and some -// more material on how NaNs are constructed, I think this is the most consistent way to verify -// NaN with how we generate it. -// Once the integration completes, I'll play around with it some more and potentially change this -// implementation to use std::isnan() if it is exactly commensurate with our usage. -static bool isNan(double value) { - return (value != value); -} - -// Safely translates JSValues to an array of doubles. -static bool grabDoubles( - size_t targetsCount, - double targets[], - JSContextRef ctx, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (argumentCount < targetsCount) { - return false; - } - for (size_t i = 0 ; i < targetsCount ; i++) { - targets[i] = JSValueToNumber(ctx, arguments[i], exception); - if (isNan(targets[i])) { - return false; - } - } - return true; -} - -static JSValueRef nativeQPLMarkerStart( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - double targets[3]; - if (isReady() && grabDoubles(3, targets, ctx, argumentCount, arguments, exception)) { - int32_t markerId = (int32_t) targets[0]; - int32_t instanceKey = (int32_t) targets[1]; - int64_t timestamp = (int64_t) targets[2]; - JQuickPerformanceLoggerProvider::get()->markerStart(markerId, instanceKey, timestamp); - } - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeQPLMarkerEnd( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - double targets[4]; - if (isReady() && grabDoubles(4, targets, ctx, argumentCount, arguments, exception)) { - int32_t markerId = (int32_t) targets[0]; - int32_t instanceKey = (int32_t) targets[1]; - int16_t actionId = (int16_t) targets[2]; - int64_t timestamp = (int64_t) targets[3]; - JQuickPerformanceLoggerProvider::get()->markerEnd(markerId, instanceKey, actionId, timestamp); - } - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeQPLMarkerNote( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - double targets[4]; - if (isReady() && grabDoubles(4, targets, ctx, argumentCount, arguments, exception)) { - int32_t markerId = (int32_t) targets[0]; - int32_t instanceKey = (int32_t) targets[1]; - int16_t actionId = (int16_t) targets[2]; - int64_t timestamp = (int64_t) targets[3]; - JQuickPerformanceLoggerProvider::get()->markerNote(markerId, instanceKey, actionId, timestamp); - } - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeQPLMarkerCancel( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - double targets[2]; - if (isReady() && grabDoubles(2, targets, ctx, argumentCount, arguments, exception)) { - int32_t markerId = (int32_t) targets[0]; - int32_t instanceKey = (int32_t) targets[1]; - JQuickPerformanceLoggerProvider::get()->markerCancel(markerId, instanceKey); - } - return JSValueMakeUndefined(ctx); -} - -static JSValueRef nativeQPLTimestamp( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], - JSValueRef* exception) { - if (!isReady()) { - return JSValueMakeNumber(ctx, 0); - } - int64_t timestamp = JQuickPerformanceLoggerProvider::get()->currentMonotonicTimestamp(); - // Since this is monotonic time, I assume the 52 bits of mantissa are enough in the double value. - return JSValueMakeNumber(ctx, timestamp); -} - -namespace facebook { -namespace react { - -void addNativePerfLoggingHooks(JSGlobalContextRef ctx) { - installGlobalFunction(ctx, "nativeQPLMarkerStart", nativeQPLMarkerStart); - installGlobalFunction(ctx, "nativeQPLMarkerEnd", nativeQPLMarkerEnd); - installGlobalFunction(ctx, "nativeQPLMarkerNote", nativeQPLMarkerNote); - installGlobalFunction(ctx, "nativeQPLMarkerCancel", nativeQPLMarkerCancel); - installGlobalFunction(ctx, "nativeQPLTimestamp", nativeQPLTimestamp); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.h b/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.h deleted file mode 100644 index 256755b1f..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JSCPerfLogging.h +++ /dev/null @@ -1,11 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -namespace facebook { -namespace react { - -void addNativePerfLoggingHooks(JSGlobalContextRef ctx); - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp b/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp deleted file mode 100644 index 9423e578f..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JSLoader.cpp +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSLoader.h" - -#include -#include -#include -#include -#include -#include -#include -#ifdef WITH_FBSYSTRACE -#include -using fbsystrace::FbSystraceSection; -#endif - -namespace facebook { -namespace react { - -static jclass gApplicationHolderClass; -static jmethodID gGetApplicationMethod; -static jmethodID gGetAssetManagerMethod; - -std::string loadScriptFromAssets(const std::string& assetName) { - JNIEnv *env = jni::Environment::current(); - jobject application = env->CallStaticObjectMethod( - gApplicationHolderClass, - gGetApplicationMethod); - jobject assetManager = env->CallObjectMethod(application, gGetAssetManagerMethod); - return loadScriptFromAssets(AAssetManager_fromJava(env, assetManager), assetName); -} - -std::string loadScriptFromAssets( - AAssetManager *manager, - const std::string& assetName) { - #ifdef WITH_FBSYSTRACE - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromAssets", - "assetName", assetName); - #endif - if (manager) { - auto asset = AAssetManager_open( - manager, - assetName.c_str(), - AASSET_MODE_STREAMING); // Optimized for sequential read: see AssetManager.java for docs - if (asset) { - std::stringbuf buf; - char BUF[0x800]; - int readbytes; - while ((readbytes = AAsset_read(asset, BUF, sizeof(BUF))) > 0) { - buf.sputn(BUF, readbytes); - } - AAsset_close(asset); - if (readbytes == 0) { // EOF! - return buf.str(); - } - } - } - FBLOGE("Unable to load script from assets: %s", assetName.c_str()); - return ""; -} - -std::string loadScriptFromFile(const std::string& fileName) { - #ifdef WITH_FBSYSTRACE - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_loadScriptFromFile", - "fileName", fileName); - #endif - std::ifstream jsfile(fileName); - if (jsfile) { - std::string output; - jsfile.seekg(0, std::ios::end); - output.reserve(jsfile.tellg()); - jsfile.seekg(0, std::ios::beg); - output.assign( - (std::istreambuf_iterator(jsfile)), - std::istreambuf_iterator()); - return output; - } - - FBLOGE("Unable to load script from file: %s", fileName.c_str()); - return ""; -} - -void registerJSLoaderNatives() { - JNIEnv *env = jni::Environment::current(); - jclass applicationHolderClass = env->FindClass("com/facebook/react/common/ApplicationHolder"); - gApplicationHolderClass = (jclass)env->NewGlobalRef(applicationHolderClass); - gGetApplicationMethod = env->GetStaticMethodID(applicationHolderClass, "getApplication", "()Landroid/app/Application;"); - - jclass appClass = env->FindClass("android/app/Application"); - gGetAssetManagerMethod = env->GetMethodID(appClass, "getAssets", "()Landroid/content/res/AssetManager;"); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JSLoader.h b/ReactAndroid/src/main/jni/react/jni/JSLoader.h deleted file mode 100644 index 8b716beef..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JSLoader.h +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -namespace facebook { -namespace react { - -/** - * Helper method for loading a JS script from Android assets without - * a reference to an AssetManager. - */ -std::string loadScriptFromAssets(const std::string& assetName); - -/** - * Helper method for loading JS script from android asset - */ -std::string loadScriptFromAssets(AAssetManager *assetManager, const std::string& assetName); - -/** - * Helper method for loading JS script from a file - */ -std::string loadScriptFromFile(const std::string& fileName); - -void registerJSLoaderNatives(); - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp b/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp deleted file mode 100644 index 7690a5656..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JSLogging.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JSLogging.h" - -#include -#include -#include -#include - -namespace facebook { -namespace react { - -JSValueRef nativeLoggingHook( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception) { - android_LogPriority logLevel = ANDROID_LOG_DEBUG; - if (argumentCount > 1) { - int level = (int) JSValueToNumber(ctx, arguments[1], NULL); - // The lowest log level we get from JS is 0. We shift and cap it to be - // in the range the Android logging method expects. - logLevel = std::min( - static_cast(level + ANDROID_LOG_DEBUG), - ANDROID_LOG_FATAL); - } - if (argumentCount > 0) { - JSStringRef jsString = JSValueToStringCopy(ctx, arguments[0], NULL); - String message = String::adopt(jsString); - FBLOG_PRI(logLevel, "ReactNativeJS", "%s", message.str().c_str()); - } - return JSValueMakeUndefined(ctx); -} - -}}; diff --git a/ReactAndroid/src/main/jni/react/jni/JSLogging.h b/ReactAndroid/src/main/jni/react/jni/JSLogging.h deleted file mode 100644 index 27756b665..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JSLogging.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include - -namespace facebook { -namespace react { -JSValueRef nativeLoggingHook( - JSContextRef ctx, - JSObjectRef function, - JSObjectRef thisObject, - size_t argumentCount, - const JSValueRef arguments[], JSValueRef *exception); -}} diff --git a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp deleted file mode 100644 index 20c71bc8c..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "JniJSModulesUnbundle.h" - -#include -#include -#include -#include -#include -#include -#include - -using magic_number_t = uint32_t; -const magic_number_t MAGIC_FILE_HEADER = 0xFB0BD1E5; -const std::string MAGIC_FILE_NAME = "UNBUNDLE"; - -namespace facebook { -namespace react { - -using asset_ptr = - std::unique_ptr>; - -static std::string jsModulesDir(const std::string& entryFile) { - std::string dir = dirname(entryFile.c_str()); - - // android's asset manager does not work with paths that start with a dot - return dir == "." ? "js-modules/" : dir + "/js-modules/"; -} - -static asset_ptr openAsset( - AAssetManager *manager, - const std::string& fileName, - int mode = AASSET_MODE_STREAMING) { - return asset_ptr( - AAssetManager_open(manager, fileName.c_str(), mode), - AAsset_close); -} - -JniJSModulesUnbundle::JniJSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile) : - m_assetManager(assetManager), - m_moduleDirectory(jsModulesDir(entryFile)) {} - -bool JniJSModulesUnbundle::isUnbundle( - AAssetManager *assetManager, - const std::string& assetName) { - if (!assetManager) { - return false; - } - - auto magicFileName = jsModulesDir(assetName) + MAGIC_FILE_NAME; - auto asset = openAsset(assetManager, magicFileName.c_str()); - if (asset == nullptr) { - return false; - } - - magic_number_t fileHeader = 0; - AAsset_read(asset.get(), &fileHeader, sizeof(fileHeader)); - return fileHeader == htole32(MAGIC_FILE_HEADER); -} - -JSModulesUnbundle::Module JniJSModulesUnbundle::getModule(uint32_t moduleId) const { - // can be nullptr for default constructor. - FBASSERTMSGF(m_assetManager != nullptr, "Unbundle has not been initialized with an asset manager"); - - std::ostringstream sourceUrlBuilder; - sourceUrlBuilder << moduleId << ".js"; - auto sourceUrl = sourceUrlBuilder.str(); - - auto fileName = m_moduleDirectory + sourceUrl; - auto asset = openAsset(m_assetManager, fileName, AASSET_MODE_BUFFER); - - const char *buffer = nullptr; - if (asset != nullptr) { - buffer = static_cast(AAsset_getBuffer(asset.get())); - } - if (buffer == nullptr) { - throw ModuleNotFound("Module not found: " + sourceUrl); - } - return {sourceUrl, std::string(buffer, AAsset_getLength(asset.get()))}; -} - -} -} diff --git a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h b/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h deleted file mode 100644 index 9f75175e4..000000000 --- a/ReactAndroid/src/main/jni/react/jni/JniJSModulesUnbundle.h +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include - -namespace facebook { -namespace react { - -class JniJSModulesUnbundle : public JSModulesUnbundle { - /** - * This implementation reads modules as single file from the assets of an apk. - */ -public: - JniJSModulesUnbundle() = default; - JniJSModulesUnbundle(AAssetManager *assetManager, const std::string& entryFile); - JniJSModulesUnbundle(JniJSModulesUnbundle&& other) = delete; - JniJSModulesUnbundle& operator= (JSModulesUnbundle&& other) = delete; - - static bool isUnbundle( - AAssetManager *assetManager, - const std::string& assetName); - virtual Module getModule(uint32_t moduleId) const override; -private: - AAssetManager *m_assetManager = nullptr; - std::string m_moduleDirectory; -}; - -} -} diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp b/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp deleted file mode 100644 index 2f2f92cec..000000000 --- a/ReactAndroid/src/main/jni/react/jni/OnLoad.cpp +++ /dev/null @@ -1,516 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "JExecutorToken.h" -#include "JExecutorTokenFactory.h" -#include "JNativeRunnable.h" -#include "JSLoader.h" -#include "ProxyExecutor.h" -#include "OnLoad.h" -#include "JMessageQueueThread.h" -#include "JniJSModulesUnbundle.h" -#include "JSLogging.h" -#include "JSCPerfLogging.h" -#include "WebWorkers.h" - -#include -#include -#include - -#ifdef WITH_FBSYSTRACE -#include -using fbsystrace::FbSystraceSection; -#endif - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -namespace { - -namespace runnable { - -struct NativeRunnable : public Countable { - std::function callable; -}; - -static jclass gNativeRunnableClass; -static jmethodID gNativeRunnableCtor; - -static LocalReference createNativeRunnable(JNIEnv* env, decltype(NativeRunnable::callable)&& callable) { - LocalReference jRunnable{env->NewObject(gNativeRunnableClass, gNativeRunnableCtor)}; - if (env->ExceptionCheck()) { - return nullptr; - } - auto nativeRunnable = createNew(); - nativeRunnable->callable = std::move(callable); - setCountableForJava(env, jRunnable.get(), std::move(nativeRunnable)); - return jRunnable; -} - -static void run(JNIEnv* env, jobject jNativeRunnable) { - auto nativeRunnable = extractRefPtr(env, jNativeRunnable); - nativeRunnable->callable(); -} - -} // namespace runnable - -namespace queue { - -static jmethodID gRunOnQueueThreadMethod; - -static void enqueueNativeRunnableOnQueue(JNIEnv* env, jobject callbackQueueThread, jobject nativeRunnable) { - env->CallVoidMethod(callbackQueueThread, gRunOnQueueThreadMethod, nativeRunnable); -} - -} // namespace queue - -namespace bridge { - -static jmethodID gCallbackMethod; -static jmethodID gOnBatchCompleteMethod; -static jmethodID gOnExecutorUnregisteredMethod; -static jmethodID gLogMarkerMethod; - -struct CountableBridge : Bridge, Countable { - using Bridge::Bridge; -}; - -static void logMarker(const std::string& marker) { - JNIEnv* env = Environment::current(); - jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker"); - jstring jmarker = env->NewStringUTF(marker.c_str()); - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, jmarker); - env->DeleteLocalRef(markerClass); - env->DeleteLocalRef(jmarker); -} - -static void makeJavaCall(JNIEnv* env, ExecutorToken executorToken, jobject callback, const MethodCall& call) { - if (call.arguments.isNull()) { - return; - } - - #ifdef WITH_FBSYSTRACE - if (call.callId != -1) { - fbsystrace_end_async_flow(TRACE_TAG_REACT_APPS, "native", call.callId); - } - #endif - - auto newArray = ReadableNativeArray::newObjectCxxArgs(std::move(call.arguments)); - env->CallVoidMethod( - callback, - gCallbackMethod, - static_cast(executorToken.getPlatformExecutorToken().get())->getJobj(), - call.moduleId, - call.methodId, - newArray.get()); -} - -static void signalBatchComplete(JNIEnv* env, jobject callback) { - env->CallVoidMethod(callback, gOnBatchCompleteMethod); -} - -class PlatformBridgeCallback : public BridgeCallback { -public: - PlatformBridgeCallback( - RefPtr weakCallback_, - RefPtr weakCallbackQueueThread_) : - weakCallback_(std::move(weakCallback_)), - weakCallbackQueueThread_(std::move(weakCallbackQueueThread_)) {} - - void executeCallbackOnCallbackQueueThread(std::function&& runnable) { - auto env = Environment::current(); - if (env->ExceptionCheck()) { - FBLOGW("Dropped callback because of pending exception"); - return; - } - - ResolvedWeakReference callbackQueueThread(weakCallbackQueueThread_); - if (!callbackQueueThread) { - FBLOGW("Dropped callback because callback queue thread went away"); - return; - } - - auto runnableWrapper = std::bind([weakCallback=weakCallback_] (std::function& runnable) { - auto env = Environment::current(); - if (env->ExceptionCheck()) { - FBLOGW("Dropped calls because of pending exception"); - return; - } - ResolvedWeakReference callback(weakCallback); - if (callback) { - runnable(callback); - } - }, std::move(runnable)); - - auto jNativeRunnable = runnable::createNativeRunnable(env, std::move(runnableWrapper)); - queue::enqueueNativeRunnableOnQueue(env, callbackQueueThread, jNativeRunnable.get()); - } - - virtual void onCallNativeModules( - ExecutorToken executorToken, - const std::string& callJSON, - bool isEndOfBatch) override { - executeCallbackOnCallbackQueueThread([executorToken, callJSON, isEndOfBatch] (ResolvedWeakReference& callback) { - JNIEnv* env = Environment::current(); - for (auto& call : react::parseMethodCalls(callJSON)) { - makeJavaCall(env, executorToken, callback, call); - if (env->ExceptionCheck()) { - return; - } - } - if (isEndOfBatch) { - signalBatchComplete(env, callback); - } - }); - } - - virtual void onExecutorUnregistered(ExecutorToken executorToken) override { - executeCallbackOnCallbackQueueThread([executorToken] (ResolvedWeakReference& callback) { - JNIEnv *env = Environment::current(); - env->CallVoidMethod( - callback, - gOnExecutorUnregisteredMethod, - static_cast(executorToken.getPlatformExecutorToken().get())->getJobj()); - }); - } -private: - RefPtr weakCallback_; - RefPtr weakCallbackQueueThread_; -}; - -static void create(JNIEnv* env, jobject obj, jobject executor, jobject callback, - jobject callbackQueueThread) { - auto weakCallback = createNew(callback); - auto weakCallbackQueueThread = createNew(callbackQueueThread); - auto bridgeCallback = folly::make_unique(weakCallback, weakCallbackQueueThread); - auto nativeExecutorFactory = extractRefPtr(env, executor); - auto executorTokenFactory = folly::make_unique(); - auto bridge = createNew(nativeExecutorFactory.get(), std::move(executorTokenFactory), std::move(bridgeCallback)); - setCountableForJava(env, obj, std::move(bridge)); -} - -static void destroy(JNIEnv* env, jobject jbridge) { - auto bridge = extractRefPtr(env, jbridge); - try { - bridge->destroy(); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } -} - -static void loadApplicationScript( - const RefPtr& bridge, - const std::string& script, - const std::string& sourceUri) { - try { - bridge->loadApplicationScript(script, sourceUri); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } -} - -static void loadApplicationUnbundle( - const RefPtr& bridge, - AAssetManager *assetManager, - const std::string& startupCode, - const std::string& startupFileName) { - try { - bridge->loadApplicationUnbundle( - std::unique_ptr( - new JniJSModulesUnbundle(assetManager, startupFileName)), - startupCode, - startupFileName); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } -} - -static void loadScriptFromAssets(JNIEnv* env, jobject obj, jobject assetManager, - jstring assetName) { - jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker"); - auto manager = AAssetManager_fromJava(env, assetManager); - auto bridge = extractRefPtr(env, obj); - auto assetNameStr = fromJString(env, assetName); - - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_start")); - auto script = react::loadScriptFromAssets(manager, assetNameStr); - #ifdef WITH_FBSYSTRACE - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_" - "loadApplicationScript", - "assetName", assetNameStr); - #endif - - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_read")); - if (JniJSModulesUnbundle::isUnbundle(manager, assetNameStr)) { - loadApplicationUnbundle(bridge, manager, script, assetNameStr); - } else { - loadApplicationScript(bridge, script, "file://" + assetNameStr); - } - if (env->ExceptionCheck()) { - return; - } - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromAssets_done")); -} - -static void loadScriptFromFile(JNIEnv* env, jobject obj, jstring fileName, jstring sourceURL) { - jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker"); - - auto bridge = extractRefPtr(env, obj); - auto fileNameStr = fileName == NULL ? "" : fromJString(env, fileName); - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_start")); - auto script = fileName == NULL ? "" : react::loadScriptFromFile(fileNameStr); - #ifdef WITH_FBSYSTRACE - auto sourceURLStr = sourceURL == NULL ? fileNameStr : fromJString(env, sourceURL); - FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "reactbridge_jni_" - "loadApplicationScript", - "sourceURL", sourceURLStr); - #endif - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_read")); - loadApplicationScript(bridge, script, fromJString(env, sourceURL)); - if (env->ExceptionCheck()) { - return; - } - env->CallStaticVoidMethod(markerClass, gLogMarkerMethod, env->NewStringUTF("loadScriptFromFile_exec")); -} - -static void callFunction(JNIEnv* env, jobject obj, JExecutorToken::jhybridobject jExecutorToken, jstring module, jstring method, - NativeArray::jhybridobject args) { - auto bridge = extractRefPtr(env, obj); - auto arguments = cthis(wrap_alias(args)); - try { - bridge->callFunction( - cthis(wrap_alias(jExecutorToken))->getExecutorToken(wrap_alias(jExecutorToken)), - fromJString(env, module), - fromJString(env, method), - std::move(arguments->array) - ); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } -} - -static void invokeCallback(JNIEnv* env, jobject obj, JExecutorToken::jhybridobject jExecutorToken, jint callbackId, - NativeArray::jhybridobject args) { - auto bridge = extractRefPtr(env, obj); - auto arguments = cthis(wrap_alias(args)); - try { - bridge->invokeCallback( - cthis(wrap_alias(jExecutorToken))->getExecutorToken(wrap_alias(jExecutorToken)), - (double) callbackId, - std::move(arguments->array) - ); - } catch (...) { - translatePendingCppExceptionToJavaException(); - } -} - -static void setGlobalVariable(JNIEnv* env, jobject obj, jstring propName, jstring jsonValue) { - auto bridge = extractRefPtr(env, obj); - bridge->setGlobalVariable(fromJString(env, propName), fromJString(env, jsonValue)); -} - -static jlong getJavaScriptContext(JNIEnv *env, jobject obj) { - auto bridge = extractRefPtr(env, obj); - return (uintptr_t) bridge->getJavaScriptContext(); -} - -static jobject getMainExecutorToken(JNIEnv* env, jobject obj) { - auto bridge = extractRefPtr(env, obj); - auto token = bridge->getMainExecutorToken(); - return static_cast(token.getPlatformExecutorToken().get())->getJobj(); -} - -static jboolean supportsProfiling(JNIEnv* env, jobject obj) { - auto bridge = extractRefPtr(env, obj); - return bridge->supportsProfiling() ? JNI_TRUE : JNI_FALSE; -} - -static void startProfiler(JNIEnv* env, jobject obj, jstring title) { - auto bridge = extractRefPtr(env, obj); - bridge->startProfiler(fromJString(env, title)); -} - -static void stopProfiler(JNIEnv* env, jobject obj, jstring title, jstring filename) { - auto bridge = extractRefPtr(env, obj); - bridge->stopProfiler(fromJString(env, title), fromJString(env, filename)); -} - -static void handleMemoryPressureUiHidden(JNIEnv* env, jobject obj) { - LOG(WARNING) << "handleMemoryPressureUiHidden"; - auto bridge = extractRefPtr(env, obj); - bridge->handleMemoryPressureUiHidden(); -} - -static void handleMemoryPressureModerate(JNIEnv* env, jobject obj) { - auto bridge = extractRefPtr(env, obj); - bridge->handleMemoryPressureModerate(); -} - -static void handleMemoryPressureCritical(JNIEnv* env, jobject obj) { - auto bridge = extractRefPtr(env, obj); - bridge->handleMemoryPressureCritical(); -} - -} // namespace bridge - -namespace executors { - -static std::string getApplicationDir(const char* methodName) { - // Get the Application Context object - auto getApplicationClass = findClassLocal( - "com/facebook/react/common/ApplicationHolder"); - auto getApplicationMethod = getApplicationClass->getStaticMethod( - "getApplication", - "()Landroid/app/Application;" - ); - auto application = getApplicationMethod(getApplicationClass); - - // Get getCacheDir() from the context - auto getDirMethod = findClassLocal("android/app/Application") - ->getMethod(methodName, - "()Ljava/io/File;" - ); - auto dirObj = getDirMethod(application); - - // Call getAbsolutePath() on the returned File object - auto getAbsolutePathMethod = findClassLocal("java/io/File") - ->getMethod("getAbsolutePath"); - return getAbsolutePathMethod(dirObj)->toStdString(); -} - -static std::string getApplicationCacheDir() { - return getApplicationDir("getCacheDir"); -} - -static std::string getApplicationPersistentDir() { - return getApplicationDir("getFilesDir"); -} - -struct CountableJSCExecutorFactory : CountableJSExecutorFactory { -public: - CountableJSCExecutorFactory(folly::dynamic jscConfig) : m_jscConfig(jscConfig) {} - virtual std::unique_ptr createJSExecutor(Bridge *bridge) override { - m_jscConfig["PersistentDirectory"] = getApplicationPersistentDir(); - return JSCExecutorFactory(getApplicationCacheDir(), m_jscConfig).createJSExecutor(bridge); - } - -private: - folly::dynamic m_jscConfig; -}; - -static void createJSCExecutor(alias_ref obj, WritableNativeMap* jscConfig) { - auto executor = createNew(jscConfig->consume()); - setCountableForJava(Environment::current(), obj.get(), std::move(executor)); -} - -static void createProxyExecutor(JNIEnv *env, jobject obj, jobject executorInstance) { - auto executor = - createNew(make_global(adopt_local(executorInstance))); - setCountableForJava(env, obj, std::move(executor)); -} - -} // namespace executors - -} - -jmethodID getLogMarkerMethod() { - return bridge::gLogMarkerMethod; -} - -extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) { - return initialize(vm, [] { - facebook::gloginit::initialize(); - // Inject some behavior into react/ - ReactMarker::logMarker = bridge::logMarker; - WebWorkerUtil::createWebWorkerThread = WebWorkers::createWebWorkerThread; - WebWorkerUtil::loadScriptFromAssets = - [] (const std::string& assetName) { - return loadScriptFromAssets(assetName); - }; - WebWorkerUtil::loadScriptFromNetworkSync = WebWorkers::loadScriptFromNetworkSync; - MessageQueues::getCurrentMessageQueueThread = - [] { - return std::unique_ptr( - JMessageQueueThread::currentMessageQueueThread().release()); - }; - PerfLogging::installNativeHooks = addNativePerfLoggingHooks; - JSLogging::nativeHook = nativeLoggingHook; - - JNativeRunnable::registerNatives(); - registerJSLoaderNatives(); - - registerNatives("com/facebook/react/bridge/JSCJavaScriptExecutor", { - makeNativeMethod("initialize", executors::createJSCExecutor), - }); - - registerNatives("com/facebook/react/bridge/ProxyJavaScriptExecutor", { - makeNativeMethod( - "initialize", "(Lcom/facebook/react/bridge/JavaJSExecutor;)V", - executors::createProxyExecutor), - }); - - // get the current env - JNIEnv* env = Environment::current(); - - jclass callbackClass = env->FindClass("com/facebook/react/bridge/ReactCallback"); - bridge::gCallbackMethod = env->GetMethodID(callbackClass, "call", "(Lcom/facebook/react/bridge/ExecutorToken;IILcom/facebook/react/bridge/ReadableNativeArray;)V"); - bridge::gOnBatchCompleteMethod = env->GetMethodID(callbackClass, "onBatchComplete", "()V"); - bridge::gOnExecutorUnregisteredMethod = env->GetMethodID(callbackClass, "onExecutorUnregistered", "(Lcom/facebook/react/bridge/ExecutorToken;)V"); - - jclass markerClass = env->FindClass("com/facebook/react/bridge/ReactMarker"); - bridge::gLogMarkerMethod = env->GetStaticMethodID(markerClass, "logMarker", "(Ljava/lang/String;)V"); - - registerNatives("com/facebook/react/bridge/ReactBridge", { - makeNativeMethod("initialize", "(Lcom/facebook/react/bridge/JavaScriptExecutor;Lcom/facebook/react/bridge/ReactCallback;Lcom/facebook/react/bridge/queue/MessageQueueThread;)V", bridge::create), - makeNativeMethod("destroy", bridge::destroy), - makeNativeMethod( - "loadScriptFromAssets", "(Landroid/content/res/AssetManager;Ljava/lang/String;)V", - bridge::loadScriptFromAssets), - makeNativeMethod("loadScriptFromFile", bridge::loadScriptFromFile), - makeNativeMethod("callFunction", bridge::callFunction), - makeNativeMethod("invokeCallback", bridge::invokeCallback), - makeNativeMethod("setGlobalVariable", bridge::setGlobalVariable), - makeNativeMethod("getMainExecutorToken", "()Lcom/facebook/react/bridge/ExecutorToken;", bridge::getMainExecutorToken), - makeNativeMethod("supportsProfiling", bridge::supportsProfiling), - makeNativeMethod("startProfiler", bridge::startProfiler), - makeNativeMethod("stopProfiler", bridge::stopProfiler), - makeNativeMethod("handleMemoryPressureUiHidden", bridge::handleMemoryPressureUiHidden), - makeNativeMethod("handleMemoryPressureModerate", bridge::handleMemoryPressureModerate), - makeNativeMethod("handleMemoryPressureCritical", bridge::handleMemoryPressureCritical), - makeNativeMethod("getJavaScriptContextNativePtrExperimental", bridge::getJavaScriptContext), - }); - - jclass nativeRunnableClass = env->FindClass("com/facebook/react/bridge/queue/NativeRunnableDeprecated"); - runnable::gNativeRunnableClass = (jclass)env->NewGlobalRef(nativeRunnableClass); - runnable::gNativeRunnableCtor = env->GetMethodID(nativeRunnableClass, "", "()V"); - wrap_alias(nativeRunnableClass)->registerNatives({ - makeNativeMethod("run", runnable::run), - }); - - jclass messageQueueThreadClass = - env->FindClass("com/facebook/react/bridge/queue/MessageQueueThread"); - queue::gRunOnQueueThreadMethod = - env->GetMethodID(messageQueueThreadClass, "runOnQueue", "(Ljava/lang/Runnable;)V"); - }); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/OnLoad.h b/ReactAndroid/src/main/jni/react/jni/OnLoad.h deleted file mode 100644 index e7a7d04a4..000000000 --- a/ReactAndroid/src/main/jni/react/jni/OnLoad.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include - -namespace facebook { -namespace react { - -jmethodID getLogMarkerMethod(); - -struct CountableJSExecutorFactory : JSExecutorFactory, Countable { - using JSExecutorFactory::JSExecutorFactory; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp deleted file mode 100644 index f0dc3bda0..000000000 --- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.cpp +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include "ProxyExecutor.h" - -#include -#include -#include -#include -#include - -#include -namespace facebook { -namespace react { - -const auto EXECUTOR_BASECLASS = "com/facebook/react/bridge/JavaJSExecutor"; - -static std::string executeJSCallWithProxy( - jobject executor, - const std::string& methodName, - const std::vector& arguments) { - static auto executeJSCall = - jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod("executeJSCall"); - - auto result = executeJSCall( - executor, - jni::make_jstring(methodName).get(), - jni::make_jstring(folly::toJson(arguments).c_str()).get()); - return result->toString(); -} - -std::unique_ptr ProxyExecutorOneTimeFactory::createJSExecutor(Bridge *bridge) { - FBASSERTMSGF( - m_executor.get() != nullptr, - "Proxy instance should not be null. Did you attempt to call createJSExecutor() on this factory " - "instance more than once?"); - return std::unique_ptr(new ProxyExecutor(std::move(m_executor), bridge)); -} - -ProxyExecutor::~ProxyExecutor() { - m_executor.reset(); -} - -void ProxyExecutor::loadApplicationScript( - const std::string&, - const std::string& sourceURL) { - static auto loadApplicationScript = - jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod("loadApplicationScript"); - - // The proxy ignores the script data passed in. - - loadApplicationScript( - m_executor.get(), - jni::make_jstring(sourceURL).get()); -} - -void ProxyExecutor::loadApplicationUnbundle(std::unique_ptr, const std::string&, const std::string&) { - jni::throwNewJavaException( - "java/lang/UnsupportedOperationException", - "Loading application unbundles is not supported for proxy executors"); -} - -void ProxyExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) { - std::vector call{ - moduleId, - methodId, - std::move(arguments), - }; - std::string result = executeJSCallWithProxy(m_executor.get(), "callFunctionReturnFlushedQueue", std::move(call)); - m_bridge->callNativeModules(*this, result, true); -} - -void ProxyExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) { - std::vector call{ - (double) callbackId, - std::move(arguments) - }; - std::string result = executeJSCallWithProxy(m_executor.get(), "invokeCallbackAndReturnFlushedQueue", std::move(call)); - m_bridge->callNativeModules(*this, result, true); -} - -void ProxyExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) { - static auto setGlobalVariable = - jni::findClassStatic(EXECUTOR_BASECLASS)->getMethod("setGlobalVariable"); - - setGlobalVariable( - m_executor.get(), - jni::make_jstring(propName).get(), - jni::make_jstring(jsonValue).get()); -} - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h b/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h deleted file mode 100644 index 36be74173..000000000 --- a/ReactAndroid/src/main/jni/react/jni/ProxyExecutor.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include -#include "OnLoad.h" - -namespace facebook { -namespace react { - -/** - * This executor factory can only create a single executor instance because it moves - * executorInstance global reference to the executor instance it creates. - */ -class ProxyExecutorOneTimeFactory : public CountableJSExecutorFactory { -public: - ProxyExecutorOneTimeFactory(jni::global_ref&& executorInstance) : - m_executor(std::move(executorInstance)) {} - virtual std::unique_ptr createJSExecutor(Bridge *bridge) override; - -private: - jni::global_ref m_executor; -}; - -class ProxyExecutor : public JSExecutor { -public: - ProxyExecutor(jni::global_ref&& executorInstance, Bridge *bridge) : - m_executor(std::move(executorInstance)), - m_bridge(bridge) {} - virtual ~ProxyExecutor() override; - virtual void loadApplicationScript( - const std::string& script, - const std::string& sourceURL) override; - virtual void loadApplicationUnbundle( - std::unique_ptr bundle, - const std::string& startupCode, - const std::string& sourceURL) override; - virtual void callFunction( - const std::string& moduleId, - const std::string& methodId, - const folly::dynamic& arguments) override; - virtual void invokeCallback( - const double callbackId, - const folly::dynamic& arguments) override; - virtual void setGlobalVariable( - const std::string& propName, - const std::string& jsonValue) override; - -private: - jni::global_ref m_executor; - Bridge *m_bridge; -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/jni/WebWorkers.h b/ReactAndroid/src/main/jni/react/jni/WebWorkers.h deleted file mode 100644 index a37df26c6..000000000 --- a/ReactAndroid/src/main/jni/react/jni/WebWorkers.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once - -#include -#include -#include -#include - -#include -#include - -#include "JMessageQueueThread.h" - -using namespace facebook::jni; - -namespace facebook { -namespace react { - -class WebWorkers : public JavaClass { -public: - static constexpr auto kJavaDescriptor = "Lcom/facebook/react/bridge/webworkers/WebWorkers;"; - - static std::unique_ptr createWebWorkerThread(int id, MessageQueueThread *ownerMessageQueueThread) { - static auto method = WebWorkers::javaClassStatic()-> - getStaticMethod("createWebWorkerThread"); - auto res = method(WebWorkers::javaClassStatic(), id, static_cast(ownerMessageQueueThread)->jobj()); - return folly::make_unique(res); - } - - static std::string loadScriptFromNetworkSync(const std::string& url, const std::string& tempfileName) { - static auto method = WebWorkers::javaClassStatic()-> - getStaticMethod("downloadScriptToFileSync"); - method( - WebWorkers::javaClassStatic(), - jni::make_jstring(url).get(), - jni::make_jstring(tempfileName).get()); - - std::ifstream tempFile(tempfileName); - if (!tempFile.good()) { - throw std::runtime_error("Didn't find worker script file at " + tempfileName); - } - std::stringstream buffer; - buffer << tempFile.rdbuf(); - std::remove(tempfileName.c_str()); - return buffer.str(); - } -}; - -} } diff --git a/ReactAndroid/src/main/jni/react/noncopyable.h b/ReactAndroid/src/main/jni/react/noncopyable.h deleted file mode 100644 index 96b32d44b..000000000 --- a/ReactAndroid/src/main/jni/react/noncopyable.h +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#pragma once -namespace facebook { -namespace react { -struct noncopyable { - noncopyable(const noncopyable&) = delete; - noncopyable& operator=(const noncopyable&) = delete; - protected: - noncopyable() = default; -}; -}} diff --git a/ReactAndroid/src/main/jni/react/perftests/BUCK b/ReactAndroid/src/main/jni/react/perftests/BUCK deleted file mode 100644 index 6f2d1acfc..000000000 --- a/ReactAndroid/src/main/jni/react/perftests/BUCK +++ /dev/null @@ -1,21 +0,0 @@ -include_defs('//ReactAndroid/DEFS') - -cxx_library( - name = 'perftests', - srcs = [ 'OnLoad.cpp' ], - soname = 'libreactnativetests.so', - preprocessor_flags = [ - '-DLOG_TAG=\"ReactPerftests\"', - ], - deps = [ - '//native:base', - '//native/fb:fb', - ], - visibility = [ - '//instrumentation_tests/com/facebook/react/...', - ], -) - -project_config( - src_target = ':perftests', -) diff --git a/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp b/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp deleted file mode 100644 index f2fac8d91..000000000 --- a/ReactAndroid/src/main/jni/react/perftests/OnLoad.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright 2004-present Facebook. All Rights Reserved. - -#include -#include -#include -#include - -namespace facebook { -namespace react { - -namespace logwatcher { - -static std::string gMessageToLookFor; -static int gMessagePriorityToLookFor; -static bool gHasSeenMessage = false; - -/** - * NB: Don't put JNI logic (or anything else that could trigger a log) here! - */ -static void stubLogHandler(int pri, const char *tag, const char *msg) { - if (gMessageToLookFor.empty()) { - return; - } - - bool priorityMatches = pri == gMessagePriorityToLookFor; - bool substringFound = strstr(msg, gMessageToLookFor.c_str()) != NULL; - gHasSeenMessage |= priorityMatches && substringFound; -} - -static jboolean hasSeenExpectedLogMessage() { - return gHasSeenMessage ? JNI_TRUE : JNI_FALSE; -} - -static void stopWatchingLogMessages(JNIEnv* env, jclass loggerClass) { - gMessageToLookFor = ""; - gHasSeenMessage = false; - setLogHandler(NULL); -} - -static void startWatchingForLogMessage(JNIEnv* env, jclass loggerClass, jstring jmsg, jint priority) { - stopWatchingLogMessages(env, loggerClass); - gMessageToLookFor = jni::fromJString(env, jmsg); - gMessagePriorityToLookFor = priority; - setLogHandler(&stubLogHandler); -} - -} // namespace logwatcher - -extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { - // get the current env - JNIEnv* env; - if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_4) != JNI_OK) { - return -1; - } - - jni::registerNatives(env, "com/facebook/catalyst/testing/LogWatcher", { - { "startWatchingForLogMessage", "(Ljava/lang/String;I)V", (void*) logwatcher::startWatchingForLogMessage}, - { "stopWatchingLogMessages", "()V", (void*) logwatcher::stopWatchingLogMessages }, - { "hasSeenExpectedLogMessage", "()Z", (void*) logwatcher::hasSeenExpectedLogMessage }, - }); - - return JNI_VERSION_1_4; -} - -} } diff --git a/ReactAndroid/src/main/jni/xreact/perftests/OnLoad.cpp b/ReactAndroid/src/main/jni/xreact/perftests/OnLoad.cpp index 4c79034aa..f6d5c0d7c 100644 --- a/ReactAndroid/src/main/jni/xreact/perftests/OnLoad.cpp +++ b/ReactAndroid/src/main/jni/xreact/perftests/OnLoad.cpp @@ -135,21 +135,66 @@ void tearDown( jsModule.reset(); } +namespace logwatcher { + +static std::string gMessageToLookFor; +static int gMessagePriorityToLookFor; +static bool gHasSeenMessage = false; + +/** + * NB: Don't put JNI logic (or anything else that could trigger a log) here! + */ +static void stubLogHandler(int pri, const char *tag, const char *msg) { + if (gMessageToLookFor.empty()) { + return; + } + + bool priorityMatches = pri == gMessagePriorityToLookFor; + bool substringFound = strstr(msg, gMessageToLookFor.c_str()) != NULL; + gHasSeenMessage |= priorityMatches && substringFound; } + +static jboolean hasSeenExpectedLogMessage(JNIEnv*, jclass) { + return gHasSeenMessage ? JNI_TRUE : JNI_FALSE; } + +static void stopWatchingLogMessages(JNIEnv*, jclass) { + gMessageToLookFor = ""; + gHasSeenMessage = false; + setLogHandler(NULL); } +static void startWatchingForLogMessage(JNIEnv* env, jclass loggerClass, jstring jmsg, jint priority) { + stopWatchingLogMessages(env, loggerClass); + gMessageToLookFor = jni::wrap_alias(jmsg)->toStdString(); + gMessagePriorityToLookFor = priority; + setLogHandler(&stubLogHandler); +} + +} // namespace logwatcher +} // namespace +} // namespace react +} // namespace facebook + +using namespace facebook::react; + extern "C" facebook::xplat::module::CxxModule* CxxBenchmarkModule() { return new facebook::react::CxxBenchmarkModule(); } extern "C" jint JNI_OnLoad(JavaVM* vm, void*) { return facebook::jni::initialize(vm, [] { + facebook::jni::registerNatives( + "com/facebook/catalyst/testing/LogWatcher", { + makeNativeMethod("startWatchingForLogMessage", "(Ljava/lang/String;I)V", logwatcher::startWatchingForLogMessage), + makeNativeMethod("stopWatchingLogMessages", "()V", logwatcher::stopWatchingLogMessages), + makeNativeMethod("hasSeenExpectedLogMessage", "()Z", logwatcher::hasSeenExpectedLogMessage), + }); facebook::jni::registerNatives( "com/facebook/react/CatalystBridgeBenchmarks", { - makeNativeMethod("runNativeBounce", facebook::react::runBounce), - makeNativeMethod("nativeSetUp", facebook::react::setUp), - makeNativeMethod("nativeTearDown", facebook::react::tearDown), + makeNativeMethod("runNativeBounce", runBounce), + makeNativeMethod("nativeSetUp", setUp), + makeNativeMethod("nativeTearDown", tearDown), }); }); } diff --git a/ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java b/ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java deleted file mode 100644 index 4f54a12e8..000000000 --- a/ReactAndroid/src/test/java/com/facebook/react/bridge/NativeModuleRegistryTest.java +++ /dev/null @@ -1,293 +0,0 @@ -/** - * Copyright (c) 2015-present, Facebook, Inc. - * All rights reserved. - * - * This source code is licensed under the BSD-style license found in the - * LICENSE file in the root directory of this source tree. An additional grant - * of patent rights can be found in the PATENTS file in the same directory. - */ - -package com.facebook.react.bridge; - -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import com.facebook.react.common.MapBuilder; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.TextNode; -import org.junit.Test; -import org.junit.Rule; -import org.junit.runner.RunWith; -import org.powermock.modules.junit4.rule.PowerMockRule; -import org.powermock.core.classloader.annotations.PowerMockIgnore; -import org.robolectric.RobolectricTestRunner; - -import static org.fest.assertions.api.Assertions.assertThat; - -/** - * Tests for {@link NativeModuleRegistry}. - */ -@RunWith(RobolectricTestRunner.class) -@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"}) -public class NativeModuleRegistryTest { - - @Rule - public PowerMockRule rule = new PowerMockRule(); - - @Test - public void testModuleWithMethods() throws Exception { - NativeModuleRegistry registry = new NativeModuleRegistry.Builder() - .add(new MethodsModule()) - .build(); - - String json = getModuleDescriptions(registry); - JsonNode node = parse(json); - - JsonNode module = node.fields().next().getValue(); - assertThat(module).isNotNull(); - - JsonNode methods = module.get("methods"); - assertThat(methods).isNotNull(); - - ArrayList expected = new ArrayList(); - expected.add("doSomething"); - expected.add("saveData"); - - assertMethodsContainExactly(methods, expected); - } - - @Test - public void testAsyncMethod() throws Exception { - NativeModuleRegistry registry = new NativeModuleRegistry.Builder() - .add(new MethodsModule()) - .build(); - - String json = getModuleDescriptions(registry); - JsonNode node = parse(json); - - JsonNode asyncMethodData = node.get("TestModule").get("methods").get("saveData"); - assertThat(asyncMethodData.get("type")).isEqualTo(new TextNode("remoteAsync")); - - JsonNode regularMethodData = node.get("TestModule").get("methods").get("doSomething"); - assertThat(regularMethodData.get("type")).isNotEqualTo(new TextNode("remoteAsync")); - } - - @Test - public void testModuleWithConstants() throws Exception { - ConstantsModule constantsModule = new ConstantsModule(); - NativeModuleRegistry registry = new NativeModuleRegistry.Builder() - .add(constantsModule) - .build(); - - String json = getModuleDescriptions(registry); - JsonNode node = parse(json); - - JsonNode module = node.fields().next().getValue(); - assertThat(module).isNotNull(); - - JsonNode methods = module.get("methods"); - assertThat(methods).isNotNull(); - - ArrayList expected = new ArrayList(); - expected.add("runDMC"); - - assertMethodsContainExactly(methods, expected); - - JsonNode constants = module.get("constants"); - assertThat(constants.get("testInt").asInt()).isEqualTo(3); - assertThat(constants.get("testDouble").asDouble()).isEqualTo(3.14); - assertThat(constants.get("testString").asText()).isEqualTo("red panda"); - - JsonNode stringMap = constants.get("testStringMap"); - assertThat(stringMap.get("war_room").asText()).isEqualTo("17.1"); - assertThat(stringMap.get("android_corex").asText()).isEqualTo("16.1"); - - JsonNode intMap = constants.get("testIntMap"); - assertThat(intMap.get("42").asInt()).isEqualTo(1); - assertThat(intMap.get("84").asInt()).isEqualTo(2); - - JsonNode stringList = constants.get("testStringList"); - assertThat(stringList.get(0).asText()).isEqualTo("vulpes vulpes"); - assertThat(stringList.get(4).asText()).isEqualTo("vulpes velox"); - - JsonNode intList = constants.get("testIntList"); - assertThat(intList.get(0).asInt()).isEqualTo(3); - assertThat(intList.get(4).asInt()).isEqualTo(5); - } - - @Test - public void testModuleWithOnlyConstants() throws Exception { - OnlyConstantsModule onlyConstantsModule = new OnlyConstantsModule(); - NativeModuleRegistry registry = new NativeModuleRegistry.Builder() - .add(onlyConstantsModule) - .build(); - - String json = getModuleDescriptions(registry); - JsonNode node = parse(json); - - JsonNode module = node.fields().next().getValue(); - assertThat(module).isNotNull(); - - JsonNode constants = module.get("constants"); - assertThat(constants.get("testInt").asInt()).isEqualTo(4); - } - - @Test - public void testModuleWithNestedMapConstants() throws Exception { - NestedMapConstantsModule nestedMapConstantsModule = new NestedMapConstantsModule(); - NativeModuleRegistry registry = new NativeModuleRegistry.Builder() - .add(nestedMapConstantsModule) - .build(); - - String json = getModuleDescriptions(registry); - JsonNode node = parse(json); - - JsonNode module = node.fields().next().getValue(); - assertThat(module).isNotNull(); - - JsonNode constants = module.get("constants"); - assertThat(constants).isNotNull(); - - JsonNode nestedMapConstant = constants.get("nestedMap"); - assertThat(nestedMapConstant).isNotNull(); - - JsonNode firstLevel = nestedMapConstant.get("weNeedToGoDeeper"); - assertThat(firstLevel).isNotNull(); - - JsonNode secondLevel = firstLevel.get("evenDeeper"); - assertThat(secondLevel).isNotNull(); - - assertThat(secondLevel.get("inception").asBoolean()).isTrue(); - } - - private JsonNode parse(String json) throws Exception { - ObjectMapper mapper = new ObjectMapper(); - return mapper.readTree(json); - } - - private void assertMethodsContainExactly(JsonNode methodsObject, List methodNames) { - ArrayList actual = new ArrayList(); - Iterator> fields = methodsObject.fields(); - while (fields.hasNext()) { - String name = fields.next().getKey(); - actual.add(name); - } - assertThat(actual) - .hasSize(methodNames.size()) - .containsAll(methodNames); - } - - private static String getModuleDescriptions(NativeModuleRegistry registry) - throws IOException { - StringWriter stringWriter = new StringWriter(); - JsonWriter writer = new JsonWriter(stringWriter); - registry.writeModuleDescriptions(writer); - writer.close(); - return stringWriter.getBuffer().toString(); - } - - private static class MethodsModule extends BaseJavaModule { - - @Override - public String getName() { - return "TestModule"; - } - - public void notACatalystMethod() { - } - - @ReactMethod - public void doSomething() { - } - - @ReactMethod - public void saveData(Promise promise) { - } - } - - private static class ConstantsModule extends BaseJavaModule { - - @Override - public String getName() { - return "ConstantsModule"; - } - - @Override - public Map getConstants() { - HashMap constants = new HashMap(); - constants.put("testInt", 3); - constants.put("testDouble", 3.14); - constants.put("testString", "red panda"); - constants.put( - "testStringMap", - MapBuilder.of( - "war_room", - "17.1", - "android_corex", - "16.1")); - constants.put( - "testIntMap", - MapBuilder.of( - 42, - 1, - 84, - 2)); - constants.put( - "testStringList", - Arrays.asList( - new String[]{ - "vulpes vulpes", - "vulpes cana", - "vulpes chama", - "vulpes fulfa", - "vulpes velox"})); - constants.put("testIntList", Arrays.asList(3, 1, 4, 1, 5)); - return constants; - } - - @ReactMethod - public void runDMC() { - } - } - - private static class OnlyConstantsModule extends BaseJavaModule { - - @Override - public String getName() { - return "OnlyConstantsModule"; - } - - @Override - public Map getConstants() { - return MapBuilder.of("testInt", 4); - } - } - - private static class NestedMapConstantsModule extends BaseJavaModule { - - @Override - public String getName() { - return "NestedMapConstantsModule"; - } - - @Override - public Map getConstants() { - return MapBuilder.of( - "nestedMap", - MapBuilder.of( - "weNeedToGoDeeper", - MapBuilder.of( - "evenDeeper", - MapBuilder.of("inception", true)))); - } - } - -}