From ea6c7f504b64a99a0443db50ad81cb054b084696 Mon Sep 17 00:00:00 2001 From: David Vacca Date: Tue, 18 Oct 2022 13:32:03 -0700 Subject: [PATCH] Delete LockFreeEventDispatcher Summary: This diff removes LockFreeEventDispatcher, its dependencies and feature flags changelog: [internal] internal Reviewed By: javache, sammy-SC Differential Revision: D40356071 fbshipit-source-id: 42212e86fe4ace0da87fd8e7ab8ee50100175432 --- .../react/config/ReactFeatureFlags.java | 2 - .../react/fabric/FabricUIManager.java | 6 +- .../events/LockFreeEventDispatcherImpl.java | 242 ------------------ 3 files changed, 1 insertion(+), 249 deletions(-) delete mode 100644 ReactAndroid/src/main/java/com/facebook/react/uimanager/events/LockFreeEventDispatcherImpl.java diff --git a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java index 25752febfa2..133bba6a9f5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java +++ b/ReactAndroid/src/main/java/com/facebook/react/config/ReactFeatureFlags.java @@ -82,8 +82,6 @@ public class ReactFeatureFlags { /** Feature Flag to use overflowInset values provided by Yoga */ public static boolean useOverflowInset = false; - public static boolean enableLockFreeEventDispatcher = false; - public static boolean enableAggressiveEventEmitterCleanup = false; public static boolean insertZReorderBarriersOnViewGroupChildren = true; diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java index a46b984e9e7..e0947264fd9 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/FabricUIManager.java @@ -81,7 +81,6 @@ import com.facebook.react.uimanager.ViewManagerRegistry; import com.facebook.react.uimanager.events.EventCategoryDef; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.react.uimanager.events.EventDispatcherImpl; -import com.facebook.react.uimanager.events.LockFreeEventDispatcherImpl; import com.facebook.react.views.text.TextLayoutManager; import com.facebook.react.views.text.TextLayoutManagerMapBuffer; import java.util.HashMap; @@ -241,10 +240,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener { mMountingManager = new MountingManager(viewManagerRegistry, mMountItemExecutor); mMountItemDispatcher = new MountItemDispatcher(mMountingManager, new MountItemDispatchListener()); - mEventDispatcher = - ReactFeatureFlags.enableLockFreeEventDispatcher - ? new LockFreeEventDispatcherImpl(reactContext) - : new EventDispatcherImpl(reactContext); + mEventDispatcher = new EventDispatcherImpl(reactContext); mShouldDeallocateEventDispatcher = true; mEventBeatManager = eventBeatManager; mReactApplicationContext.addLifecycleEventListener(this); diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/LockFreeEventDispatcherImpl.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/LockFreeEventDispatcherImpl.java deleted file mode 100644 index 4c62d7aeca7..00000000000 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/events/LockFreeEventDispatcherImpl.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -package com.facebook.react.uimanager.events; - -import com.facebook.common.logging.FLog; -import com.facebook.infer.annotation.Assertions; -import com.facebook.react.bridge.LifecycleEventListener; -import com.facebook.react.bridge.ReactApplicationContext; -import com.facebook.react.bridge.UiThreadUtil; -import com.facebook.react.common.build.ReactBuildConfig; -import com.facebook.react.modules.core.ChoreographerCompat; -import com.facebook.react.modules.core.ReactChoreographer; -import com.facebook.react.uimanager.common.UIManagerType; -import java.util.concurrent.CopyOnWriteArrayList; - -/** - * Class responsible for dispatching UI events to JS. The main purpose of this class is to act as an - * intermediary between UI code generating events and JS, making sure we don't send more events than - * JS can process. - * - *

To use it, create a subclass of {@link Event} and call {@link #dispatchEvent(Event)} whenever - * there's a UI event to dispatch. - * - *

This class works by installing a Choreographer frame callback on the main thread. This - * callback then enqueues a runnable on the JS thread (if one is not already pending) that is - * responsible for actually dispatch events to JS. This implementation depends on the properties - * that 1) FrameCallbacks run after UI events have been processed in Choreographer.java 2) when we - * enqueue a runnable on the JS queue thread, it won't be called until after any previously enqueued - * JS jobs have finished processing - * - *

If JS is taking a long time processing events, then the UI events generated on the UI thread - * can be coalesced into fewer events so that when the runnable runs, we don't overload JS with a - * ton of events and make it get even farther behind. - * - *

Ideally, we don't need this and JS is fast enough to process all the events each frame, but - * bad things happen, including load on CPUs from the system, and we should handle this case well. - * - *

== Event Cookies == - * - *

An event cookie is made up of the event type id, view tag, and a custom coalescing key. Only - * Events that have the same cookie can be coalesced. - * - *

Event Cookie Composition: VIEW_TAG_MASK = 0x00000000ffffffff EVENT_TYPE_ID_MASK = - * 0x0000ffff00000000 COALESCING_KEY_MASK = 0xffff000000000000 - * - *

This is a copy of EventDispatcherImpl, meant only to remove locking and synchronization. - */ -public class LockFreeEventDispatcherImpl implements EventDispatcher, LifecycleEventListener { - - private final boolean DEBUG_MODE = ReactBuildConfig.DEBUG; - private final String TAG = LockFreeEventDispatcherImpl.class.getSimpleName(); - - private final ReactApplicationContext mReactContext; - private final CopyOnWriteArrayList mListeners = - new CopyOnWriteArrayList<>(); - private final CopyOnWriteArrayList mPostEventDispatchListeners = - new CopyOnWriteArrayList<>(); - private final LockFreeEventDispatcherImpl.ScheduleDispatchFrameCallback mCurrentFrameCallback = - new LockFreeEventDispatcherImpl.ScheduleDispatchFrameCallback(); - - private volatile ReactEventEmitter mReactEventEmitter; - - public LockFreeEventDispatcherImpl(ReactApplicationContext reactContext) { - mReactContext = reactContext; - mReactContext.addLifecycleEventListener(this); - mReactEventEmitter = new ReactEventEmitter(mReactContext); - } - - /** Sends the given Event to C++, where it will be flushed to JS ASAP. */ - public void dispatchEvent(Event event) { - Assertions.assertCondition(event.isInitialized(), "Dispatched event hasn't been initialized"); - Assertions.assertNotNull(mReactEventEmitter); - - if (DEBUG_MODE) { - FLog.v(TAG, "dispatchEvent: " + event.toString()); - } - - for (EventDispatcherListener listener : mListeners) { - listener.onEventDispatch(event); - } - - event.dispatchModern(mReactEventEmitter); - event.dispose(); - } - - public void dispatchAllEvents() { - maybePostFrameCallbackFromNonUI(); - } - - private void maybePostFrameCallbackFromNonUI() { - if (mReactEventEmitter != null) { - // If the host activity is paused, the frame callback may not be currently - // posted. Ensure that it is so that this event gets delivered promptly. - mCurrentFrameCallback.maybePostFromNonUI(); - } else { - // No JS application has started yet, or resumed. This can happen when a ReactRootView is - // added to view hierarchy, but ReactContext creation has not completed yet. In this case, any - // touch event dispatch will hit this codepath, and we simply queue them so that they - // are dispatched once ReactContext creation completes and JS app is running. - } - } - - /** Add a listener to this EventDispatcher. */ - public void addListener(EventDispatcherListener listener) { - mListeners.add(listener); - } - - /** Remove a listener from this EventDispatcher. */ - public void removeListener(EventDispatcherListener listener) { - mListeners.remove(listener); - } - - public void addBatchEventDispatchedListener(BatchEventDispatchedListener listener) { - mPostEventDispatchListeners.add(listener); - } - - public void removeBatchEventDispatchedListener(BatchEventDispatchedListener listener) { - mPostEventDispatchListeners.remove(listener); - } - - @Override - public void onHostResume() { - UiThreadUtil.assertOnUiThread(); - mCurrentFrameCallback.resume(); - } - - @Override - public void onHostPause() { - stopFrameCallback(); - } - - @Override - public void onHostDestroy() { - stopFrameCallback(); - } - - public void onCatalystInstanceDestroyed() { - UiThreadUtil.runOnUiThread( - new Runnable() { - @Override - public void run() { - stopFrameCallback(); - } - }); - } - - private void stopFrameCallback() { - UiThreadUtil.assertOnUiThread(); - mCurrentFrameCallback.stop(); - } - - public void registerEventEmitter(@UIManagerType int uiManagerType, RCTEventEmitter eventEmitter) { - mReactEventEmitter.register(uiManagerType, eventEmitter); - } - - public void registerEventEmitter( - @UIManagerType int uiManagerType, RCTModernEventEmitter eventEmitter) { - mReactEventEmitter.register(uiManagerType, eventEmitter); - } - - public void unregisterEventEmitter(@UIManagerType int uiManagerType) { - mReactEventEmitter.unregister(uiManagerType); - } - - private class ScheduleDispatchFrameCallback extends ChoreographerCompat.FrameCallback { - private volatile boolean mIsPosted = false; - private boolean mShouldStop = false; - - @Override - public void doFrame(long frameTimeNanos) { - UiThreadUtil.assertOnUiThread(); - - if (mShouldStop) { - mIsPosted = false; - } else { - post(); - } - - driveEventBeats(); - } - - public void resume() { - mShouldStop = false; - maybePost(); - } - - public void stop() { - mShouldStop = true; - } - - public void maybePost() { - if (!mIsPosted) { - mIsPosted = true; - post(); - } - } - - private void post() { - ReactChoreographer.getInstance() - .postFrameCallback(ReactChoreographer.CallbackType.TIMERS_EVENTS, mCurrentFrameCallback); - } - - public void maybePostFromNonUI() { - if (mIsPosted) { - return; - } - - // We should only hit this slow path when we receive events while the host activity is paused. - if (mReactContext.isOnUiQueueThread()) { - maybePost(); - } else { - mReactContext.runOnUiQueueThread( - new Runnable() { - @Override - public void run() { - maybePost(); - } - }); - } - } - } - - /** - * Is this a misnomer? It's called "driveEventBeats" but then is just calls - * `onBatchEventDispatched` listeners? Practically, all that `onBatchEventDispatched` is used for - * in Fabric is to drive AsyncEventBeats. - * - *

If this class ships for Fabric, we should remove `driveEventBeats` from here entirely, - * because it no longer needs to be connected to this event dispatcher. We should/probably can - * also delete `onRequestEventBeat` entirely. - */ - private void driveEventBeats() { - for (BatchEventDispatchedListener listener : mPostEventDispatchListeners) { - listener.onBatchEventDispatched(); - } - } -}