feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,58 @@
/*
* 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.
*/
#include "AsynchronousEventBeat.h"
#include <react/debug/react_native_assert.h>
namespace facebook::react {
AsynchronousEventBeat::AsynchronousEventBeat(
RunLoopObserver::Unique uiRunLoopObserver,
RuntimeExecutor runtimeExecutor)
: EventBeat({}),
uiRunLoopObserver_(std::move(uiRunLoopObserver)),
runtimeExecutor_(std::move(runtimeExecutor)) {
uiRunLoopObserver_->setDelegate(this);
uiRunLoopObserver_->enable();
}
void AsynchronousEventBeat::activityDidChange(
const RunLoopObserver::Delegate* delegate,
RunLoopObserver::Activity /*activity*/) const noexcept {
react_native_assert(delegate == this);
induce();
}
void AsynchronousEventBeat::induce() const {
if (!isRequested_ || isBeatCallbackScheduled_) {
return;
}
isRequested_ = false;
// Here we know that `this` object exists because the caller has a strong
// pointer to `owner`. To ensure the object will exist inside
// `runtimeExecutor_` callback, we need to copy the pointer there.
auto weakOwner = uiRunLoopObserver_->getOwner();
isBeatCallbackScheduled_ = true;
runtimeExecutor_([this, weakOwner](jsi::Runtime& runtime) {
isBeatCallbackScheduled_ = false;
auto owner = weakOwner.lock();
if (!owner) {
return;
}
if (beatCallback_) {
beatCallback_(runtime);
}
});
}
} // namespace facebook::react

View File

@@ -0,0 +1,41 @@
/*
* 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.
*/
#include <ReactCommon/RuntimeExecutor.h>
#include <react/renderer/core/EventBeat.h>
#include <react/utils/RunLoopObserver.h>
namespace facebook::react {
/*
* Event beat associated with JavaScript runtime.
* The beat is called on `RuntimeExecutor`'s thread induced by the UI thread
* event loop.
*/
class AsynchronousEventBeat : public EventBeat,
public RunLoopObserver::Delegate {
public:
AsynchronousEventBeat(
RunLoopObserver::Unique uiRunLoopObserver,
RuntimeExecutor runtimeExecutor);
void induce() const override;
#pragma mark - RunLoopObserver::Delegate
void activityDidChange(
const RunLoopObserver::Delegate* delegate,
RunLoopObserver::Activity activity) const noexcept override;
private:
RunLoopObserver::Unique uiRunLoopObserver_;
RuntimeExecutor runtimeExecutor_;
mutable std::atomic<bool> isBeatCallbackScheduled_{false};
};
} // namespace facebook::react

View File

@@ -0,0 +1,39 @@
# 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.
cmake_minimum_required(VERSION 3.13)
set(CMAKE_VERBOSE_MAKEFILE on)
add_compile_options(
-fexceptions
-frtti
-std=c++20
-Wall
-Wpedantic
-DLOG_TAG=\"Fabric\")
file(GLOB react_render_scheduler_SRC CONFIGURE_DEPENDS *.cpp)
add_library(react_render_scheduler STATIC ${react_render_scheduler_SRC})
target_include_directories(react_render_scheduler PUBLIC ${REACT_COMMON_DIR})
target_link_libraries(react_render_scheduler
folly_runtime
glog
jsi
react_config
react_debug
react_render_componentregistry
react_render_core
react_render_debug
react_render_graphics
react_render_mounting
react_render_runtimescheduler
react_render_uimanager
react_utils
rrc_root
rrc_view
yoga
)

View File

@@ -0,0 +1,22 @@
/*
* 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.
*/
#include <vector>
namespace facebook::react {
struct InspectorData {
std::vector<std::string> hierarchy;
int selectedIndex;
std::string fileName;
int lineNumber;
int columnNumber;
// TODO T97216348: remove folly::dynamic from InspectorData struct
folly::dynamic props;
};
} // namespace facebook::react

View File

@@ -0,0 +1,364 @@
/*
* 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.
*/
#include "Scheduler.h"
#include <glog/logging.h>
#include <jsi/jsi.h>
#include <react/debug/react_native_assert.h>
#include <react/renderer/componentregistry/ComponentDescriptorRegistry.h>
#include <react/renderer/core/EventQueueProcessor.h>
#include <react/renderer/core/LayoutContext.h>
#include <react/renderer/debug/SystraceSection.h>
#include <react/renderer/mounting/MountingOverrideDelegate.h>
#include <react/renderer/mounting/ShadowViewMutation.h>
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <react/renderer/uimanager/UIManager.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#ifdef RN_SHADOW_TREE_INTROSPECTION
#include <react/renderer/mounting/stubs.h>
#include <iostream>
#endif
namespace facebook::react {
Scheduler::Scheduler(
const SchedulerToolbox& schedulerToolbox,
UIManagerAnimationDelegate* animationDelegate,
SchedulerDelegate* delegate) {
runtimeExecutor_ = schedulerToolbox.runtimeExecutor;
contextContainer_ = schedulerToolbox.contextContainer;
reactNativeConfig_ =
contextContainer_->at<std::shared_ptr<const ReactNativeConfig>>(
"ReactNativeConfig");
// Creating a container for future `EventDispatcher` instance.
eventDispatcher_ = std::make_shared<std::optional<const EventDispatcher>>();
auto uiManager = std::make_shared<UIManager>(
runtimeExecutor_, schedulerToolbox.backgroundExecutor, contextContainer_);
auto eventOwnerBox = std::make_shared<EventBeat::OwnerBox>();
eventOwnerBox->owner = eventDispatcher_;
auto weakRuntimeScheduler =
contextContainer_->find<std::weak_ptr<RuntimeScheduler>>(
"RuntimeScheduler");
auto runtimeScheduler = weakRuntimeScheduler.has_value()
? weakRuntimeScheduler.value().lock()
: nullptr;
auto eventPipe = [uiManager, runtimeScheduler = runtimeScheduler.get()](
jsi::Runtime& runtime,
const EventTarget* eventTarget,
const std::string& type,
ReactEventPriority priority,
const EventPayload& payload) {
uiManager->visitBinding(
[&](UIManagerBinding const& uiManagerBinding) {
uiManagerBinding.dispatchEvent(
runtime, eventTarget, type, priority, payload);
},
runtime);
};
auto eventPipeConclusion =
[runtimeScheduler = runtimeScheduler.get()](jsi::Runtime& runtime) {
if (runtimeScheduler != nullptr) {
runtimeScheduler->callExpiredTasks(runtime);
}
};
auto statePipe = [uiManager](const StateUpdate& stateUpdate) {
uiManager->updateState(stateUpdate);
};
// Creating an `EventDispatcher` instance inside the already allocated
// container (inside the optional).
eventDispatcher_->emplace(
EventQueueProcessor(eventPipe, eventPipeConclusion, statePipe),
schedulerToolbox.synchronousEventBeatFactory,
schedulerToolbox.asynchronousEventBeatFactory,
eventOwnerBox);
// Casting to `std::shared_ptr<EventDispatcher const>`.
auto eventDispatcher =
EventDispatcher::Shared{eventDispatcher_, &eventDispatcher_->value()};
componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory(
eventDispatcher, contextContainer_);
uiManager->setDelegate(this);
uiManager->setComponentDescriptorRegistry(componentDescriptorRegistry_);
auto bindingsExecutor =
schedulerToolbox.bridgelessBindingsExecutor.has_value()
? schedulerToolbox.bridgelessBindingsExecutor.value()
: runtimeExecutor_;
bindingsExecutor([uiManager](jsi::Runtime& runtime) {
UIManagerBinding::createAndInstallIfNeeded(runtime, uiManager);
});
auto componentDescriptorRegistryKey =
"ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE";
contextContainer_->erase(componentDescriptorRegistryKey);
contextContainer_->insert(
componentDescriptorRegistryKey,
std::weak_ptr<const ComponentDescriptorRegistry>(
componentDescriptorRegistry_));
delegate_ = delegate;
commitHooks_ = schedulerToolbox.commitHooks;
uiManager_ = uiManager;
for (auto& commitHook : commitHooks_) {
uiManager->registerCommitHook(*commitHook);
}
if (animationDelegate != nullptr) {
animationDelegate->setComponentDescriptorRegistry(
componentDescriptorRegistry_);
}
uiManager_->setAnimationDelegate(animationDelegate);
#ifdef ANDROID
removeOutstandingSurfacesOnDestruction_ = true;
#else
removeOutstandingSurfacesOnDestruction_ = reactNativeConfig_->getBool(
"react_fabric:remove_outstanding_surfaces_on_destruction_ios");
#endif
CoreFeatures::cacheLastTextMeasurement =
reactNativeConfig_->getBool("react_fabric:enable_text_measure_cache");
CoreFeatures::enableGranularShadowTreeStateReconciliation =
reactNativeConfig_->getBool(
"react_fabric:enable_granular_shadow_tree_state_reconciliation");
CoreFeatures::enableReportEventPaintTime = reactNativeConfig_->getBool(
"rn_responsiveness_performance:enable_paint_time_reporting");
}
Scheduler::~Scheduler() {
LOG(WARNING) << "Scheduler::~Scheduler() was called (address: " << this
<< ").";
for (auto& commitHook : commitHooks_) {
uiManager_->unregisterCommitHook(*commitHook);
}
// All Surfaces must be explicitly stopped before destroying `Scheduler`.
// The idea is that `UIManager` is allowed to call `Scheduler` only if the
// corresponding `ShadowTree` instance exists.
// The thread-safety of this operation is guaranteed by this requirement.
uiManager_->setDelegate(nullptr);
uiManager_->setAnimationDelegate(nullptr);
// Then, let's verify that the requirement was satisfied.
auto surfaceIds = std::vector<SurfaceId>{};
uiManager_->getShadowTreeRegistry().enumerate(
[&surfaceIds](const ShadowTree& shadowTree, bool&) {
surfaceIds.push_back(shadowTree.getSurfaceId());
});
react_native_assert(
surfaceIds.empty() &&
"Scheduler was destroyed with outstanding Surfaces.");
if (surfaceIds.empty()) {
return;
}
LOG(ERROR) << "Scheduler was destroyed with outstanding Surfaces.";
// If we are here, that means assert didn't fire which indicates that we in
// production.
// Now we have still-running surfaces, which is no good, no good.
// That's indeed a sign of a severe issue on the application layer.
// At this point, we don't have much to lose, so we are trying to unmount all
// outstanding `ShadowTree`s to prevent all stored JSI entities from
// overliving the `Scheduler`. (Unmounting `ShadowNode`s disables
// `EventEmitter`s which destroys JSI objects.)
for (auto surfaceId : surfaceIds) {
uiManager_->getShadowTreeRegistry().visit(
surfaceId,
[](const ShadowTree& shadowTree) { shadowTree.commitEmptyTree(); });
// Removing surfaces is gated because it acquires mutex waiting for commits
// in flight; in theory, it can deadlock.
if (removeOutstandingSurfacesOnDestruction_) {
uiManager_->getShadowTreeRegistry().remove(surfaceId);
}
}
}
void Scheduler::registerSurface(
const SurfaceHandler& surfaceHandler) const noexcept {
surfaceHandler.setContextContainer(getContextContainer());
surfaceHandler.setUIManager(uiManager_.get());
}
InspectorData Scheduler::getInspectorDataForInstance(
const EventEmitter& eventEmitter) const noexcept {
return executeSynchronouslyOnSameThread_CAN_DEADLOCK<InspectorData>(
runtimeExecutor_, [=](jsi::Runtime& runtime) -> InspectorData {
auto uiManagerBinding = UIManagerBinding::getBinding(runtime);
auto value = uiManagerBinding->getInspectorDataForInstance(
runtime, eventEmitter);
// TODO T97216348: avoid transforming jsi into folly::dynamic
auto dynamic = jsi::dynamicFromValue(runtime, value);
auto source = dynamic["source"];
InspectorData result = {};
result.fileName =
source["fileName"].isNull() ? "" : source["fileName"].c_str();
result.lineNumber = (int)source["lineNumber"].getDouble();
result.columnNumber = (int)source["columnNumber"].getDouble();
result.selectedIndex = (int)dynamic["selectedIndex"].getDouble();
// TODO T97216348: remove folly::dynamic from InspectorData struct
result.props = dynamic["props"];
auto hierarchy = dynamic["hierarchy"];
for (auto& i : hierarchy) {
auto viewHierarchyValue = i["name"];
if (!viewHierarchyValue.isNull()) {
result.hierarchy.emplace_back(viewHierarchyValue.c_str());
}
}
return result;
});
}
void Scheduler::unregisterSurface(
const SurfaceHandler& surfaceHandler) const noexcept {
surfaceHandler.setUIManager(nullptr);
}
const ComponentDescriptor*
Scheduler::findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(
ComponentHandle handle) const {
return componentDescriptorRegistry_
->findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(handle);
}
#pragma mark - Delegate
void Scheduler::setDelegate(SchedulerDelegate* delegate) {
delegate_ = delegate;
}
SchedulerDelegate* Scheduler::getDelegate() const {
return delegate_;
}
#pragma mark - UIManagerAnimationDelegate
void Scheduler::animationTick() const {
uiManager_->animationTick();
}
#pragma mark - UIManagerDelegate
void Scheduler::uiManagerDidFinishTransaction(
MountingCoordinator::Shared mountingCoordinator,
bool mountSynchronously) {
SystraceSection s("Scheduler::uiManagerDidFinishTransaction");
if (delegate_ != nullptr) {
auto weakRuntimeScheduler =
contextContainer_->find<std::weak_ptr<RuntimeScheduler>>(
"RuntimeScheduler");
auto runtimeScheduler = weakRuntimeScheduler.has_value()
? weakRuntimeScheduler.value().lock()
: nullptr;
if (runtimeScheduler && !mountSynchronously) {
runtimeScheduler->scheduleRenderingUpdate(
[delegate = delegate_,
mountingCoordinator = std::move(mountingCoordinator)]() {
delegate->schedulerDidFinishTransaction(mountingCoordinator);
});
} else {
delegate_->schedulerDidFinishTransaction(mountingCoordinator);
}
}
}
void Scheduler::uiManagerDidCreateShadowNode(const ShadowNode& shadowNode) {
SystraceSection s("Scheduler::uiManagerDidCreateShadowNode");
if (delegate_ != nullptr) {
delegate_->schedulerDidRequestPreliminaryViewAllocation(
shadowNode.getSurfaceId(), shadowNode);
}
}
void Scheduler::uiManagerDidDispatchCommand(
const ShadowNode::Shared& shadowNode,
const std::string& commandName,
const folly::dynamic& args) {
SystraceSection s("Scheduler::uiManagerDispatchCommand");
if (delegate_ != nullptr) {
auto shadowView = ShadowView(*shadowNode);
delegate_->schedulerDidDispatchCommand(shadowView, commandName, args);
}
}
void Scheduler::uiManagerDidSendAccessibilityEvent(
const ShadowNode::Shared& shadowNode,
const std::string& eventType) {
SystraceSection s("Scheduler::uiManagerDidSendAccessibilityEvent");
if (delegate_ != nullptr) {
auto shadowView = ShadowView(*shadowNode);
delegate_->schedulerDidSendAccessibilityEvent(shadowView, eventType);
}
}
/*
* Set JS responder for a view.
*/
void Scheduler::uiManagerDidSetIsJSResponder(
const ShadowNode::Shared& shadowNode,
bool isJSResponder,
bool blockNativeResponder) {
if (delegate_ != nullptr) {
delegate_->schedulerDidSetIsJSResponder(
ShadowView(*shadowNode), isJSResponder, blockNativeResponder);
}
}
void Scheduler::reportMount(SurfaceId surfaceId) const {
uiManager_->reportMount(surfaceId);
}
ContextContainer::Shared Scheduler::getContextContainer() const {
return contextContainer_;
}
std::shared_ptr<UIManager> Scheduler::getUIManager() const {
return uiManager_;
}
void Scheduler::addEventListener(
const std::shared_ptr<const EventListener>& listener) {
if (eventDispatcher_->has_value()) {
eventDispatcher_->value().addListener(listener);
}
}
void Scheduler::removeEventListener(
const std::shared_ptr<const EventListener>& listener) {
if (eventDispatcher_->has_value()) {
eventDispatcher_->value().removeListener(listener);
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,147 @@
/*
* 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.
*/
#pragma once
#include <memory>
#include <mutex>
#include <ReactCommon/RuntimeExecutor.h>
#include <react/config/ReactNativeConfig.h>
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
#include <react/renderer/components/root/RootComponentDescriptor.h>
#include <react/renderer/core/ComponentDescriptor.h>
#include <react/renderer/core/EventEmitter.h>
#include <react/renderer/core/EventListener.h>
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/mounting/MountingOverrideDelegate.h>
#include <react/renderer/scheduler/InspectorData.h>
#include <react/renderer/scheduler/SchedulerDelegate.h>
#include <react/renderer/scheduler/SchedulerToolbox.h>
#include <react/renderer/scheduler/SurfaceHandler.h>
#include <react/renderer/uimanager/UIManagerAnimationDelegate.h>
#include <react/renderer/uimanager/UIManagerBinding.h>
#include <react/renderer/uimanager/UIManagerDelegate.h>
#include <react/utils/ContextContainer.h>
namespace facebook::react {
/*
* Scheduler coordinates Shadow Tree updates and event flows.
*/
class Scheduler final : public UIManagerDelegate {
public:
Scheduler(
const SchedulerToolbox& schedulerToolbox,
UIManagerAnimationDelegate* animationDelegate,
SchedulerDelegate* delegate);
~Scheduler() override;
#pragma mark - Surface Management
/*
* Registers and unregisters a `SurfaceHandler` object in the `Scheduler`.
* All registered `SurfaceHandler` objects must be unregistered
* (with the same `Scheduler`) before their deallocation.
*/
void registerSurface(const SurfaceHandler& surfaceHandler) const noexcept;
void unregisterSurface(const SurfaceHandler& surfaceHandler) const noexcept;
InspectorData getInspectorDataForInstance(
const EventEmitter& eventEmitter) const noexcept;
/*
* This is broken. Please do not use.
* `ComponentDescriptor`s are not designed to be used outside of `UIManager`,
* there is no any guarantees about their lifetime.
*/
const ComponentDescriptor*
findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(
ComponentHandle handle) const;
#pragma mark - Delegate
/*
* Sets and gets the Scheduler's delegate.
* If you requesting a ComponentDescriptor and unsure that it's there, you are
* doing something wrong.
*/
void setDelegate(SchedulerDelegate* delegate);
SchedulerDelegate* getDelegate() const;
#pragma mark - UIManagerAnimationDelegate
// This is not needed on iOS or any platform that has a "pull" instead of
// "push" MountingCoordinator model. This just tells the delegate an update
// is available and that it should `pullTransaction`; we may want to rename
// this to be more generic and not animation-specific.
void animationTick() const;
#pragma mark - UIManagerDelegate
void uiManagerDidFinishTransaction(
MountingCoordinator::Shared mountingCoordinator,
bool mountSynchronously) override;
void uiManagerDidCreateShadowNode(const ShadowNode& shadowNode) override;
void uiManagerDidDispatchCommand(
const ShadowNode::Shared& shadowNode,
const std::string& commandName,
const folly::dynamic& args) override;
void uiManagerDidSendAccessibilityEvent(
const ShadowNode::Shared& shadowNode,
const std::string& eventType) override;
void uiManagerDidSetIsJSResponder(
const ShadowNode::Shared& shadowNode,
bool isJSResponder,
bool blockNativeResponder) override;
#pragma mark - ContextContainer
ContextContainer::Shared getContextContainer() const;
#pragma mark - UIManager
std::shared_ptr<UIManager> getUIManager() const;
void reportMount(SurfaceId surfaceId) const;
#pragma mark - Event listeners
void addEventListener(const std::shared_ptr<const EventListener>& listener);
void removeEventListener(
const std::shared_ptr<const EventListener>& listener);
private:
friend class SurfaceHandler;
SchedulerDelegate* delegate_;
SharedComponentDescriptorRegistry componentDescriptorRegistry_;
RuntimeExecutor runtimeExecutor_;
std::shared_ptr<UIManager> uiManager_;
std::shared_ptr<const ReactNativeConfig> reactNativeConfig_;
std::vector<std::shared_ptr<UIManagerCommitHook>> commitHooks_;
/*
* At some point, we have to have an owning shared pointer to something that
* will become an `EventDispatcher` a moment later. That's why we have it as a
* pointer to an optional: we construct the pointer first, share that with
* parts that need to have ownership (and only ownership) of that, and then
* fill the optional.
*/
std::shared_ptr<std::optional<const EventDispatcher>> eventDispatcher_;
/**
* Hold onto ContextContainer. See SchedulerToolbox.
* Must not be nullptr.
*/
ContextContainer::Shared contextContainer_;
/*
* Temporary flags.
*/
bool removeOutstandingSurfacesOnDestruction_{false};
bool reduceDeleteCreateMutationLayoutAnimation_{false};
};
} // namespace facebook::react

View File

@@ -0,0 +1,58 @@
/*
* 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.
*/
#pragma once
#include <memory>
#include <react/renderer/core/ReactPrimitives.h>
#include <react/renderer/mounting/MountingCoordinator.h>
#include <react/renderer/mounting/ShadowView.h>
namespace facebook::react {
/*
* Abstract class for Scheduler's delegate.
*/
class SchedulerDelegate {
public:
/*
* Called right after Scheduler computed (and laid out) a new updated version
* of the tree and calculated a set of mutations which are sufficient
* to construct a new one.
*/
virtual void schedulerDidFinishTransaction(
const MountingCoordinator::Shared& mountingCoordinator) = 0;
/*
* Called right after a new ShadowNode was created.
*/
virtual void schedulerDidRequestPreliminaryViewAllocation(
SurfaceId surfaceId,
const ShadowNode& shadowView) = 0;
virtual void schedulerDidDispatchCommand(
const ShadowView& shadowView,
const std::string& commandName,
const folly::dynamic& args) = 0;
virtual void schedulerDidSendAccessibilityEvent(
const ShadowView& shadowView,
const std::string& eventType) = 0;
/*
* Set JS responder for a view
*/
virtual void schedulerDidSetIsJSResponder(
const ShadowView& shadowView,
bool isJSResponder,
bool blockNativeResponder) = 0;
virtual ~SchedulerDelegate() noexcept = default;
};
} // namespace facebook::react

View File

@@ -0,0 +1,80 @@
/*
* 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.
*/
#pragma once
#include <memory>
#include <ReactCommon/RuntimeExecutor.h>
#include <react/renderer/componentregistry/ComponentDescriptorFactory.h>
#include <react/renderer/core/EventBeat.h>
#include <react/renderer/leakchecker/LeakChecker.h>
#include <react/renderer/uimanager/UIManagerCommitHook.h>
#include <react/renderer/uimanager/primitives.h>
#include <react/utils/ContextContainer.h>
#include <react/utils/RunLoopObserver.h>
namespace facebook::react {
/*
* Contains all external dependencies of Scheduler.
* Copyable.
*/
struct SchedulerToolbox final {
/*
* Represents general purpose DI container for product components/needs.
* Must not be `nullptr`.
*/
ContextContainer::Shared contextContainer;
/*
* Represents externally managed, lazily available collection of components.
*/
ComponentRegistryFactory componentRegistryFactory;
/*
* Represents running JavaScript VM and associated execution queue.
* Can execute lambdas before main bundle has loaded.
*/
std::optional<RuntimeExecutor> bridgelessBindingsExecutor;
/*
* Represents running JavaScript VM and associated execution queue.
* Executes lambdas after main bundle has loaded.
*/
RuntimeExecutor runtimeExecutor;
/*
* Represent connections with a platform-specific UI run loops.
*/
RunLoopObserver::Factory mainRunLoopObserverFactory;
/*
* Asynchronous & synchronous event beats.
* Represent connections with the platform-specific run loops and general
* purpose background queue.
*/
EventBeat::Factory asynchronousEventBeatFactory;
EventBeat::Factory synchronousEventBeatFactory;
/*
* General-purpose executor that is used to dispatch work on some utility
* queue (mostly) asynchronously to avoid unnecessary blocking the caller
* queue.
* The concrete implementation can use a serial or concurrent queue.
* Due to architectural constraints, the concrete implementation *must* call
* the call back synchronously if the executor is invoked on the main thread.
*/
BackgroundExecutor backgroundExecutor;
/*
* A list of `UIManagerCommitHook`s that should be registered in `UIManager`.
*/
std::vector<std::shared_ptr<UIManagerCommitHook>> commitHooks;
};
} // namespace facebook::react

View File

@@ -0,0 +1,335 @@
/*
* 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.
*/
#include "SurfaceHandler.h"
#include <react/debug/react_native_assert.h>
#include <react/renderer/debug/SystraceSection.h>
#include <react/renderer/uimanager/UIManager.h>
namespace facebook::react {
using Status = SurfaceHandler::Status;
SurfaceHandler::SurfaceHandler(
const std::string& moduleName,
SurfaceId surfaceId) noexcept {
parameters_.moduleName = moduleName;
parameters_.surfaceId = surfaceId;
}
SurfaceHandler::SurfaceHandler(SurfaceHandler&& other) noexcept {
operator=(std::move(other));
}
SurfaceHandler& SurfaceHandler::operator=(SurfaceHandler&& other) noexcept {
std::unique_lock lock1(linkMutex_, std::defer_lock);
std::unique_lock lock2(parametersMutex_, std::defer_lock);
std::unique_lock lock3(other.linkMutex_, std::defer_lock);
std::unique_lock lock4(other.parametersMutex_, std::defer_lock);
std::lock(lock1, lock2, lock3, lock4);
link_ = other.link_;
parameters_ = other.parameters_;
other.link_ = Link{};
other.parameters_ = Parameters{};
other.parameters_.contextContainer = parameters_.contextContainer;
return *this;
}
#pragma mark - Surface Life-Cycle Management
void SurfaceHandler::setContextContainer(
ContextContainer::Shared contextContainer) const noexcept {
parameters_.contextContainer = std::move(contextContainer);
}
Status SurfaceHandler::getStatus() const noexcept {
std::shared_lock lock(linkMutex_);
return link_.status;
}
void SurfaceHandler::start() const noexcept {
SystraceSection s("SurfaceHandler::start");
std::unique_lock lock(linkMutex_);
react_native_assert(
link_.status == Status::Registered && "Surface must be registered.");
react_native_assert(
getLayoutConstraints().layoutDirection != LayoutDirection::Undefined &&
"layoutDirection must be set.");
react_native_assert(
parameters_.contextContainer && "ContextContainer must be set.");
auto parameters = Parameters{};
{
SystraceSection s2("SurfaceHandler::start::paramsLock");
std::shared_lock parametersLock(parametersMutex_);
parameters = parameters_;
}
auto shadowTree = std::make_unique<ShadowTree>(
parameters.surfaceId,
parameters.layoutConstraints,
parameters.layoutContext,
*link_.uiManager,
*parameters.contextContainer);
link_.shadowTree = shadowTree.get();
link_.uiManager->startSurface(
std::move(shadowTree),
parameters.moduleName,
parameters.props,
parameters_.displayMode);
link_.status = Status::Running;
applyDisplayMode(parameters.displayMode);
}
void SurfaceHandler::stop() const noexcept {
auto shadowTree = ShadowTree::Unique{};
{
std::unique_lock lock(linkMutex_);
react_native_assert(
link_.status == Status::Running && "Surface must be running.");
link_.status = Status::Registered;
link_.shadowTree = nullptr;
shadowTree = link_.uiManager->stopSurface(parameters_.surfaceId);
}
// As part of stopping a Surface, we need to properly destroy all
// mounted views, so we need to commit an empty tree to trigger all
// side-effects (including destroying and removing mounted views).
react_native_assert(shadowTree && "`shadowTree` must not be null.");
if (shadowTree) {
shadowTree->commitEmptyTree();
}
}
void SurfaceHandler::setDisplayMode(DisplayMode displayMode) const noexcept {
auto parameters = Parameters{};
{
std::unique_lock lock(parametersMutex_);
if (parameters_.displayMode == displayMode) {
return;
}
parameters_.displayMode = displayMode;
parameters = parameters_;
}
{
std::shared_lock lock(linkMutex_);
if (link_.status != Status::Running) {
return;
}
link_.uiManager->setSurfaceProps(
parameters.surfaceId,
parameters.moduleName,
parameters.props,
parameters.displayMode);
applyDisplayMode(displayMode);
}
}
DisplayMode SurfaceHandler::getDisplayMode() const noexcept {
std::shared_lock lock(parametersMutex_);
return parameters_.displayMode;
}
#pragma mark - Accessors
SurfaceId SurfaceHandler::getSurfaceId() const noexcept {
std::shared_lock lock(parametersMutex_);
return parameters_.surfaceId;
}
void SurfaceHandler::setSurfaceId(SurfaceId surfaceId) const noexcept {
std::unique_lock lock(parametersMutex_);
parameters_.surfaceId = surfaceId;
}
std::string SurfaceHandler::getModuleName() const noexcept {
std::shared_lock lock(parametersMutex_);
return parameters_.moduleName;
}
void SurfaceHandler::setProps(const folly::dynamic& props) const noexcept {
SystraceSection s("SurfaceHandler::setProps");
auto parameters = Parameters{};
{
std::unique_lock lock(parametersMutex_);
parameters_.props = props;
parameters = parameters_;
}
{
std::shared_lock lock(linkMutex_);
if (link_.status == Status::Running) {
link_.uiManager->setSurfaceProps(
parameters.surfaceId,
parameters.moduleName,
parameters.props,
parameters.displayMode);
}
}
}
folly::dynamic SurfaceHandler::getProps() const noexcept {
std::shared_lock lock(parametersMutex_);
return parameters_.props;
}
std::shared_ptr<const MountingCoordinator>
SurfaceHandler::getMountingCoordinator() const noexcept {
std::shared_lock lock(linkMutex_);
react_native_assert(
link_.status != Status::Unregistered && "Surface must be registered.");
react_native_assert(
link_.shadowTree && "`link_.shadowTree` must not be null.");
return link_.shadowTree->getMountingCoordinator();
}
#pragma mark - Layout
Size SurfaceHandler::measure(
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept {
std::shared_lock lock(linkMutex_);
if (link_.status != Status::Running) {
return layoutConstraints.clamp({0, 0});
}
react_native_assert(
link_.shadowTree && "`link_.shadowTree` must not be null.");
auto currentRootShadowNode =
link_.shadowTree->getCurrentRevision().rootShadowNode;
PropsParserContext propsParserContext{
parameters_.surfaceId, *parameters_.contextContainer.get()};
auto rootShadowNode = currentRootShadowNode->clone(
propsParserContext, layoutConstraints, layoutContext);
rootShadowNode->layoutIfNeeded();
return rootShadowNode->getLayoutMetrics().frame.size;
}
void SurfaceHandler::constraintLayout(
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept {
SystraceSection s("SurfaceHandler::constraintLayout");
{
std::unique_lock lock(parametersMutex_);
if (parameters_.layoutConstraints == layoutConstraints &&
parameters_.layoutContext == layoutContext) {
return;
}
parameters_.layoutConstraints = layoutConstraints;
parameters_.layoutContext = layoutContext;
}
{
std::shared_lock lock(linkMutex_);
if (link_.status != Status::Running) {
return;
}
PropsParserContext propsParserContext{
parameters_.surfaceId, *parameters_.contextContainer.get()};
react_native_assert(
link_.shadowTree && "`link_.shadowTree` must not be null.");
link_.shadowTree->commit(
[&](const RootShadowNode& oldRootShadowNode) {
return oldRootShadowNode.clone(
propsParserContext, layoutConstraints, layoutContext);
},
{/* default commit options */});
}
}
LayoutConstraints SurfaceHandler::getLayoutConstraints() const noexcept {
std::shared_lock lock(parametersMutex_);
return parameters_.layoutConstraints;
}
LayoutContext SurfaceHandler::getLayoutContext() const noexcept {
std::shared_lock lock(parametersMutex_);
return parameters_.layoutContext;
}
#pragma mark - Private
void SurfaceHandler::applyDisplayMode(DisplayMode displayMode) const noexcept {
SystraceSection s("SurfaceHandler::applyDisplayMode");
react_native_assert(
link_.status == Status::Running && "Surface must be running.");
react_native_assert(
link_.shadowTree && "`link_.shadowTree` must not be null.");
switch (displayMode) {
case DisplayMode::Visible:
link_.shadowTree->setCommitMode(ShadowTree::CommitMode::Normal);
break;
case DisplayMode::Suspended:
link_.shadowTree->setCommitMode(ShadowTree::CommitMode::Suspended);
break;
case DisplayMode::Hidden:
link_.shadowTree->setCommitMode(ShadowTree::CommitMode::Normal);
// Getting a current revision.
auto revision = link_.shadowTree->getCurrentRevision();
// Committing an empty tree to force mounting to disassemble view
// hierarchy.
link_.shadowTree->commitEmptyTree();
link_.shadowTree->setCommitMode(ShadowTree::CommitMode::Suspended);
// Committing the current revision back. It will be mounted only when
// `DisplayMode` is changed back to `Normal`.
link_.shadowTree->commit(
[&](const RootShadowNode& /*oldRootShadowNode*/) {
return std::static_pointer_cast<RootShadowNode>(
revision.rootShadowNode->ShadowNode::clone({}));
},
{/* default commit options */});
break;
}
}
void SurfaceHandler::setUIManager(const UIManager* uiManager) const noexcept {
std::unique_lock lock(linkMutex_);
react_native_assert(
link_.status != Status::Running && "Surface must not be running.");
if (link_.uiManager == uiManager) {
return;
}
link_.uiManager = uiManager;
link_.status =
uiManager != nullptr ? Status::Registered : Status::Unregistered;
}
SurfaceHandler::~SurfaceHandler() noexcept {
react_native_assert(
link_.status == Status::Unregistered &&
"`SurfaceHandler` must be unregistered (or moved-from) before deallocation.");
}
} // namespace facebook::react

View File

@@ -0,0 +1,208 @@
/*
* 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.
*/
#pragma once
#include <memory>
#include <shared_mutex>
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/core/LayoutContext.h>
#include <react/renderer/core/ReactPrimitives.h>
#include <react/utils/ContextContainer.h>
namespace facebook::react {
class Scheduler;
class ShadowTree;
class MountingCoordinator;
class UIManager;
/*
* Represents a running React Native surface and provides control over it.
* The instances of this class are movable only.
* The instances of this class can be safely deallocated only if `status` is
* `Unregistered`; this is a way to enforce internal consistency and
* deallocation ordering constraints the core relies on.
*
*
* Even though all methods of the class are thread-safe, the consumer side must
* ensure the logical consistency of some methods (e.g. calling `stop` for
* non-running surface will crash).
*/
class SurfaceHandler {
public:
/*
* Represents a status of the `SurfaceHandler` instance.
*/
enum class Status {
/*
* Newly created, moved-from, or already-unregistered instances. The only
* state in which the object can be safely deallocated.
*/
Unregistered = 0,
/*
* Registered instances that have an internal reference to a `UIManager`
* instance and ready to start a surface.
*/
Registered = 1,
/*
* Registered and running instances.
*/
Running = 2,
};
/*
* Can be constructed anytime with a `moduleName` and a `surfaceId`.
*/
SurfaceHandler(const std::string& moduleName, SurfaceId surfaceId) noexcept;
virtual ~SurfaceHandler() noexcept;
/*
* Movable-only.
*/
SurfaceHandler(SurfaceHandler&& other) noexcept;
SurfaceHandler(const SurfaceHandler& SurfaceHandler) noexcept = delete;
SurfaceHandler& operator=(SurfaceHandler&& other) noexcept;
SurfaceHandler& operator=(const SurfaceHandler& other) noexcept = delete;
#pragma mark - Surface Life-Cycle Management
/*
* Must be called before surface is started.
*/
void setContextContainer(
ContextContainer::Shared contextContainer) const noexcept;
/*
* Returns a momentum value of the status.
*/
Status getStatus() const noexcept;
/*
* Starts or stops the surface.
* Can not be called when the status is `Unregistered`.
* `start()` must not be called for a running surface, and `stop()` must not
* be called for a not running surface.
*/
void start() const noexcept;
void stop() const noexcept;
/*
* Sets (and gets) the running mode.
* The running mode can be changed anytime (even for `Unregistered` surface).
*/
virtual void setDisplayMode(DisplayMode displayMode) const noexcept;
DisplayMode getDisplayMode() const noexcept;
#pragma mark - Accessors
SurfaceId getSurfaceId() const noexcept;
void setSurfaceId(SurfaceId surfaceId) const noexcept;
std::string getModuleName() const noexcept;
/*
* Provides access for surface props.
* Props can be changed anytime (even for `Unregistered` surface).
*/
void setProps(const folly::dynamic& props) const noexcept;
folly::dynamic getProps() const noexcept;
/*
* Returns a `MountingCoordinator` instance associated with a running surface.
* Can be not be called when the status is `Unregistered`.
* The returning value cannot be `nullptr`.
*/
std::shared_ptr<const MountingCoordinator> getMountingCoordinator()
const noexcept;
#pragma mark - Layout
/*
* Measures the surface with given layout constraints and layout context.
* Returns zero size if called on the stopped or unregistered surface.
*/
Size measure(
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept;
/*
* Sets layout constraints and layout context for the surface.
*/
void constraintLayout(
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept;
/*
* Returns layout constraints and layout context associated with the surface.
*/
LayoutConstraints getLayoutConstraints() const noexcept;
LayoutContext getLayoutContext() const noexcept;
private:
friend class Scheduler;
/*
* Must be called by `Scheduler` during registration process.
*/
void setUIManager(const UIManager* uiManager) const noexcept;
void applyDisplayMode(DisplayMode displayMode) const noexcept;
#pragma mark - Link & Parameters
/*
* All data members of the class are split into two groups (`Link` and
* `Parameters`) that require separate synchronization. This way it's easier
* to see that proper lock is acquired. Separate synchronization is needed to
* prevent deadlocks.
*/
/*
* Represents parameters of the surface. Parameters can be changed
* independently from controlling the running state
* (registering/unregistering, starting/stopping) of the surface.
* Changing parameters requires acquiring a unique lock; reading needs only
* a shared lock.
*/
struct Parameters {
std::string moduleName{};
SurfaceId surfaceId{};
DisplayMode displayMode{DisplayMode::Visible};
folly::dynamic props{};
LayoutConstraints layoutConstraints{};
LayoutContext layoutContext{};
ContextContainer::Shared contextContainer{};
};
/*
* Represents an underlying link to a `ShadowTree` and an `UIManager`.
* Registering, unregistering, starting, and stopping the surface requires
* acquiring a unique lock; other access needs only a shared lock.
*/
struct Link {
Status status{Status::Unregistered};
const UIManager* uiManager{};
const ShadowTree* shadowTree{};
};
/*
* `link_` and `linkMutex_` pair.
*/
mutable std::shared_mutex linkMutex_;
mutable Link link_;
/*
* `parameters_` and `parametersMutex_` pair.
*/
mutable std::shared_mutex parametersMutex_;
mutable Parameters parameters_;
};
} // namespace facebook::react

View File

@@ -0,0 +1,102 @@
/*
* 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.
*/
#include "SurfaceManager.h"
#include <react/renderer/scheduler/Scheduler.h>
namespace facebook::react {
SurfaceManager::SurfaceManager(const Scheduler& scheduler) noexcept
: scheduler_(scheduler) {}
void SurfaceManager::startSurface(
SurfaceId surfaceId,
const std::string& moduleName,
const folly::dynamic& props,
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept {
{
std::unique_lock lock(mutex_);
auto surfaceHandler = SurfaceHandler{moduleName, surfaceId};
surfaceHandler.setContextContainer(scheduler_.getContextContainer());
registry_.emplace(surfaceId, std::move(surfaceHandler));
}
visit(surfaceId, [&](const SurfaceHandler& surfaceHandler) {
surfaceHandler.setProps(props);
surfaceHandler.constraintLayout(layoutConstraints, layoutContext);
scheduler_.registerSurface(surfaceHandler);
surfaceHandler.start();
});
}
void SurfaceManager::stopSurface(SurfaceId surfaceId) const noexcept {
visit(surfaceId, [&](const SurfaceHandler& surfaceHandler) {
surfaceHandler.stop();
scheduler_.unregisterSurface(surfaceHandler);
});
{
std::unique_lock lock(mutex_);
auto iterator = registry_.find(surfaceId);
registry_.erase(iterator);
}
}
Size SurfaceManager::measureSurface(
SurfaceId surfaceId,
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept {
auto size = Size{};
visit(surfaceId, [&](const SurfaceHandler& surfaceHandler) {
size = surfaceHandler.measure(layoutConstraints, layoutContext);
});
return size;
}
MountingCoordinator::Shared SurfaceManager::findMountingCoordinator(
SurfaceId surfaceId) const noexcept {
auto mountingCoordinator = MountingCoordinator::Shared{};
visit(surfaceId, [&](const SurfaceHandler& surfaceHandler) {
mountingCoordinator = surfaceHandler.getMountingCoordinator();
});
return mountingCoordinator;
}
void SurfaceManager::constraintSurfaceLayout(
SurfaceId surfaceId,
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept {
visit(surfaceId, [=](const SurfaceHandler& surfaceHandler) {
surfaceHandler.constraintLayout(layoutConstraints, layoutContext);
});
}
void SurfaceManager::visit(
SurfaceId surfaceId,
const std::function<void(SurfaceHandler const& surfaceHandler)>& callback)
const noexcept {
std::shared_lock lock(mutex_);
auto iterator = registry_.find(surfaceId);
if (iterator == registry_.end()) {
return;
}
callback(iterator->second);
}
} // namespace facebook::react

View File

@@ -0,0 +1,66 @@
/*
* 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.
*/
#pragma once
#include <mutex>
#include <shared_mutex>
#include <unordered_map>
#include <react/renderer/core/LayoutConstraints.h>
#include <react/renderer/mounting/MountingCoordinator.h>
#include <react/renderer/scheduler/SurfaceHandler.h>
namespace facebook::react {
/*
* `SurfaceManager` allows controlling React Native Surfaces via
* `SurfaceHandler` without using `SurfaceHandler` directly. `SurfaceManager`
* maintains a registry of `SurfaceHandler`s and allows to reference to them via
* a `SurfaceId`.
* The is supposed to be used during the transition period only.
*/
class SurfaceManager final {
public:
explicit SurfaceManager(const Scheduler& scheduler) noexcept;
#pragma mark - Surface Management
void startSurface(
SurfaceId surfaceId,
const std::string& moduleName,
const folly::dynamic& props,
const LayoutConstraints& layoutConstraints = {},
const LayoutContext& layoutContext = {}) const noexcept;
void stopSurface(SurfaceId surfaceId) const noexcept;
Size measureSurface(
SurfaceId surfaceId,
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept;
void constraintSurfaceLayout(
SurfaceId surfaceId,
const LayoutConstraints& layoutConstraints,
const LayoutContext& layoutContext) const noexcept;
MountingCoordinator::Shared findMountingCoordinator(
SurfaceId surfaceId) const noexcept;
private:
void visit(
SurfaceId surfaceId,
const std::function<void(SurfaceHandler const& surfaceHandler)>& callback)
const noexcept;
const Scheduler& scheduler_;
mutable std::shared_mutex mutex_; // Protects `registry_`.
mutable std::unordered_map<SurfaceId, SurfaceHandler> registry_{};
};
} // namespace facebook::react

View File

@@ -0,0 +1,59 @@
/*
* 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.
*/
#include "SynchronousEventBeat.h"
#include <react/debug/react_native_assert.h>
#include <utility>
namespace facebook::react {
SynchronousEventBeat::SynchronousEventBeat(
RunLoopObserver::Unique uiRunLoopObserver,
RuntimeExecutor runtimeExecutor,
std::shared_ptr<RuntimeScheduler> runtimeScheduler)
: EventBeat({}),
uiRunLoopObserver_(std::move(uiRunLoopObserver)),
runtimeExecutor_(std::move(runtimeExecutor)),
runtimeScheduler_(std::move(runtimeScheduler)) {
uiRunLoopObserver_->setDelegate(this);
uiRunLoopObserver_->enable();
}
void SynchronousEventBeat::activityDidChange(
const RunLoopObserver::Delegate* delegate,
RunLoopObserver::Activity /*activity*/) const noexcept {
react_native_assert(delegate == this);
lockExecutorAndBeat();
}
void SynchronousEventBeat::induce() const {
if (!this->isRequested_) {
return;
}
if (uiRunLoopObserver_->isOnRunLoopThread()) {
this->lockExecutorAndBeat();
}
}
void SynchronousEventBeat::lockExecutorAndBeat() const {
if (!this->isRequested_) {
return;
}
if (runtimeScheduler_) {
runtimeScheduler_->executeNowOnTheSameThread(
[this](jsi::Runtime& runtime) { beat(runtime); });
} else {
executeSynchronouslyOnSameThread_CAN_DEADLOCK(
runtimeExecutor_, [this](jsi::Runtime& runtime) { beat(runtime); });
}
}
} // namespace facebook::react

View File

@@ -0,0 +1,45 @@
/*
* 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.
*/
#pragma once
#include <ReactCommon/RuntimeExecutor.h>
#include <react/renderer/core/EventBeat.h>
#include <react/renderer/runtimescheduler/RuntimeScheduler.h>
#include <react/utils/RunLoopObserver.h>
namespace facebook::react {
/*
* Event beat associated with main run loop.
* The callback is always called on the main thread.
*/
class SynchronousEventBeat final : public EventBeat,
public RunLoopObserver::Delegate {
public:
SynchronousEventBeat(
RunLoopObserver::Unique uiRunLoopObserver,
RuntimeExecutor runtimeExecutor,
std::shared_ptr<RuntimeScheduler> runtimeScheduler);
void induce() const override;
#pragma mark - RunLoopObserver::Delegate
void activityDidChange(
const RunLoopObserver::Delegate* delegate,
RunLoopObserver::Activity activity) const noexcept override;
private:
void lockExecutorAndBeat() const;
RunLoopObserver::Unique uiRunLoopObserver_;
RuntimeExecutor runtimeExecutor_;
std::shared_ptr<RuntimeScheduler> runtimeScheduler_;
};
} // namespace facebook::react