in litho-core/src/main/java/com/facebook/litho/ComponentTree.java [2983:3118]
LayoutState runAndGet(@CalculateLayoutSource final int source) {
if (runningThreadId.compareAndSet(-1, Process.myTid())) {
futureTask.run();
}
final int runningThreadId = this.runningThreadId.get();
final boolean notRunningOnMyThread = runningThreadId != Process.myTid();
final int originalThreadPriority;
final boolean didRaiseThreadPriority;
final boolean shouldWaitForResult = !futureTask.isDone() && notRunningOnMyThread;
if (shouldWaitForResult && !isMainThread() && !isFromSyncLayout(source)) {
return null;
}
if (isMainThread() && shouldWaitForResult) {
// This means the UI thread is about to be blocked by the bg thread. Instead of waiting,
// the bg task is interrupted.
if (mMoveLayoutsBetweenThreads && !isFromSyncLayout) {
interrupt();
interruptToken =
WorkContinuationInstrumenter.onAskForWorkToContinue("interruptCalculateLayout");
}
originalThreadPriority =
ThreadUtils.tryRaiseThreadPriority(runningThreadId, Process.THREAD_PRIORITY_DISPLAY);
didRaiseThreadPriority = true;
} else {
originalThreadPriority = THREAD_PRIORITY_DEFAULT;
didRaiseThreadPriority = false;
}
LayoutState result;
PerfEvent logFutureTaskGetWaiting = null;
final ComponentsLogger logger = getContextLogger();
final boolean shouldTrace = notRunningOnMyThread && ComponentsSystrace.isTracing();
try {
if (shouldTrace) {
ComponentsSystrace.beginSectionWithArgs("LayoutStateFuture.get")
.arg("treeId", ComponentTree.this.mId)
.arg("root", root.getSimpleName())
.arg("runningThreadId", runningThreadId)
.flush();
ComponentsSystrace.beginSectionWithArgs("LayoutStateFuture.wait")
.arg("treeId", ComponentTree.this.mId)
.arg("root", root.getSimpleName())
.arg("runningThreadId", runningThreadId)
.flush();
}
logFutureTaskGetWaiting =
logger != null
? LogTreePopulator.populatePerfEventFromLogger(
mContext,
logger,
logger.newPerformanceEvent(mContext, EVENT_LAYOUT_STATE_FUTURE_GET_WAIT))
: null;
result = futureTask.get();
if (shouldTrace) {
ComponentsSystrace.endSection();
}
if (logFutureTaskGetWaiting != null) {
logFutureTaskGetWaiting.markerPoint("FUTURE_TASK_END");
}
if (didRaiseThreadPriority) {
// Reset the running thread's priority after we're unblocked.
try {
Process.setThreadPriority(runningThreadId, originalThreadPriority);
} catch (IllegalArgumentException | SecurityException ignored) {
}
}
if (interruptRequested && result.isPartialLayoutState()) {
if (ThreadUtils.isMainThread()) {
// This means that the bg task was interrupted and it returned a partially resolved
// InternalNode. We need to finish computing this LayoutState.
final Object token =
onBeginWorkContinuation("continuePartialLayoutState", continuationToken);
continuationToken = null;
try {
result = resolvePartialInternalNodeAndCalculateLayout(result);
} catch (Throwable th) {
markFailure(token, th);
throw th;
} finally {
onEndWorkContinuation(token);
}
} else {
// This means that the bg task was interrupted and the UI thread will pick up the rest
// of
// the work. No need to return a LayoutState.
result = null;
continuationToken =
onOfferWorkForContinuation("offerPartialLayoutState", interruptToken);
interruptToken = null;
}
}
} catch (ExecutionException | InterruptedException | CancellationException e) {
if (shouldTrace) {
ComponentsSystrace.endSection();
}
final Throwable cause = e.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else {
throw new RuntimeException(e.getMessage(), e);
}
} finally {
if (shouldTrace) {
ComponentsSystrace.endSection();
}
if (logFutureTaskGetWaiting != null) {
logFutureTaskGetWaiting.markerAnnotate(
PARAM_LAYOUT_FUTURE_WAIT_FOR_RESULT, shouldWaitForResult);
logFutureTaskGetWaiting.markerAnnotate(PARAM_IS_MAIN_THREAD, isMainThread());
logger.logPerfEvent(logFutureTaskGetWaiting);
}
}
if (result == null) {
return null;
}
synchronized (LayoutStateFuture.this) {
if (released) {
return null;
}
return result;
}
}