Scheduler.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. /*
  2. * Copyright (c) Facebook, Inc. and its affiliates.
  3. *
  4. * This source code is licensed under the MIT license found in the
  5. * LICENSE file in the root directory of this source tree.
  6. */
  7. #include "Scheduler.h"
  8. #include <glog/logging.h>
  9. #include <jsi/jsi.h>
  10. #include <react/core/LayoutContext.h>
  11. #include <react/debug/SystraceSection.h>
  12. #include <react/uimanager/ComponentDescriptorRegistry.h>
  13. #include <react/uimanager/UIManager.h>
  14. #include <react/uimanager/UIManagerBinding.h>
  15. #include <react/uimanager/UITemplateProcessor.h>
  16. namespace facebook {
  17. namespace react {
  18. Scheduler::Scheduler(
  19. SchedulerToolbox schedulerToolbox,
  20. SchedulerDelegate *delegate) {
  21. runtimeExecutor_ = schedulerToolbox.runtimeExecutor;
  22. reactNativeConfig_ =
  23. schedulerToolbox.contextContainer
  24. ->at<std::shared_ptr<const ReactNativeConfig>>("ReactNativeConfig");
  25. auto uiManager = std::make_shared<UIManager>();
  26. auto eventOwnerBox = std::make_shared<EventBeat::OwnerBox>();
  27. auto eventPipe = [uiManager](
  28. jsi::Runtime &runtime,
  29. const EventTarget *eventTarget,
  30. const std::string &type,
  31. const ValueFactory &payloadFactory) {
  32. uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) {
  33. uiManagerBinding.dispatchEvent(
  34. runtime, eventTarget, type, payloadFactory);
  35. });
  36. };
  37. auto statePipe = [uiManager](StateUpdate const &stateUpdate) {
  38. uiManager->updateState(stateUpdate);
  39. };
  40. eventDispatcher_ = std::make_shared<EventDispatcher>(
  41. eventPipe,
  42. statePipe,
  43. schedulerToolbox.synchronousEventBeatFactory,
  44. schedulerToolbox.asynchronousEventBeatFactory,
  45. eventOwnerBox);
  46. eventOwnerBox->owner = eventDispatcher_;
  47. componentDescriptorRegistry_ = schedulerToolbox.componentRegistryFactory(
  48. eventDispatcher_, schedulerToolbox.contextContainer);
  49. rootComponentDescriptor_ = std::make_unique<const RootComponentDescriptor>(
  50. ComponentDescriptorParameters{eventDispatcher_, nullptr, nullptr});
  51. uiManager->setDelegate(this);
  52. uiManager->setComponentDescriptorRegistry(componentDescriptorRegistry_);
  53. runtimeExecutor_([=](jsi::Runtime &runtime) {
  54. auto uiManagerBinding = UIManagerBinding::createAndInstallIfNeeded(runtime);
  55. uiManagerBinding->attach(uiManager);
  56. });
  57. auto componentDescriptorRegistryKey =
  58. "ComponentDescriptorRegistry_DO_NOT_USE_PRETTY_PLEASE";
  59. schedulerToolbox.contextContainer->erase(componentDescriptorRegistryKey);
  60. schedulerToolbox.contextContainer->insert(
  61. componentDescriptorRegistryKey,
  62. std::weak_ptr<ComponentDescriptorRegistry const>(
  63. componentDescriptorRegistry_));
  64. delegate_ = delegate;
  65. uiManager_ = uiManager;
  66. }
  67. Scheduler::~Scheduler() {
  68. LOG(WARNING) << "Scheduler::~Scheduler() was called (address: " << this
  69. << ").";
  70. // All Surfaces must be explicitly stopped before destroying `Scheduler`.
  71. // The idea is that `UIManager` is allowed to call `Scheduler` only if the
  72. // corresponding `ShadowTree` instance exists.
  73. // The thread-safety of this operation is guaranteed by this requirement.
  74. uiManager_->setDelegate(nullptr);
  75. // Then, let's verify that the requirement was satisfied.
  76. auto surfaceIds = std::vector<SurfaceId>{};
  77. uiManager_->getShadowTreeRegistry().enumerate(
  78. [&](ShadowTree const &shadowTree, bool &stop) {
  79. surfaceIds.push_back(shadowTree.getSurfaceId());
  80. });
  81. assert(
  82. surfaceIds.size() == 0 &&
  83. "Scheduler was destroyed with outstanding Surfaces.");
  84. if (surfaceIds.size() == 0) {
  85. return;
  86. }
  87. LOG(ERROR) << "Scheduler was destroyed with outstanding Surfaces.";
  88. // If we are here, that means assert didn't fire which indicates that we in
  89. // production.
  90. // Now we have still-running surfaces, which is no good, no good.
  91. // That's indeed a sign of a severe issue on the application layer.
  92. // At this point, we don't have much to lose, so we are trying to unmount all
  93. // outstanding `ShadowTree`s to prevent all stored JSI entities from
  94. // overliving the `Scheduler`. (Unmounting `ShadowNode`s disables
  95. // `EventEmitter`s which destroys JSI objects.)
  96. for (auto surfaceId : surfaceIds) {
  97. uiManager_->getShadowTreeRegistry().visit(
  98. surfaceId,
  99. [](ShadowTree const &shadowTree) { shadowTree.commitEmptyTree(); });
  100. }
  101. }
  102. void Scheduler::startSurface(
  103. SurfaceId surfaceId,
  104. const std::string &moduleName,
  105. const folly::dynamic &initialProps,
  106. const LayoutConstraints &layoutConstraints,
  107. const LayoutContext &layoutContext) const {
  108. SystraceSection s("Scheduler::startSurface");
  109. auto shadowTree = std::make_unique<ShadowTree>(
  110. surfaceId,
  111. layoutConstraints,
  112. layoutContext,
  113. *rootComponentDescriptor_,
  114. *uiManager_);
  115. auto uiManager = uiManager_;
  116. uiManager->getShadowTreeRegistry().add(std::move(shadowTree));
  117. runtimeExecutor_([=](jsi::Runtime &runtime) {
  118. uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) {
  119. uiManagerBinding.startSurface(
  120. runtime, surfaceId, moduleName, initialProps);
  121. });
  122. });
  123. }
  124. void Scheduler::renderTemplateToSurface(
  125. SurfaceId surfaceId,
  126. const std::string &uiTemplate) {
  127. SystraceSection s("Scheduler::renderTemplateToSurface");
  128. try {
  129. if (uiTemplate.size() == 0) {
  130. return;
  131. }
  132. NativeModuleRegistry nMR;
  133. auto tree = UITemplateProcessor::buildShadowTree(
  134. uiTemplate,
  135. surfaceId,
  136. folly::dynamic::object(),
  137. *componentDescriptorRegistry_,
  138. nMR,
  139. reactNativeConfig_);
  140. uiManager_->getShadowTreeRegistry().visit(
  141. surfaceId, [=](const ShadowTree &shadowTree) {
  142. return shadowTree.tryCommit(
  143. [&](RootShadowNode::Shared const &oldRootShadowNode) {
  144. return std::make_shared<RootShadowNode>(
  145. *oldRootShadowNode,
  146. ShadowNodeFragment{
  147. /* .props = */ ShadowNodeFragment::propsPlaceholder(),
  148. /* .children = */
  149. std::make_shared<SharedShadowNodeList>(
  150. SharedShadowNodeList{tree}),
  151. });
  152. });
  153. });
  154. } catch (const std::exception &e) {
  155. LOG(ERROR) << " >>>> EXCEPTION <<< rendering uiTemplate in "
  156. << "Scheduler::renderTemplateToSurface: " << e.what();
  157. }
  158. }
  159. void Scheduler::stopSurface(SurfaceId surfaceId) const {
  160. SystraceSection s("Scheduler::stopSurface");
  161. // Note, we have to do in inside `visit` function while the Shadow Tree
  162. // is still being registered.
  163. uiManager_->getShadowTreeRegistry().visit(
  164. surfaceId, [](ShadowTree const &shadowTree) {
  165. // As part of stopping a Surface, we need to properly destroy all
  166. // mounted views, so we need to commit an empty tree to trigger all
  167. // side-effects that will perform that.
  168. shadowTree.commitEmptyTree();
  169. });
  170. // Waiting for all concurrent commits to be finished and unregistering the
  171. // `ShadowTree`.
  172. uiManager_->getShadowTreeRegistry().remove(surfaceId);
  173. // We execute JavaScript/React part of the process at the very end to minimize
  174. // any visible side-effects of stopping the Surface. Any possible commits from
  175. // the JavaScript side will not be able to reference a `ShadowTree` and will
  176. // fail silently.
  177. auto uiManager = uiManager_;
  178. runtimeExecutor_([=](jsi::Runtime &runtime) {
  179. uiManager->visitBinding([&](UIManagerBinding const &uiManagerBinding) {
  180. uiManagerBinding.stopSurface(runtime, surfaceId);
  181. });
  182. });
  183. }
  184. Size Scheduler::measureSurface(
  185. SurfaceId surfaceId,
  186. const LayoutConstraints &layoutConstraints,
  187. const LayoutContext &layoutContext) const {
  188. SystraceSection s("Scheduler::measureSurface");
  189. Size size;
  190. uiManager_->getShadowTreeRegistry().visit(
  191. surfaceId, [&](const ShadowTree &shadowTree) {
  192. shadowTree.tryCommit(
  193. [&](RootShadowNode::Shared const &oldRootShadowNode) {
  194. auto rootShadowNode =
  195. oldRootShadowNode->clone(layoutConstraints, layoutContext);
  196. rootShadowNode->layoutIfNeeded();
  197. size = rootShadowNode->getLayoutMetrics().frame.size;
  198. return nullptr;
  199. });
  200. });
  201. return size;
  202. }
  203. MountingCoordinator::Shared Scheduler::findMountingCoordinator(
  204. SurfaceId surfaceId) const {
  205. MountingCoordinator::Shared mountingCoordinator = nullptr;
  206. uiManager_->getShadowTreeRegistry().visit(
  207. surfaceId, [&](const ShadowTree &shadowTree) {
  208. mountingCoordinator = shadowTree.getMountingCoordinator();
  209. });
  210. return mountingCoordinator;
  211. }
  212. void Scheduler::constraintSurfaceLayout(
  213. SurfaceId surfaceId,
  214. const LayoutConstraints &layoutConstraints,
  215. const LayoutContext &layoutContext) const {
  216. SystraceSection s("Scheduler::constraintSurfaceLayout");
  217. uiManager_->getShadowTreeRegistry().visit(
  218. surfaceId, [&](ShadowTree const &shadowTree) {
  219. shadowTree.commit([&](RootShadowNode::Shared const &oldRootShadowNode) {
  220. return oldRootShadowNode->clone(layoutConstraints, layoutContext);
  221. });
  222. });
  223. }
  224. ComponentDescriptor const *
  225. Scheduler::findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(
  226. ComponentHandle handle) const {
  227. return componentDescriptorRegistry_
  228. ->findComponentDescriptorByHandle_DO_NOT_USE_THIS_IS_BROKEN(handle);
  229. }
  230. #pragma mark - Delegate
  231. void Scheduler::setDelegate(SchedulerDelegate *delegate) {
  232. delegate_ = delegate;
  233. }
  234. SchedulerDelegate *Scheduler::getDelegate() const {
  235. return delegate_;
  236. }
  237. #pragma mark - UIManagerDelegate
  238. void Scheduler::uiManagerDidFinishTransaction(
  239. MountingCoordinator::Shared const &mountingCoordinator) {
  240. SystraceSection s("Scheduler::uiManagerDidFinishTransaction");
  241. if (delegate_) {
  242. delegate_->schedulerDidFinishTransaction(mountingCoordinator);
  243. }
  244. }
  245. void Scheduler::uiManagerDidCreateShadowNode(
  246. const ShadowNode::Shared &shadowNode) {
  247. SystraceSection s("Scheduler::uiManagerDidCreateShadowNode");
  248. if (delegate_) {
  249. auto shadowView = ShadowView(*shadowNode);
  250. delegate_->schedulerDidRequestPreliminaryViewAllocation(
  251. shadowNode->getSurfaceId(), shadowView);
  252. }
  253. }
  254. void Scheduler::uiManagerDidDispatchCommand(
  255. const ShadowNode::Shared &shadowNode,
  256. std::string const &commandName,
  257. folly::dynamic const args) {
  258. SystraceSection s("Scheduler::uiManagerDispatchCommand");
  259. if (delegate_) {
  260. auto shadowView = ShadowView(*shadowNode);
  261. delegate_->schedulerDidDispatchCommand(shadowView, commandName, args);
  262. }
  263. }
  264. /*
  265. * Set JS responder for a view
  266. */
  267. void Scheduler::uiManagerDidSetJSResponder(
  268. SurfaceId surfaceId,
  269. const ShadowNode::Shared &shadowNode,
  270. bool blockNativeResponder) {
  271. if (delegate_) {
  272. // TODO: the first shadowView paramenter, should be the first parent that
  273. // is non virtual.
  274. auto shadowView = ShadowView(*shadowNode);
  275. delegate_->schedulerDidSetJSResponder(
  276. surfaceId, shadowView, shadowView, blockNativeResponder);
  277. }
  278. }
  279. /*
  280. * Clear the JSResponder for a view
  281. */
  282. void Scheduler::uiManagerDidClearJSResponder() {
  283. if (delegate_) {
  284. delegate_->schedulerDidClearJSResponder();
  285. }
  286. }
  287. } // namespace react
  288. } // namespace facebook