LayoutState runAndGet()

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;
      }
    }