in litho-rendercore/src/main/java/com/facebook/rendercore/MountState.java [97:248]
public void mount(RenderTree renderTree) {
if (renderTree == null) {
throw new IllegalStateException("Trying to mount a null RenderTreeNode");
}
if (mIsMounting) {
throw new IllegalStateException("Trying to mount while already mounting!");
}
final RenderTree previousRenderTree = mRenderTree;
if (!updateRenderTree(renderTree)) {
return;
}
final boolean isTracing = RenderCoreSystrace.isEnabled();
if (isTracing) {
RenderCoreSystrace.beginSection("MountState.mount");
RenderCoreSystrace.beginSection("RenderCoreExtension.beforeMount");
}
mIsMounting = true;
RenderCoreExtension.beforeMount(mRootHost, mMountDelegate, mRenderTree.getExtensionResults());
if (isTracing) {
RenderCoreSystrace.endSection();
RenderCoreSystrace.beginSection("MountState.prepareMount");
}
prepareMount(previousRenderTree);
if (isTracing) {
RenderCoreSystrace.endSection();
}
// TODO: Remove this additional logging when root cause of crash in mountRenderUnit is found.
// We only want to collect logs when we're not ensuring the parent is mounted. When false,
// we will throw an exception that contains these logs. The StringBuilder is not needed when
// mEnsureParentMount is true.
@Nullable final StringBuilder mountLoopLogBuilder;
if (!mEnsureParentMounted) {
mountLoopLogBuilder = new StringBuilder();
mountLoopLogBuilder.append("Start of mount loop log:\n");
} else {
mountLoopLogBuilder = null;
}
// Starting from 1 as the RenderTreeNode in position 0 always represents the root which is
// handled in prepareMount()
for (int i = 1, size = renderTree.getMountableOutputCount(); i < size; i++) {
final RenderTreeNode renderTreeNode = renderTree.getRenderTreeNodeAtIndex(i);
final boolean isMountable = isMountable(renderTreeNode, i);
final MountItem currentMountItem =
mIdToMountedItemMap.get(renderTreeNode.getRenderUnit().getId());
boolean isMounted = currentMountItem != null;
// There is a bug (T99579422) happening where we try to incorrectly update an already mounted
// render unit.
// TODO: T101249557
if (isMounted) {
final RenderUnit currentRenderUnit = currentMountItem.getRenderUnit();
boolean needsRecovery = false;
// The old render unit we try to update is the root host which should not be updated (that's
// why we start from index 1).
if (currentRenderUnit.getId() != renderTreeNode.getRenderUnit().getId()) {
needsRecovery = true;
ErrorReporter.getInstance()
.report(
LogLevel.ERROR,
TAG,
"The current render unit id does not match the new one. "
+ " index: "
+ i
+ " mountableOutputCounts: "
+ renderTree.getMountableOutputCount()
+ " currentRenderUnitId: "
+ currentRenderUnit.getId()
+ " newRenderUnitId: "
+ renderTreeNode.getRenderUnit().getId(),
null,
0,
null);
}
// The new render unit is not the same type as the old one.
if (!currentRenderUnit
.getRenderContentType()
.equals(renderTreeNode.getRenderUnit().getRenderContentType())) {
needsRecovery = true;
ErrorReporter.getInstance()
.report(
LogLevel.ERROR,
TAG,
"Trying to update a MountItem with different ContentType. "
+ "index: "
+ i
+ " currentRenderUnitId: "
+ currentRenderUnit.getId()
+ " newRenderUnitId: "
+ renderTreeNode.getRenderUnit().getId()
+ " currentRenderUnitContentType: "
+ currentRenderUnit.getRenderContentType()
+ " newRenderUnitContentType: "
+ renderTreeNode.getRenderUnit().getRenderContentType(),
null,
0,
null);
}
if (needsRecovery) {
recreateMountedItemMap(previousRenderTree);
// reset the loop to start over.
i = 1;
continue;
}
}
if (!mEnsureParentMounted) {
mountLoopLogBuilder.append(
String.format(
Locale.US,
"Processing index %d: isMountable = %b, isMounted = %b\n",
i,
isMountable,
isMounted));
}
if (!isMountable) {
if (isMounted) {
unmountItemRecursively(currentMountItem.getRenderTreeNode().getRenderUnit().getId());
}
} else if (!isMounted) {
mountRenderUnit(renderTreeNode, mountLoopLogBuilder);
} else {
updateMountItemIfNeeded(mMountDelegate, mContext, renderTreeNode, currentMountItem);
}
}
mNeedsRemount = false;
mIsMounting = false;
if (isTracing) {
RenderCoreSystrace.endSection();
RenderCoreSystrace.beginSection("RenderCoreExtension.afterMount");
}
RenderCoreExtension.afterMount(mMountDelegate);
if (isTracing) {
RenderCoreSystrace.endSection();
}
}