From 9cd98fa3eeded9f9bded846ac8ec94f05052a6c7 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Sun, 25 Apr 2021 16:14:03 -0700 Subject: [PATCH] Prevent redundant dispatches onto RuntimeExecutor queue in AsynchronousEventBeat::induce Summary: Changelog: [internal] Prevent redundant calls to RuntimeExecutor by making sure no two calls to the executor are scheduled at the same time. Reviewed By: mdvacca Differential Revision: D27989412 fbshipit-source-id: 8f9b1591f7c9c2265fd4b05bf3dc5505ffc2568b --- .../react/fabric/jni/AsyncEventBeatV2.cpp | 69 +++++++++++++++++++ .../react/fabric/jni/AsyncEventBeatV2.h | 40 +++++++++++ .../com/facebook/react/fabric/jni/Binding.cpp | 40 ++++++++--- 3 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.cpp create mode 100644 ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.h diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.cpp new file mode 100644 index 00000000000..1d9b2dd27f2 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include +#include + +#include "AsyncEventBeatV2.h" + +namespace facebook::react { + +AsyncEventBeatV2::AsyncEventBeatV2( + EventBeat::SharedOwnerBox const &ownerBox, + EventBeatManager *eventBeatManager, + RuntimeExecutor runtimeExecutor, + jni::global_ref javaUIManager) + : EventBeat(ownerBox), + eventBeatManager_(eventBeatManager), + runtimeExecutor_(runtimeExecutor), + javaUIManager_(javaUIManager) { + eventBeatManager->addObserver(*this); +} + +AsyncEventBeatV2::~AsyncEventBeatV2() { + eventBeatManager_->removeObserver(*this); +} + +void AsyncEventBeatV2::tick() const { + if (!isRequested_ || isBeatCallbackScheduled_) { + return; + } + + isRequested_ = false; + isBeatCallbackScheduled_ = true; + + runtimeExecutor_([this, ownerBox = ownerBox_](jsi::Runtime &runtime) { + isBeatCallbackScheduled_ = false; + auto owner = ownerBox->owner.lock(); + if (!owner) { + return; + } + + if (beatCallback_) { + beatCallback_(runtime); + } + }); +} + +void AsyncEventBeatV2::induce() const { + tick(); +} + +void AsyncEventBeatV2::request() const { + bool alreadyRequested = isRequested_; + EventBeat::request(); + if (!alreadyRequested) { + // Notifies java side that an event will be dispatched (e.g. LayoutEvent) + static auto onRequestEventBeat = + jni::findClassStatic("com/facebook/react/fabric/FabricUIManager") + ->getMethod("onRequestEventBeat"); + onRequestEventBeat(javaUIManager_); + } +} + +} // namespace facebook::react diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.h b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.h new file mode 100644 index 00000000000..acd682f4cd8 --- /dev/null +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/AsyncEventBeatV2.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +#include + +#include "EventBeatManager.h" + +namespace facebook::react { + +class AsyncEventBeatV2 final : public EventBeat, + public EventBeatManagerObserver { + public: + AsyncEventBeatV2( + EventBeat::SharedOwnerBox const &ownerBox, + EventBeatManager *eventBeatManager, + RuntimeExecutor runtimeExecutor, + jni::global_ref javaUIManager); + + ~AsyncEventBeatV2() override; + + void tick() const override; + + void induce() const override; + + void request() const override; + + private: + EventBeatManager *eventBeatManager_; + RuntimeExecutor runtimeExecutor_; + jni::global_ref javaUIManager_; + mutable std::atomic isBeatCallbackScheduled_{false}; +}; + +} // namespace facebook::react diff --git a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp index 192f8493f94..631d20ee8cd 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp +++ b/ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.cpp @@ -7,6 +7,7 @@ #include "Binding.h" #include "AsyncEventBeat.h" +#include "AsyncEventBeatV2.h" #include "EventEmitterWrapper.h" #include "ReactNativeConfigHolder.h" #include "StateWrapperImpl.h" @@ -488,21 +489,40 @@ void Binding::installFabricUIManager( std::make_shared(jsMessageQueueThread); auto runtimeExecutor = runtimeExecutorHolder->cthis()->get(); + auto enableV2AsynchronousEventBeat = + config->getBool("react_fabric:enable_asynchronous_event_beat_v2_android"); + // TODO: T31905686 Create synchronous Event Beat jni::global_ref localJavaUIManager = javaUIManager_; EventBeat::Factory synchronousBeatFactory = - [eventBeatManager, runtimeExecutor, localJavaUIManager]( - EventBeat::SharedOwnerBox const &ownerBox) { - return std::make_unique( - ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); - }; + [eventBeatManager, + runtimeExecutor, + localJavaUIManager, + enableV2AsynchronousEventBeat](EventBeat::SharedOwnerBox const &ownerBox) + -> std::unique_ptr { + if (enableV2AsynchronousEventBeat) { + return std::make_unique( + ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); + } else { + return std::make_unique( + ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); + } + }; EventBeat::Factory asynchronousBeatFactory = - [eventBeatManager, runtimeExecutor, localJavaUIManager]( - EventBeat::SharedOwnerBox const &ownerBox) { - return std::make_unique( - ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); - }; + [eventBeatManager, + runtimeExecutor, + localJavaUIManager, + enableV2AsynchronousEventBeat](EventBeat::SharedOwnerBox const &ownerBox) + -> std::unique_ptr { + if (enableV2AsynchronousEventBeat) { + return std::make_unique( + ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); + } else { + return std::make_unique( + ownerBox, eventBeatManager, runtimeExecutor, localJavaUIManager); + } + }; contextContainer->insert("ReactNativeConfig", config); contextContainer->insert("FabricUIManager", javaUIManager_);