Fabric: Start/stop Surface calls were moved down to C++ layer

Summary:
There is no need to make JS calls to start or stop React Native apps; Scheduler does it automatically. Yay!

With this change (because we have to change Scheduler API) we are starting slow process migrating away from using term `reactRootTag` when we refer to running a ReactNative app (aka Surface). We will use `surfaceId` instead. We plan to slowly and gracefully retire `reactTag` term entity replacing it with several appropriate entities specific for particular usage, e.g. `viewId` (some id which makes sense for mounting), `surfaceId`, `nodeId` (unique id representing nodes which were cloned from the original one), or `eventTarget`.

Reviewed By: mdvacca

Differential Revision: D9999336

fbshipit-source-id: bbc7303c195b070b8c235c9ca35546d1dc693e98
This commit is contained in:
Valentin Shergin 2018-09-26 10:02:04 -07:00 committed by Facebook Github Bot
parent b91f6d1e93
commit c69313fc52
11 changed files with 146 additions and 66 deletions

View File

@ -39,17 +39,19 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithContextContainer:(std::shared_ptr<void>)contextContatiner;
- (void)registerRootTag:(ReactTag)tag;
- (void)startSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId
moduleName:(NSString *)moduleName
initailProps:(NSDictionary *)initialProps;
- (void)unregisterRootTag:(ReactTag)tag;
- (void)stopSurfaceWithSurfaceId:(facebook::react::SurfaceId)surfaceId;
- (CGSize)measureWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
layoutContext:(facebook::react::LayoutContext)layoutContext
rootTag:(ReactTag)rootTag;
- (void)constraintLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
- (CGSize)measureSurfaceWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
layoutContext:(facebook::react::LayoutContext)layoutContext
rootTag:(ReactTag)rootTag;
surfaceId:(facebook::react::SurfaceId)surfaceId;
- (void)constraintSurfaceLayoutWithLayoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
layoutContext:(facebook::react::LayoutContext)layoutContext
surfaceId:(facebook::react::SurfaceId)surfaceId;
@end

View File

@ -11,6 +11,8 @@
#import <fabric/uimanager/Scheduler.h>
#import <fabric/uimanager/SchedulerDelegate.h>
#import <React/RCTFollyConvert.h>
#import "RCTConversions.h"
using namespace facebook::react;
@ -55,28 +57,34 @@ private:
_scheduler->setDelegate(nullptr);
}
- (void)registerRootTag:(ReactTag)tag
- (void)startSurfaceWithSurfaceId:(SurfaceId)surfaceId
moduleName:(NSString *)moduleName
initailProps:(NSDictionary *)initialProps
{
_scheduler->registerRootTag(tag);
_scheduler->startSurface(
surfaceId,
RCTStringFromNSString(moduleName),
convertIdToFollyDynamic(initialProps)
);
}
- (void)unregisterRootTag:(ReactTag)tag
- (void)stopSurfaceWithSurfaceId:(SurfaceId)surfaceId
{
_scheduler->unregisterRootTag(tag);
_scheduler->stopSurface(surfaceId);
}
- (CGSize)measureWithLayoutConstraints:(LayoutConstraints)layoutConstraints
layoutContext:(LayoutContext)layoutContext
rootTag:(ReactTag)rootTag
{
return RCTCGSizeFromSize(_scheduler->measure(rootTag, layoutConstraints, layoutContext));
}
- (void)constraintLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints
- (CGSize)measureSurfaceWithLayoutConstraints:(LayoutConstraints)layoutConstraints
layoutContext:(LayoutContext)layoutContext
rootTag:(ReactTag)rootTag
surfaceId:(SurfaceId)surfaceId
{
_scheduler->constraintLayout(rootTag, layoutConstraints, layoutContext);
return RCTCGSizeFromSize(_scheduler->measureSurface(surfaceId, layoutConstraints, layoutContext));
}
- (void)constraintSurfaceLayoutWithLayoutConstraints:(LayoutConstraints)layoutConstraints
layoutContext:(LayoutContext)layoutContext
surfaceId:(SurfaceId)surfaceId
{
_scheduler->constraintSurfaceLayout(surfaceId, layoutConstraints, layoutContext);
}
@end

View File

@ -150,9 +150,9 @@ using namespace facebook::react;
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
return [_scheduler measureWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
rootTag:surface.rootTag];
return [_scheduler measureSurfaceWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
surfaceId:surface.rootTag];
}
- (void)setMinimumSize:(CGSize)minimumSize
@ -167,9 +167,9 @@ using namespace facebook::react;
layoutConstraints.minimumSize = RCTSizeFromCGSize(minimumSize);
layoutConstraints.maximumSize = RCTSizeFromCGSize(maximumSize);
[_scheduler constraintLayoutWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
rootTag:surface.rootTag];
[_scheduler constraintSurfaceLayoutWithLayoutConstraints:layoutConstraints
layoutContext:layoutContext
surfaceId:surface.rootTag];
}
- (void)startSurface:(RCTFabricSurface *)surface
@ -177,27 +177,21 @@ using namespace facebook::react;
[_mountingManager.componentViewRegistry dequeueComponentViewWithName:@"Root" tag:surface.rootTag];
[self createSchedulerIfNeeded];
[_scheduler registerRootTag:surface.rootTag];
[_scheduler startSurfaceWithSurfaceId:surface.rootTag
moduleName:surface.moduleName
initailProps:surface.properties];
[self setMinimumSize:surface.minimumSize
maximumSize:surface.maximumSize
surface:surface];
// TODO: Move this down to Scheduler.
NSDictionary *applicationParameters = @{
@"rootTag": @(surface.rootTag),
@"initialProps": surface.properties,
};
[self->_batchedBridge enqueueJSCall:@"AppRegistry" method:@"runApplication" args:@[surface.moduleName, applicationParameters] completion:NULL];
}
- (void)stopSurface:(RCTFabricSurface *)surface
{
// TODO: Move this down to Scheduler.
[_batchedBridge enqueueJSCall:@"ReactFabric" method:@"unmountComponentAtNode" args:@[@(surface.rootTag)] completion:NULL];
[self ensureSchedulerDoesExist];
[_scheduler unregisterRootTag:surface.rootTag];
[_scheduler stopSurfaceWithSurfaceId:surface.rootTag];
UIView<RCTComponentViewProtocol> *rootView = [_mountingManager.componentViewRegistry componentViewByTag:surface.rootTag];
[_mountingManager.componentViewRegistry enqueueComponentViewWithName:@"Root" tag:surface.rootTag componentView:rootView];

View File

@ -22,6 +22,11 @@ namespace react {
using Tag = int32_t;
using InstanceHandle = struct InstanceHandleDummyStruct {} *;
/*
* An id of a running Surface instance that is used to refer to the instance.
*/
using SurfaceId = int32_t;
/*
* `RawProps` represents untyped map with props comes from JavaScript side.
*/

View File

@ -106,7 +106,7 @@ static const std::string componentNameByReactViewName(std::string viewName) {
FabricUIManager::~FabricUIManager() {
(*executor_)([this] {
uninstaller_();
}, EventBeatBasedExecutor::Mode::Synchronous);
});
}
void FabricUIManager::setComponentDescriptorRegistry(const SharedComponentDescriptorRegistry &componentDescriptorRegistry) {
@ -129,6 +129,14 @@ void FabricUIManager::setDispatchEventToTargetFunction(std::function<DispatchEve
dispatchEventToTargetFunction_ = dispatchEventFunction;
}
void FabricUIManager::setStartSurfaceFunction(std::function<StartSurface> startSurfaceFunction) {
startSurfaceFunction_ = startSurfaceFunction;
}
void FabricUIManager::setStopSurfaceFunction(std::function<StopSurface> stopSurfaceFunction) {
stopSurfaceFunction_ = stopSurfaceFunction;
}
void FabricUIManager::dispatchEventToTarget(const EventTarget *eventTarget, const std::string &type, const folly::dynamic &payload) const {
if (eventTarget) {
dispatchEventToTargetFunction_(
@ -146,6 +154,18 @@ void FabricUIManager::dispatchEventToTarget(const EventTarget *eventTarget, cons
}
}
void FabricUIManager::startSurface(SurfaceId surfaceId, const std::string &moduleName, const folly::dynamic &initialProps) const {
(*executor_)([this, surfaceId, moduleName, initialProps] {
startSurfaceFunction_(surfaceId, moduleName, initialProps);
});
}
void FabricUIManager::stopSurface(SurfaceId surfaceId) const {
(*executor_)([this, surfaceId] {
stopSurfaceFunction_(surfaceId);
});
}
SharedShadowNode FabricUIManager::createNode(int tag, std::string viewName, int rootTag, folly::dynamic props, SharedEventTarget eventTarget) const {
isLoggingEnabled && LOG(INFO) << "FabricUIManager::createNode(tag: " << tag << ", name: " << viewName << ", rootTag: " << rootTag << ", props: " << props << ")";

View File

@ -32,6 +32,9 @@ using UIManagerUninstaller = void ();
using DispatchEventToEmptyTargetFunction = void (const EventHandler &eventHandler, const std::string &type, const folly::dynamic &payload);
using DispatchEventToTargetFunction = void (const EventHandler &eventHandler, const EventTarget &eventTarget, const std::string &type, const folly::dynamic &payload);
using StartSurface = void (SurfaceId surfaceId, const std::string &moduleName, const folly::dynamic &initalProps);
using StopSurface = void (SurfaceId surfaceId);
class FabricUIManager {
public:
@ -61,10 +64,14 @@ public:
*/
void setDispatchEventToEmptyTargetFunction(std::function<DispatchEventToEmptyTargetFunction> dispatchEventFunction);
void setDispatchEventToTargetFunction(std::function<DispatchEventToTargetFunction> dispatchEventFunction);
void setStartSurfaceFunction(std::function<StartSurface>);
void setStopSurfaceFunction(std::function<StopSurface>);
#pragma mark - Native-facing Interface
void dispatchEventToTarget(const EventTarget *eventTarget, const std::string &type, const folly::dynamic &payload) const;
void startSurface(SurfaceId surfaceId, const std::string &moduleName, const folly::dynamic &initialProps) const;
void stopSurface(SurfaceId surfaceId) const;
#pragma mark - JavaScript/React-facing Interface
@ -86,12 +93,13 @@ public:
void registerEventHandler(UniqueEventHandler eventHandler) const;
private:
SharedComponentDescriptorRegistry componentDescriptorRegistry_;
UIManagerDelegate *delegate_;
mutable UniqueEventHandler eventHandler_;
std::function<DispatchEventToEmptyTargetFunction> dispatchEventToEmptyTargetFunction_;
std::function<DispatchEventToTargetFunction> dispatchEventToTargetFunction_;
std::function<StartSurface> startSurfaceFunction_;
std::function<StopSurface> stopSurfaceFunction_;
std::unique_ptr<EventBeatBasedExecutor> executor_;
std::function<UIManagerInstaller> installer_;

View File

@ -51,14 +51,30 @@ Scheduler::~Scheduler() {
uiManager_->setDelegate(nullptr);
}
void Scheduler::registerRootTag(Tag rootTag) {
auto shadowTree = std::make_unique<ShadowTree>(rootTag);
void Scheduler::startSurface(
SurfaceId surfaceId,
const std::string &moduleName,
const folly::dynamic &initialProps
) const {
std::lock_guard<std::mutex> lock(mutex_);
auto shadowTree = std::make_unique<ShadowTree>(surfaceId);
shadowTree->setDelegate(this);
shadowTreeRegistry_.emplace(rootTag, std::move(shadowTree));
shadowTreeRegistry_.emplace(surfaceId, std::move(shadowTree));
#ifndef ANDROID
uiManager_->startSurface(surfaceId, moduleName, initialProps);
#endif
}
void Scheduler::unregisterRootTag(Tag rootTag) {
const auto &iterator = shadowTreeRegistry_.find(rootTag);
void Scheduler::stopSurface(SurfaceId surfaceId) const {
std::lock_guard<std::mutex> lock(mutex_);
#ifndef ANDROID
uiManager_->stopSurface(surfaceId);
#endif
const auto &iterator = shadowTreeRegistry_.find(surfaceId);
const auto &shadowTree = iterator->second;
assert(shadowTree);
// As part of stopping the Surface, we have to commit an empty tree.
@ -67,14 +83,24 @@ void Scheduler::unregisterRootTag(Tag rootTag) {
shadowTreeRegistry_.erase(iterator);
}
Size Scheduler::measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const {
const auto &shadowTree = shadowTreeRegistry_.at(rootTag);
Size Scheduler::measureSurface(
SurfaceId surfaceId,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext
) const {
std::lock_guard<std::mutex> lock(mutex_);
const auto &shadowTree = shadowTreeRegistry_.at(surfaceId);
assert(shadowTree);
return shadowTree->measure(layoutConstraints, layoutContext);
}
void Scheduler::constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) {
const auto &shadowTree = shadowTreeRegistry_.at(rootTag);
void Scheduler::constraintSurfaceLayout(
SurfaceId surfaceId,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext
) const {
std::lock_guard<std::mutex> lock(mutex_);
const auto &shadowTree = shadowTreeRegistry_.at(surfaceId);
assert(shadowTree);
return shadowTree->constraintLayout(layoutConstraints, layoutContext);
}
@ -91,7 +117,7 @@ SchedulerDelegate *Scheduler::getDelegate() const {
#pragma mark - ShadowTreeDelegate
void Scheduler::shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) {
void Scheduler::shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) const {
if (delegate_) {
delegate_->schedulerDidFinishTransaction(shadowTree.getRootTag(), mutations);
}
@ -100,6 +126,8 @@ void Scheduler::shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowVi
#pragma mark - UIManagerDelegate
void Scheduler::uiManagerDidFinishTransaction(Tag rootTag, const SharedShadowNodeUnsharedList &rootChildNodes) {
std::lock_guard<std::mutex> lock(mutex_);
const auto iterator = shadowTreeRegistry_.find(rootTag);
if (iterator == shadowTreeRegistry_.end()) {
// This might happen during surface unmounting/deallocation process

View File

@ -6,6 +6,7 @@
#pragma once
#include <memory>
#include <mutex>
#include <fabric/core/ComponentDescriptor.h>
#include <fabric/core/LayoutConstraints.h>
@ -28,17 +29,30 @@ class Scheduler final:
public ShadowTreeDelegate {
public:
Scheduler(const SharedContextContainer &contextContainer);
~Scheduler();
#pragma mark - Shadow Tree Management
#pragma mark - Surface Management
void registerRootTag(Tag rootTag);
void unregisterRootTag(Tag rootTag);
void startSurface(
SurfaceId surfaceId,
const std::string &moduleName,
const folly::dynamic &initialProps
) const;
Size measure(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext) const;
void constraintLayout(const Tag &rootTag, const LayoutConstraints &layoutConstraints, const LayoutContext &layoutContext);
void stopSurface(SurfaceId surfaceId) const;
Size measureSurface(
SurfaceId surfaceId,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext
) const;
void constraintSurfaceLayout(
SurfaceId surfaceId,
const LayoutConstraints &layoutConstraints,
const LayoutContext &layoutContext
) const;
#pragma mark - Delegate
@ -57,7 +71,7 @@ public:
#pragma mark - ShadowTreeDelegate
void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) override;
void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) const override;
#pragma mark - Deprecated
@ -69,7 +83,8 @@ public:
private:
SchedulerDelegate *delegate_;
std::shared_ptr<FabricUIManager> uiManager_;
std::unordered_map<Tag, std::unique_ptr<ShadowTree>> shadowTreeRegistry_;
mutable std::mutex mutex_;
mutable std::unordered_map<SurfaceId, std::unique_ptr<ShadowTree>> shadowTreeRegistry_; // Protected by `mutex_`.
SharedEventDispatcher eventDispatcher_;
SharedContextContainer contextContainer_;
};

View File

@ -165,11 +165,11 @@ void ShadowTree::toggleEventEmitters(const ShadowViewMutationList &mutations) {
#pragma mark - Delegate
void ShadowTree::setDelegate(ShadowTreeDelegate *delegate) {
void ShadowTree::setDelegate(ShadowTreeDelegate const *delegate) {
delegate_ = delegate;
}
ShadowTreeDelegate *ShadowTree::getDelegate() const {
ShadowTreeDelegate const *ShadowTree::getDelegate() const {
return delegate_;
}

View File

@ -68,8 +68,8 @@ public:
* The delegate is stored as a raw pointer, so the owner must null
* the pointer before being destroyed.
*/
void setDelegate(ShadowTreeDelegate *delegate);
ShadowTreeDelegate *getDelegate() const;
void setDelegate(ShadowTreeDelegate const *delegate);
ShadowTreeDelegate const *getDelegate() const;
private:
@ -85,7 +85,7 @@ private:
const Tag rootTag_;
SharedRootShadowNode rootShadowNode_;
ShadowTreeDelegate *delegate_;
ShadowTreeDelegate const *delegate_;
mutable std::mutex commitMutex_;
};

View File

@ -21,7 +21,7 @@ public:
/*
* Called right after Shadow Tree commit a new state of the the tree.
*/
virtual void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) = 0;
virtual void shadowTreeDidCommit(const ShadowTree &shadowTree, const ShadowViewMutationList &mutations) const = 0;
virtual ~ShadowTreeDelegate() noexcept = default;
};