Skip to content

Commit 57c7f89

Browse files
Pull the coordinator that reported a transaction, as iOS does, in the Android pull model
With enableMountingCoordinatorPullModelAndroid, a commit tells Java only its surface id, and the UI thread looked the surface's MountingCoordinator up in the binding's surface registry. Commits a surface makes while it starts or stops, when it is not in the registry, were not mounted, and the legacy stopSurface(int) deadlocked on the registry lock. The commit now keeps the MountingCoordinator that reported it until the UI thread pulls, and pullAndExecuteTransaction pulls from it, as iOS pulls from the coordinator its main-queue block captures. If a surface is restarted with the same id while the previous surface's commit waits to be pulled, the latest coordinator wins and a warning is logged. Java does not mount such a restarted surface anyway (MountingManager.startSurface keeps the stopped one). The registry and the push model are unchanged.
1 parent 4a31469 commit 57c7f89

2 files changed

Lines changed: 23 additions & 23 deletions

File tree

‎packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.cpp‎

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -125,29 +125,12 @@ void FabricUIManagerBinding::pullAndExecuteTransaction(SurfaceId surfaceId) {
125125

126126
std::shared_ptr<const MountingCoordinator> mountingCoordinator;
127127
{
128-
std::shared_lock lock(surfaceHandlerRegistryMutex_);
129-
auto iterator = surfaceHandlerRegistry_.find(surfaceId);
130-
if (iterator == surfaceHandlerRegistry_.end()) {
128+
std::scoped_lock lock(pullableMountingCoordinatorsMutex_);
129+
auto pullable = pullableMountingCoordinators_.extract(surfaceId);
130+
if (pullable.empty()) {
131131
return;
132132
}
133-
const auto* surfaceHandler = std::get_if<SurfaceHandler>(&iterator->second);
134-
jni::local_ref<SurfaceHandlerBinding::jhybridobject> javaSurfaceHandler;
135-
if (surfaceHandler == nullptr) {
136-
javaSurfaceHandler =
137-
std::get<jni::weak_ref<SurfaceHandlerBinding::jhybridobject>>(
138-
iterator->second)
139-
.lockLocal();
140-
if (javaSurfaceHandler) {
141-
surfaceHandler = &javaSurfaceHandler->cthis()->getSurfaceHandler();
142-
}
143-
}
144-
if (surfaceHandler != nullptr) {
145-
mountingCoordinator = surfaceHandler->getMountingCoordinator();
146-
}
147-
}
148-
149-
if (mountingCoordinator == nullptr) {
150-
return;
133+
mountingCoordinator = std::move(pullable.mapped());
151134
}
152135

153136
auto mountingManager = getMountingManager("pullAndExecuteTransaction");
@@ -732,8 +715,19 @@ void FabricUIManagerBinding::schedulerShouldRenderTransactions(
732715
// commit thread). Just notify Java that a transaction is available; the UI
733716
// thread calls back into `pullAndExecuteTransaction` at its next mount
734717
// dispatch.
735-
mountingManager->onTransactionAvailable(
736-
mountingCoordinator->getSurfaceId());
718+
auto surfaceId = mountingCoordinator->getSurfaceId();
719+
{
720+
std::scoped_lock lock(pullableMountingCoordinatorsMutex_);
721+
auto& pullable = pullableMountingCoordinators_[surfaceId];
722+
if (pullable != nullptr && pullable != mountingCoordinator) {
723+
LOG(WARNING)
724+
<< "FabricUIManagerBinding::schedulerShouldRenderTransactions: "
725+
<< "surface " << surfaceId
726+
<< " was restarted while the previous surface's commit waits to be pulled";
727+
}
728+
pullable = mountingCoordinator;
729+
}
730+
mountingManager->onTransactionAvailable(surfaceId);
737731
} else if (ReactNativeFeatureFlags::
738732
enableAccumulatedUpdatesInRawPropsAndroid()) {
739733
auto mountingTransaction = mountingCoordinator->pullTransaction(

‎packages/react-native/ReactAndroid/src/main/jni/react/fabric/FabricUIManagerBinding.h‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ class FabricUIManagerBinding : public jni::HybridClass<FabricUIManagerBinding>,
167167
std::mutex pendingTransactionsMutex_;
168168
std::vector<MountingTransaction> pendingTransactions_;
169169

170+
// Pull model: keeps the coordinator that reported a surface's commit alive
171+
// until the UI thread handles the pull, as iOS does by capturing it in the
172+
// block it dispatches to the main queue. Java only gets the surface id.
173+
std::mutex pullableMountingCoordinatorsMutex_;
174+
std::unordered_map<SurfaceId, std::shared_ptr<const MountingCoordinator>> pullableMountingCoordinators_;
175+
170176
float pointScaleFactor_ = 1;
171177

172178
bool enableFabricLogs_{false};

0 commit comments

Comments
 (0)