Gradle 源碼分析(五)

1. 寫在前面

Gradle源碼分析(四)一文中,我們分析了Gradle構(gòu)建流程的 TaskGraph 階段,這里將分析 RunTasks 階段(gradle 源碼版本為 5.6.4)。

2. RunTasks

2.1 整體實(shí)現(xiàn)

這里我整理了 RunTasks 階段的一些主要操作,并繪制了調(diào)用鏈的時(shí)序圖。如果對(duì)源碼不感興趣的同學(xué)只需要看這一部分的內(nèi)容即可。

2.1.1 時(shí)序圖

RunTasks時(shí)序圖.png

2.1.2 主要操作

RunTasks 階段 Gradle 主要做了下面這些事情。

  1. 處理 --dry-run;
  2. 回調(diào)傳給 whenReady() 的閉包;
  3. 創(chuàng)建線程和 ExecutorWorker
  4. 執(zhí)行 task 前的預(yù)處理;
  5. 調(diào)用 TaskActionListenerbeforeAction(),遍歷 TaskAction ,并調(diào)用其 execute(),調(diào)用 TaskActionListenerafterAction()

2.2 源碼分析

2.2.1 處理 --dry-run

RunTasks 的過(guò)程發(fā)生在 DefaultGradleLauncherrunWork() 中,先來(lái)看看其源碼。

// DefaultGradleLauncher.java
private void runWork() {
    // ...
    List<Throwable> taskFailures = new ArrayList<Throwable>();
    buildExecuter.execute(gradle, taskFailures);
    // ...
}

這里調(diào)用了 buildExecuterexecute(),而 buildExecuter 是通過(guò)反射調(diào)用GradleScopeServicescreateBuildExecuter() 生成的。

// GradleScopeServices.java
BuildWorkExecutor createBuildExecuter(StyledTextOutputFactory textOutputFactory, IncludedBuildControllers includedBuildControllers, BuildOperationExecutor buildOperationExecutor) {
    return new BuildOperationFiringBuildWorkerExecutor(
        new IncludedBuildLifecycleBuildWorkExecutor(
            new DefaultBuildWorkExecutor(
                // 記住這兩個(gè) BuildExecutionAction
                asList(new DryRunBuildExecutionAction(textOutputFactory),
                    new SelectedTaskExecutionAction())),
            includedBuildControllers),
        buildOperationExecutor);
}

這里有兩個(gè)比較重要的 BuildExecutionAction,暫時(shí)先記住它們:

  • DryRunBuildExecutionAction
  • SelectedTaskExecutionAction

上面的代碼最終會(huì)調(diào)用到 DefaultBuildWorkExecutorexecute(),來(lái)看看其源碼。

// DefaultBuildWorkExecutor.java
public void execute(GradleInternal gradle, Collection<? super Throwable> failures) {
    execute(gradle, 0, failures);
}

// 和 TaskGraph 階段的 BuildConfigurationAction 執(zhí)行差不多
private void execute(final GradleInternal gradle, final int index, final Collection<? super Throwable> taskFailures) {
    if (index >= executionActions.size()) {
        return;
    }
    executionActions.get(index).execute(new BuildExecutionContext() {
        @Override
        public GradleInternal getGradle() {
            return gradle;
        }

        @Override
        public void proceed() {
            execute(gradle, index + 1, taskFailures);
        }

    }, taskFailures);
}

這里遍歷執(zhí)行了傳給 DefaultBuildWorkExecutor 構(gòu)造器的 BuildConfigurationActionexecute(),也就是前面提到的 DryRunBuildExecutionActionSelectedTaskExecutionAction。來(lái)看看 DryRunBuildExecutionActionexecute() 做了什么。

// DryRunBuildExecutionAction.java
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
    GradleInternal gradle = context.getGradle();
    // 判斷是否有指定參數(shù) -m 或者 --dry-run
    if (gradle.getStartParameter().isDryRun()) {
        for (Task task : gradle.getTaskGraph().getAllTasks()) {
            // 如果有指定,則直接攔截task的執(zhí)行,改為打印 task 的 name 以及執(zhí)行順序
            textOutputFactory.create(DryRunBuildExecutionAction.class)
                .append(((TaskInternal) task).getIdentityPath().getPath())
                .append(" ")
                .style(StyledTextOutput.Style.ProgressStatus)
                .append("SKIPPED")
                .println();
        }
    } else {
        // 3. 如果沒(méi)有配置,則執(zhí)行下一個(gè) BuildExecutionAction 的 execute()
        context.proceed();
    }
}

可以看到 DryRunBuildExecutionAction 的作用是攔截 task 的執(zhí)行過(guò)程。

  1. 首先通過(guò) StartParameter 獲取到是否有指定 -m 或者 --dry-run 參數(shù);
  2. 如果有指定該參數(shù),則攔截 tasks 的執(zhí)行,改為遍歷所有待執(zhí)行的 tasks,逐個(gè)打印其 path;
  3. 如果沒(méi)有指定該參數(shù),則執(zhí)行下一個(gè) BuildExecutionActionexecute()

來(lái)看看 ./gradlew clean --dry-run 的效果圖。

--dry-run效果圖.png

2.2.2 回調(diào)傳給 whenReady() 的閉包

接下來(lái)會(huì)執(zhí)行到 SelectedTaskExecutionActionexecute(),來(lái)看看其源碼。

// SelectedTaskExecutionAction.java
public void execute(BuildExecutionContext context, Collection<? super Throwable> taskFailures) {
    GradleInternal gradle = context.getGradle();
    TaskExecutionGraphInternal taskGraph = gradle.getTaskGraph();
    // 是否有指定參數(shù) --continue,如果為true,在失敗的時(shí)候依舊會(huì)繼續(xù)執(zhí)行
    if (gradle.getStartParameter().isContinueOnFailure()) {
        taskGraph.setContinueOnFailure(true);
    }

    taskGraph.addTaskExecutionGraphListener(new BindAllReferencesOfProjectsToExecuteListener());
    // 執(zhí)行 tasks
    taskGraph.execute(taskFailures);
}

這里首先會(huì)看是否有指定 --continue,該參數(shù)表示在執(zhí)行失敗的時(shí)候是否繼續(xù)執(zhí)行 tasks,然后調(diào)用 DefaultTaskExecutionGraphexecute() 準(zhǔn)備 run tasks。

// DefaultTaskExecutionGraph.java
public void execute(Collection<? super Throwable> failures) {
    ProjectExecutionServiceRegistry projectExecutionServices = new ProjectExecutionServiceRegistry();
    executeWithServices(projectExecutionServices, failures);
    // ...
}

private void executeWithServices(ProjectExecutionServiceRegistry projectExecutionServices, Collection<? super Throwable> failures) {
    Timer clock = Time.startTimer();
    // 1. 確保task的有向無(wú)環(huán)圖已經(jīng)生成
    ensurePopulated();
    if (!hasFiredWhenReady) {
        ProjectStateRegistry projectStateRegistry = gradleInternal.getServices().get(ProjectStateRegistry.class);
        // 2. 調(diào)用 TaskExecutionGraphListener 的 graphPopulated()
        projectStateRegistry.withLenientState(new Runnable() {
            @Override
            public void run() {
                buildOperationExecutor.run(new NotifyTaskGraphWhenReady(DefaultTaskExecutionGraph.this, graphListeners.getSource(), gradleInternal));
            }
        });
        hasFiredWhenReady = true;
    } 

    try {
        // 3. 調(diào)用 DefaultPlanExecutor的process()
        planExecutor.process(executionPlan, failures,
            new BuildOperationAwareExecutionAction(
                buildOperationExecutor.getCurrentOperation(),
                new InvokeNodeExecutorsAction(nodeExecutors, projectExecutionServices)
            )
        );
    }
    // ...
}

這里首先調(diào)用了 ensurePopulated() 確保 task 的有向無(wú)環(huán)圖已經(jīng)生成,然后會(huì)調(diào)用 NotifyTaskGraphWhenReadyrun(),來(lái)看看其源碼。

// NotifyTaskGraphWhenReady(DefaultTaskExecutionGraph的內(nèi)部類)
public void run(BuildOperationContext context) {
    graphListener.graphPopulated(taskExecutionGraph);
}

這里會(huì)調(diào)用 TaskExecutionGraphListenergraphPopulated();為什么提這個(gè)方法,這就得看看 DefaultTaskExecutionGraphwhenReady() 了,這也是編寫 gradle 腳本經(jīng)常使用的一個(gè)方法。

// DefaultTaskExecutionGraph.java
public void whenReady(final Closure closure) {
    graphListeners.add(new ClosureBackedMethodInvocationDispatch("graphPopulated", listenerBuildOperationDecorator.decorate("TaskExecutionGraph.whenReady", closure)));
}

public void whenReady(final Action<TaskExecutionGraph> action) {
    graphListeners.add(listenerBuildOperationDecorator.decorate("TaskExecutionGraph.whenReady", TaskExecutionGraphListener.class, new TaskExecutionGraphListener() {
        @Override
        public void graphPopulated(TaskExecutionGraph graph) {
            action.execute(graph);
        }
    }));
}

可以看到,傳給 whenReady() 的動(dòng)作實(shí)際上是被封裝成了 TaskExecutionGraphListener,所以調(diào)用 TaskExecutionGraphListenergraphPopulated() 即回調(diào)了傳給 whenReady() 的動(dòng)作。

接著調(diào)用了 planExecutorprocess(),注意這里傳遞的參數(shù) BuildOperationAwareExecutionAction,后面會(huì)使用到。

2.2.3 創(chuàng)建線程和 ExecutorWorker

planExecutor 是通過(guò)反射調(diào)用的 ExecutionGradleServicescreatePlanExecutor()

// ExecutionGradleServices.java
PlanExecutor createPlanExecutor(
    ParallelismConfigurationManager parallelismConfigurationManager,
    ExecutorFactory executorFactory,
    WorkerLeaseService workerLeaseService,
    BuildCancellationToken cancellationToken,
    ResourceLockCoordinationService coordinationService) {
    // 這個(gè)參數(shù)gradle并行構(gòu)建的時(shí)候會(huì)有用 org.gradle.parallel = true
    int parallelThreads = parallelismConfigurationManager.getParallelismConfiguration().getMaxWorkerCount();
    if (parallelThreads < 1) {
        throw new IllegalStateException(String.format("Cannot create executor for requested number of worker threads: %s.", parallelThreads));
    }

    return new DefaultPlanExecutor(
        parallelismConfigurationManager.getParallelismConfiguration(),
        executorFactory,
        workerLeaseService,
        cancellationToken,
        coordinationService
    );
}

DefaultPlanExecutor 的實(shí)例,來(lái)看看其 process() 的源碼。

// DefaultPlanExecutor.java
public void process(ExecutionPlan executionPlan, Collection<? super Throwable> failures, Action<Node> nodeExecutor) {
    // 創(chuàng)建線程池
    ManagedExecutor executor = executorFactory.create("Execution worker for '" + executionPlan.getDisplayName() + "'");
    try {
        WorkerLease parentWorkerLease = workerLeaseService.getCurrentWorkerLease();
        // org.gradle.parallel=true 的時(shí)候會(huì)開(kāi)啟多個(gè) ExecutorWorker 并行構(gòu)建
        startAdditionalWorkers(executionPlan, nodeExecutor, executor, parentWorkerLease);
        new ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, cancellationToken, coordinationService).run();
        awaitCompletion(executionPlan, failures);
    }
    // ...
}

private void startAdditionalWorkers(ExecutionPlan executionPlan, Action<? super Node> nodeExecutor, Executor executor, WorkerLease parentWorkerLease) {
    // 創(chuàng)建多個(gè) ExecutorWorker 并行構(gòu)建
    for (int i = 1; i < executorCount; i++) {
        executor.execute(new ExecutorWorker(executionPlan, nodeExecutor, parentWorkerLease, cancellationToken, coordinationService));
    }
}

這里會(huì)創(chuàng)建線程池 ManagedExecutor 和任務(wù) ExecutorWorker,在開(kāi)啟了 org.gradle.parallel 的情況下,會(huì)創(chuàng)建多個(gè)線程和任務(wù)并行執(zhí)行。

2.2.4 task 執(zhí)行前的預(yù)處理

接著會(huì)調(diào)用到 ExecutorWorkerrun(),來(lái)看看其源碼。

// ExecutorWorker(DefaultPlanExecutor.java的內(nèi)部類)
public void run() {
    WorkerLease childLease = parentWorkerLease.createChild();
    while (true) {
        // 調(diào)用 executeNextNode()
        boolean nodesRemaining = executeNextNode(childLease, new Action<Node>() {
            @Override
            public void execute(Node work) {
                nodeExecutor.execute(work);
                // ...
            }
        });
        if (!nodesRemaining) {
            // 沒(méi)有任務(wù)執(zhí)行了。
            break;
        }
    }
}

private boolean executeNextNode(final WorkerLease workerLease, final Action<Node> nodeExecutor) {
    final MutableReference<Node> selected = MutableReference.empty();
    final MutableBoolean nodesRemaining = new MutableBoolean();
    coordinationService.withStateLock(new Transformer<ResourceLockState.Disposition, ResourceLockState>() {
        @Override
        public ResourceLockState.Disposition transform(ResourceLockState resourceLockState) {
            // 是否取消執(zhí)行
            if (cancellationToken.isCancellationRequested()) {
                executionPlan.cancelExecution();
            }

            nodesRemaining.set(executionPlan.hasNodesRemaining());
            // 沒(méi)有任務(wù)執(zhí)行了,則標(biāo)記為結(jié)束
            if (!nodesRemaining.get()) {
                return FINISHED;
            }

            try {
                selected.set(executionPlan.selectNext(workerLease, resourceLockState));
            } catch (Throwable t) {
                resourceLockState.releaseLocks();
                executionPlan.abortAllAndFail(t);
                nodesRemaining.set(false);
            }

            if (selected.get() == null && nodesRemaining.get()) {
                return RETRY;
            } else {
                return FINISHED;
            }
        }
    });

    Node selectedNode = selected.get();
    if (selectedNode != null) {
        execute(selectedNode, workerLease, nodeExecutor);
    }
    return nodesRemaining.get();
}

private void execute(final Node selected, final WorkerLease workerLease, Action<Node> nodeExecutor) {
    try {
        if (!selected.isComplete()) {
            try {
                // 執(zhí)行 ExecutorWorker里面創(chuàng)建的 Action 匿名內(nèi)部類實(shí)例的 execute()
                nodeExecutor.execute(selected);
            } catch (Throwable e) {
                selected.setExecutionFailure(e);
            }
        }
    }
    // ...
}

可以看到最終會(huì)調(diào)用到 nodeExecutor.execute(work),而這里的 nodeExecutor 也就是前面說(shuō)的傳給 process()BuildOperationAwareExecutionAction 的實(shí)例,來(lái)看看其 execute()

public void execute(Node node) {
    // ...
    delegate.execute(node);
    // ...
}

這里實(shí)際上是調(diào)用了 InvokeNodeExecutorsActionexecute()

public void execute(Node node) {
    for (NodeExecutor nodeExecutor : nodeExecutors) {
        if (nodeExecutor.execute(node, projectExecutionServices)) {
            return;
        }
    }
    throw new IllegalStateException("Unknown type of node: " + node);
}

可以看到它只是遍歷調(diào)用了傳遞進(jìn)來(lái)的 nodeExecutorexecute();這里的 nodeExecutors 是通過(guò)反射調(diào)用了 GradleScopeServicescreateLocalTaskNodeExecutor()

// GradleScopeServices.java
LocalTaskNodeExecutor createLocalTaskNodeExecutor() {
    return new LocalTaskNodeExecutor();
}

LocalTaskNodeExecutor 的實(shí)例,來(lái)看看其 execute() 的源碼。

// LocalTaskNodeExecutor.java
public boolean execute(Node node, ProjectExecutionServiceRegistry services) {
    if (node instanceof LocalTaskNode) {
        LocalTaskNode localTaskNode = (LocalTaskNode) node;
        TaskInternal task = localTaskNode.getTask();
        TaskStateInternal state = task.getState();
        // 判斷任務(wù)是否已經(jīng)執(zhí)行過(guò),如果執(zhí)行過(guò),則直接返回
        if (state.getExecuted()) {
            return true;
        }
        TaskExecutionContext ctx = new DefaultTaskExecutionContext(localTaskNode);
        // 這里又通過(guò)反射找 TaskExecuter
        TaskExecuter taskExecuter = services.getProjectService((ProjectInternal) task.getProject(), TaskExecuter.class);
        assert taskExecuter != null;
        // 這里就是執(zhí)行 task 的入口
        taskExecuter.execute(task, state, ctx);
        localTaskNode.getPostAction().execute(task);
        return true;
    } else {
        return false;
    }
}

它首先判斷 task 是否有執(zhí)行過(guò),如果有執(zhí)行過(guò)則直接返回;如果沒(méi)有執(zhí)行過(guò),則調(diào)用 TaskExecuterexecute() 執(zhí)行 task。taskExecuter 是通過(guò)反射調(diào)用的 ProjectExecutionServicescreateTaskExecuter()

// ProjectExecutionServices.java
TaskExecuter createTaskExecuter(TaskExecutionModeResolver repository,
                                BuildCacheController buildCacheController,
                                TaskInputsListener inputsListener,
                                TaskActionListener actionListener,
                                OutputChangeListener outputChangeListener,
                                ClassLoaderHierarchyHasher classLoaderHierarchyHasher,
                                TaskSnapshotter taskSnapshotter,
                                FileCollectionFingerprinterRegistry fingerprinterRegistry,
                                BuildOperationExecutor buildOperationExecutor,
                                AsyncWorkTracker asyncWorkTracker,
                                BuildOutputCleanupRegistry cleanupRegistry,
                                ExecutionHistoryStore executionHistoryStore,
                                OutputFilesRepository outputFilesRepository,
                                BuildScanPluginApplied buildScanPlugin,
                                FileCollectionFactory fileCollectionFactory,
                                PropertyWalker propertyWalker,
                                TaskExecutionGraphInternal taskExecutionGraph,
                                TaskExecutionListener taskExecutionListener,
                                TaskListenerInternal taskListenerInternal,
                                TaskCacheabilityResolver taskCacheabilityResolver,
                                WorkExecutor<AfterPreviousExecutionContext, CachingResult> workExecutor,
                                ReservedFileSystemLocationRegistry reservedFileSystemLocationRegistry,
                                ListenerManager listenerManager
) {

    boolean buildCacheEnabled = buildCacheController.isEnabled();
    boolean scanPluginApplied = buildScanPlugin.isBuildScanPluginApplied();
    // 這個(gè) executer 才是真正執(zhí)行 task 的
    TaskExecuter executer = new ExecuteActionsTaskExecuter(
        buildCacheEnabled,
        scanPluginApplied,
        taskSnapshotter,
        executionHistoryStore,
        buildOperationExecutor,
        asyncWorkTracker,
        actionListener,
        taskCacheabilityResolver,
        fingerprinterRegistry,
        classLoaderHierarchyHasher,
        workExecutor,
        listenerManager
    );
    // 下面這些都是包裝
    executer = new ValidatingTaskExecuter(executer, reservedFileSystemLocationRegistry);
    executer = new SkipEmptySourceFilesTaskExecuter(inputsListener, executionHistoryStore, cleanupRegistry, outputChangeListener, executer);
    executer = new ResolveBeforeExecutionOutputsTaskExecuter(taskSnapshotter, executer);
    if (buildCacheEnabled || scanPluginApplied) {
        executer = new StartSnapshotTaskInputsBuildOperationTaskExecuter(buildOperationExecutor, executer);
    }
    executer = new ResolveAfterPreviousExecutionStateTaskExecuter(executionHistoryStore, executer);
    executer = new CleanupStaleOutputsExecuter(cleanupRegistry, outputFilesRepository, buildOperationExecutor, outputChangeListener, executer);
    executer = new FinalizePropertiesTaskExecuter(executer);
    executer = new ResolveTaskExecutionModeExecuter(repository, fileCollectionFactory, propertyWalker, executer);
    executer = new SkipTaskWithNoActionsExecuter(taskExecutionGraph, executer);
    executer = new SkipOnlyIfTaskExecuter(executer);
    executer = new CatchExceptionTaskExecuter(executer);
    executer = new EventFiringTaskExecuter(buildOperationExecutor, taskExecutionListener, taskListenerInternal, executer);
    return executer;
}

真正執(zhí)行 task 的是 ExecuteActionsTaskExecuter,其他都是對(duì)其進(jìn)行的包裝,在執(zhí)行 task 前做一些預(yù)處理操作,從下往上挑關(guān)鍵的說(shuō)。

2.2.4.1 EventFiringTaskExecuter

首先來(lái)看看 EventFiringTaskExecuterexecute()

// EventFiringTaskExecuter.java
public TaskExecuterResult execute(final TaskInternal task, final TaskStateInternal state, final TaskExecutionContext context) {
    return buildOperationExecutor.call(new CallableBuildOperation<TaskExecuterResult>() {
        @Override
        public TaskExecuterResult call(BuildOperationContext operationContext) {
            TaskExecuterResult result = executeTask(operationContext);
            // ...
            return result;
        }

        private TaskExecuterResult executeTask(BuildOperationContext operationContext) {
            // ... 
            // 1. 調(diào)用 TaskExecutionListener 的 beforeExecute()
            taskExecutionListener.beforeExecute(task);
            // ...
            // 2. 執(zhí)行下一個(gè) execute()
            TaskExecuterResult result = delegate.execute(task, state, context);
            // ... 
            // 3. 調(diào)用 TaskExecutionListener 的 afterExecute()
            taskExecutionListener.afterExecute(task, state);
            // ...
        }
    });
}

可以看到,這里主要是增加事件回調(diào)。在 Task 執(zhí)行前調(diào)用 TaskExecutionListenerbeforeExecute(),在 Task 執(zhí)行后調(diào)用 TaskExecutionListenerafterExecute()

2.2.4.2 CatchExceptionTaskExecuter

再來(lái)看看 CatchExceptionTaskExecuterexecute()

// CatchExceptionTaskExecuter.java
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
    try {
        return delegate.execute(task, state, context);
    } catch (RuntimeException e) {
        state.setOutcome(new TaskExecutionException(task, e));
        return TaskExecuterResult.WITHOUT_OUTPUTS;
    }
}

這里主要是給 task 執(zhí)行加上 try{}catch{}

2.2.4.3 SkipOnlyIfTaskExecuter

再來(lái)看看 SkipOnlyIfTaskExecuterexecute()

// SkipOnlyIfTaskExecuter.java
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
    boolean skip;
    try {
        skip = !task.getOnlyIf().isSatisfiedBy(task);
    } catch (Throwable t) {
        state.setOutcome(new GradleException(String.format("Could not evaluate onlyIf predicate for %s.", task), t));
        return TaskExecuterResult.WITHOUT_OUTPUTS;
    }

    if (skip) {
        state.setOutcome(TaskExecutionOutcome.SKIPPED);
        return TaskExecuterResult.WITHOUT_OUTPUTS;
    }

    return executer.execute(task, state, context);
}

這里主要是判斷 task 的 onlyIf 條件是否滿足執(zhí)行,onlyIf 類似于 javaif 語(yǔ)句,只有當(dāng)判斷條件為真的時(shí)候才會(huì)執(zhí)行 task。

舉個(gè)栗子方便理解。在 root project 的 build.gradle 文件里面添加如下代碼。

subprojects { Project p ->
    Task hello = p.task("hello") {
        doLast {
            println("execute hello task!")
        }
    }
}

sync 后運(yùn)行 ./gradlew hello ,結(jié)果如下。

沒(méi)有onlyIf.png

這里分別執(zhí)行了 app 和 app2 的 hello task,然后修改 build.gradle 增加 onlyIf 判斷。

subprojects { Project p ->
    Task hello = p.task("hello") {
        doLast {
            println("execute hello task!")
        }
    }
    // 只有當(dāng)是 app 的時(shí)候才執(zhí)行
    hello.onlyIf { hello.project.name == "app" }
}

sync 后再次運(yùn)行 ./gradlew hello ,結(jié)果如下,可以看到相較于上面少了 :app2:hello 的執(zhí)行,說(shuō)明 onlyIf 生效了。

有onlyIf.png

2.2.4.4 SkipTaskWithNoActionsExecuter

來(lái)看看 SkipTaskWithNoActionsExecuterexecute()

// SkipTaskWithNoActionsExecuter.java
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
    if (!task.hasTaskActions()) {
        boolean upToDate = true;
        for (Task dependency : taskExecutionGraph.getDependencies(task)) {
            if (!dependency.getState().getSkipped()) {
                upToDate = false;
                break;
            }
        }
        state.setActionable(false);
        state.setOutcome(upToDate ? TaskExecutionOutcome.UP_TO_DATE : TaskExecutionOutcome.EXECUTED);
        return TaskExecuterResult.WITHOUT_OUTPUTS;
    }
    return executer.execute(task, state, context);
}

這里是跳過(guò)那些沒(méi)有 action 的 task,沒(méi)有 action 說(shuō)明 task 不需要執(zhí)行。

2.2.4.5 ResolveTaskExecutionModeExecuter

來(lái)看看 ResolveTaskExecutionModeExecuterexecute()

// ResolveTaskExecutionModeExecuter.java
public TaskExecuterResult execute(final TaskInternal task, TaskStateInternal state, final TaskExecutionContext context) {
    Timer clock = Time.startTimer();
    // 1. 解析 task 屬性
    TaskProperties properties = DefaultTaskProperties.resolve(propertyWalker, fileCollectionFactory, task);
    context.setTaskProperties(properties);
    // 2. 解析 task 的 Execution Mode
    TaskExecutionMode taskExecutionMode = executionModeResolver.getExecutionMode(task, properties);
    TaskOutputsInternal outputs = task.getOutputs();
    context.setTaskExecutionMode(taskExecutionMode);
    // ...
}

這里主要做了兩件事情:

  1. 解析 Task 的屬性,比如輸入、輸出等;
  2. 獲取 TaskExecution Mode

過(guò)程一有點(diǎn)多,先說(shuō)過(guò)程二。這里的 executionModeResolver 是通過(guò)反射調(diào)用 ProjectExecutionServicescreateExecutionModeResolver()

TaskExecutionModeResolver createExecutionModeResolver(
    StartParameter startParameter
) {
    return new DefaultTaskExecutionModeResolver(startParameter);
}

來(lái)看看 DefaultTaskExecutionModeResolvergetExecutionMode()

// DefaultTaskExecutionModeResolver.java
public TaskExecutionMode getExecutionMode(TaskInternal task, TaskProperties properties) {
    AndSpec<? super TaskInternal> upToDateSpec = task.getOutputs().getUpToDateSpec();
    // 如果沒(méi)有聲明 outputs 并且沒(méi)有指定 upToDateSpec
    if (!properties.hasDeclaredOutputs() && upToDateSpec.isEmpty()) {
        if (task.hasTaskActions()) {
            if (requiresInputChanges(task)) {
                DeprecationLogger.nagUserOfDeprecated("Using the incremental task API without declaring any outputs", "Please declare output files for your task or use `TaskOutputs.upToDateWhen()`.");
            } else {
                return TaskExecutionMode.NO_OUTPUTS_WITH_ACTIONS;
            }
        } else {
            return TaskExecutionMode.NO_OUTPUTS_WITHOUT_ACTIONS;
        }
    }

    if (startParameter.isRerunTasks()) {
        return TaskExecutionMode.RERUN_TASKS_ENABLED;
    }

    if (!upToDateSpec.isSatisfiedBy(task)) {
        return TaskExecutionMode.UP_TO_DATE_WHEN_FALSE;
    }

    return TaskExecutionMode.INCREMENTAL;
}

這個(gè) TaskExecutionMode 究竟是啥玩意呢?來(lái)看看其源碼。

public enum TaskExecutionMode {
    INCREMENTAL(null, true, true),
    NO_OUTPUTS_WITHOUT_ACTIONS("Task has not declared any outputs nor actions.", false, false),
    NO_OUTPUTS_WITH_ACTIONS("Task has not declared any outputs despite executing actions.", false, false),
    RERUN_TASKS_ENABLED("Executed with '--rerun-tasks'.", true, false),
    UP_TO_DATE_WHEN_FALSE("Task.upToDateWhen is false.", true, false);

    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    private final Optional<String> rebuildReason;
    private final boolean taskHistoryMaintained;
    private final boolean allowedToUseCachedResults;

    TaskExecutionMode(@Nullable String rebuildReason, boolean taskHistoryMaintained, boolean allowedToUseCachedResults) {
        this.rebuildReason = Optional.ofNullable(rebuildReason);
        this.taskHistoryMaintained = taskHistoryMaintained;
        this.allowedToUseCachedResults = allowedToUseCachedResults;
    }

    // 返回原因
    public Optional<String> getRebuildReason() {
        return rebuildReason;
    }

    // 這個(gè)方法標(biāo)記了是否需要記錄執(zhí)行歷史
    public boolean isTaskHistoryMaintained() {
        return taskHistoryMaintained;
    }

    // 這里方法決定了是否加載緩存來(lái)替代執(zhí)行 task
    public boolean isAllowedToUseCachedResults() {
        return allowedToUseCachedResults;
    }
}

TaskExecutionMode 有兩個(gè)比較重要的方法 isTaskHistoryMaintained()isAllowedToUseCachedResults(),它們影響到了 Task 的執(zhí)行流程。

再看下過(guò)程一是如何解析 Task 屬性的。先來(lái)看看DefaultTaskPropertiesresolve()

// DefaultTaskProperties.java
public static TaskProperties resolve(PropertyWalker propertyWalker, FileCollectionFactory fileCollectionFactory, TaskInternal task) {
    String beanName = task.toString();
    GetInputFilesVisitor inputFilesVisitor = new GetInputFilesVisitor(beanName, fileCollectionFactory);
    GetOutputFilesVisitor outputFilesVisitor = new GetOutputFilesVisitor(beanName, fileCollectionFactory);
    GetInputPropertiesVisitor inputPropertiesVisitor = new GetInputPropertiesVisitor(beanName);
    GetLocalStateVisitor localStateVisitor = new GetLocalStateVisitor(beanName, fileCollectionFactory);
    GetDestroyablesVisitor destroyablesVisitor = new GetDestroyablesVisitor(beanName, fileCollectionFactory);
    ValidationVisitor validationVisitor = new ValidationVisitor();
    try {
        // 主要是這個(gè)方法
        TaskPropertyUtils.visitProperties(propertyWalker, task, new CompositePropertyVisitor(
            inputPropertiesVisitor,
            inputFilesVisitor,
            outputFilesVisitor,
            validationVisitor,
            destroyablesVisitor,
            localStateVisitor
        ));
    } catch (Exception e) {
        throw new TaskExecutionException(task, e);
    }

    // 把解析出來(lái)的屬性存到 DefaultTaskProperties里面
    return new DefaultTaskProperties(
        task.toString(),
        inputPropertiesVisitor.getPropertyValuesSupplier(),
        inputFilesVisitor.getFileProperties(),
        outputFilesVisitor.getFileProperties(),
        outputFilesVisitor.hasDeclaredOutputs(),
        localStateVisitor.getFiles(),
        destroyablesVisitor.getFiles(),
        validationVisitor.getTaskPropertySpecs());
}

主要是調(diào)用的 TaskPropertyUtils.visitProperties(),來(lái)看看其源碼。

// TaskPropertyUtils.java
public static void visitProperties(PropertyWalker propertyWalker, final TaskInternal task, final PropertyVisitor visitor) {
    StrictErrorsOnlyContext validationContext = new StrictErrorsOnlyContext(task);
    propertyWalker.visitProperties(task, validationContext, visitor);
    // ...
}

這里的 propertyWalker 是通過(guò)反射調(diào)用的 ExecutionGlobalServicescreatePropertyWalker()

// ExecutionGlobalServices.java
PropertyWalker createPropertyWalker(TaskScheme taskScheme) {
    return taskScheme.getInspectionScheme().getPropertyWalker();
}

taskScheme 是通過(guò)反射調(diào)用的 ExecutionGlobalServicescreateTaskScheme()

// ExecutionGlobalServices.java
TaskScheme createTaskScheme(InspectionSchemeFactory inspectionSchemeFactory, InstantiatorFactory instantiatorFactory) {
    InstantiationScheme instantiationScheme = instantiatorFactory.decorateScheme();
    InspectionScheme inspectionScheme = inspectionSchemeFactory.inspectionScheme(
        ImmutableSet.of(
            Input.class,
            InputFile.class,
            InputFiles.class,
            InputDirectory.class,
            OutputFile.class,
            OutputFiles.class,
            OutputDirectory.class,
            OutputDirectories.class,
            Destroys.class,
            LocalState.class,
            Nested.class,
            Console.class,
            ReplacedBy.class,
            Internal.class,
            OptionValues.class
        ),
        ImmutableSet.of(
            Classpath.class,
            CompileClasspath.class,
            Incremental.class,
            Optional.class,
            PathSensitive.class,
            SkipWhenEmpty.class
        ),
        instantiationScheme);
    return new TaskScheme(instantiationScheme, inspectionScheme);
}

注意下傳給 inspectionScheme() 的第一個(gè)參數(shù),是很多的注解,解析屬性會(huì)用到它們,后面再說(shuō)。先看下 InspectionSchemeFactory.InspectionSchemeImplgetPropertyWalker()

// InspectionSchemeFactory.java
private static class InspectionSchemeImpl implements InspectionScheme {
    private final DefaultPropertyWalker propertyWalker;

    public InspectionSchemeImpl(List<TypeAnnotationHandler> typeHandlers, List<PropertyAnnotationHandler> propertyHandlers, Collection<Class<? extends Annotation>> propertyModifiers, TypeAnnotationMetadataStore typeAnnotationMetadataStore, CrossBuildInMemoryCacheFactory cacheFactory) {
        propertyWalker = new DefaultPropertyWalker(metadataStore);
    }

    @Override
    public PropertyWalker getPropertyWalker() {
        return propertyWalker;
    }
}

DefaultPropertyWalker 的實(shí)例,來(lái)看看其源碼。

public class DefaultPropertyWalker implements PropertyWalker {
    private final RuntimeBeanNodeFactory nodeFactory;

    public DefaultPropertyWalker(TypeMetadataStore typeMetadataStore) {
        this.nodeFactory = new RuntimeBeanNodeFactory(typeMetadataStore);
    }

    @Override
    public void visitProperties(Object bean, ParameterValidationContext validationContext, PropertyVisitor visitor) {
        Queue<RuntimeBeanNode<?>> queue = new ArrayDeque<RuntimeBeanNode<?>>();
        // node 為 RootRuntimeBeanNode
        queue.add(nodeFactory.createRoot(bean));
        while (!queue.isEmpty()) {
            RuntimeBeanNode<?> node = queue.remove();
            node.visitNode(visitor, queue, nodeFactory, validationContext);
        }
    }
}

// RuntimeBeanNodeFactory.java
public RuntimeBeanNode<?> createRoot(Object bean) {
    return new RootRuntimeBeanNode(bean, metadataStore.getTypeMetadata(bean.getClass()));
}

這里的 nodeRootRuntimeBeanNode,來(lái)看看其 visitNode()

// AbstractNestedRuntimeBeanNode.java
protected void visitProperties(PropertyVisitor visitor, final Queue<RuntimeBeanNode<?>> queue, final RuntimeBeanNodeFactory nodeFactory, ParameterValidationContext validationContext) {
    TypeMetadata typeMetadata = getTypeMetadata();
    typeMetadata.collectValidationFailures(getPropertyName(), validationContext);
    for (PropertyMetadata propertyMetadata : typeMetadata.getPropertiesMetadata()) {
        // 找屬性對(duì)應(yīng)的 PropertyAnnotationHandler
        PropertyAnnotationHandler annotationHandler = typeMetadata.getAnnotationHandlerFor(propertyMetadata);
        if (annotationHandler.shouldVisit(visitor)) {
            String propertyName = getQualifiedPropertyName(propertyMetadata.getPropertyName());
            PropertyValue value = new BeanPropertyValue(getBean(), propertyMetadata.getGetterMethod());
            // 這里最終會(huì)調(diào)用 注解對(duì)應(yīng)的 PropertyAnnotationHandler 的 visitPropertyValue()
            annotationHandler.visitPropertyValue(propertyName, value, propertyMetadata, visitor, new BeanPropertyContext() {
                @Override
                public void addNested(String propertyName, Object bean) {
                    queue.add(nodeFactory.create(AbstractNestedRuntimeBeanNode.this, propertyName, bean));
                }
            });
        }
    }
}

還記得前面很多注解的參數(shù)嗎,其實(shí)解析屬性就是解析這些注解所修飾的東西。每個(gè)注解都會(huì)對(duì)應(yīng)一個(gè) PropertyAnnotationHandler。拿 InputFile 舉個(gè)栗子,它對(duì)應(yīng)的是 InputFilePropertyAnnotationHandler,來(lái)看看其 visitPropertyValue()

// AbstractInputFilePropertyAnnotationHandler.java
public void visitPropertyValue(String propertyName, PropertyValue value, PropertyMetadata propertyMetadata, PropertyVisitor visitor, BeanPropertyContext context) {
    // ...
    // 調(diào)用了 visitor 的 visitInputFileProperty(),visitor 即前面 DefaultTaskProperties.resolve() 里面?zhèn)魅氲?GetInputFilesVisitor
    visitor.visitInputFileProperty(
        propertyName,
        propertyMetadata.isAnnotationPresent(Optional.class),
        propertyMetadata.isAnnotationPresent(SkipWhenEmpty.class),
        propertyMetadata.isAnnotationPresent(Incremental.class),
        fileNormalizer,
        value,
        getFilePropertyType()
    );
}

這里調(diào)用到了 visitorvisitInputFileProperty(),它是前面 DefaultTaskProperties.resolve() 里面?zhèn)魅氲?GetInputFilesVisitor 實(shí)例,來(lái)看看其 visitInputFileProperty()

public void visitInputFileProperty(final String propertyName, boolean optional, boolean skipWhenEmpty, boolean incremental, @Nullable Class<? extends FileNormalizer> fileNormalizer, PropertyValue value, InputFilePropertyType filePropertyType) {
    // 解析 input file 是 directory 還是 file
    FileCollection actualValue = FileParameterUtils.resolveInputFileValue(fileCollectionFactory, filePropertyType, value);
    // 加到集合中
    specs.add(new DefaultInputFilePropertySpec(
        propertyName,
        FileParameterUtils.normalizerOrDefault(fileNormalizer),
        new PropertyFileCollection(ownerDisplayName, propertyName, "input", actualValue),
        value,
        skipWhenEmpty,
        incremental
    ));
    if (skipWhenEmpty) {
        hasSourceFiles = true;
    }
}

2.2.4.6 SkipEmptySourceFilesTaskExecuter

再來(lái)看看 SkipEmptySourceFilesTaskExecuterexecute()

// SkipEmptySourceFilesTaskExecuter.java
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, final TaskExecutionContext context) {
        TaskProperties properties = context.getTaskProperties();
        FileCollection sourceFiles = properties.getSourceFiles();
        // 如果有 source files 但是 source files 是空的
        if (properties.hasSourceFiles() && sourceFiles.isEmpty()) {
            AfterPreviousExecutionState previousExecution = context.getAfterPreviousExecution();
            ImmutableSortedMap<String, FileCollectionFingerprint> outputFiles = previousExecution == null
                ? ImmutableSortedMap.<String, FileCollectionFingerprint>of()
                : previousExecution.getOutputFileProperties();
            if (outputFiles.isEmpty()) {
                // 沒(méi)有 outputs,則標(biāo)記為 NO_SOURCE
                state.setOutcome(TaskExecutionOutcome.NO_SOURCE);
            } else {
                outputChangeListener.beforeOutputChange();
                OutputsCleaner outputsCleaner = new OutputsCleaner(new Predicate<File>() {
                    @Override
                    public boolean test(File file) {
                        return buildOutputCleanupRegistry.isOutputOwnedByBuild(file);
                    }
                }, new Predicate<File>() {
                    @Override
                    public boolean test(File dir) {
                        return buildOutputCleanupRegistry.isOutputOwnedByBuild(dir);
                    }
                });
                for (FileCollectionFingerprint outputFingerprints : outputFiles.values()) {
                    try {
                        outputsCleaner.cleanupOutputs(outputFingerprints);
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                }
                if (outputsCleaner.getDidWork()) {
                    state.setOutcome(TaskExecutionOutcome.EXECUTED);
                } else {
                    state.setOutcome(TaskExecutionOutcome.NO_SOURCE);
                }
            }
            taskInputsListener.onExecute(task, Cast.cast(FileCollectionInternal.class, sourceFiles));
            executionHistoryStore.remove(task.getPath());
            return TaskExecuterResult.WITHOUT_OUTPUTS;
        } else {
            taskInputsListener.onExecute(task, Cast.cast(FileCollectionInternal.class, properties.getInputFiles()));
        }
        return executer.execute(task, state, context);
    }

這里是處理那些有設(shè)置 sourc files 但是 source files 為空的 Task,source files 為空說(shuō)明 Task 沒(méi)有需要處理的資源。

2.2.4.7 ValidatingTaskExecuter

再來(lái)看看 ValidatingTaskExecuterexecute()

// ValidatingTaskExecuter.java
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
    List<String> messages = Lists.newArrayList();
    FileResolver resolver = ((ProjectInternal) task.getProject()).getFileResolver();
    final TaskValidationContext validationContext = new DefaultTaskValidationContext(resolver, reservedFileSystemLocationRegistry, messages);
    // 做一些屬性的校驗(yàn)操作
    context.getTaskProperties().validate(validationContext);

    if (!messages.isEmpty()) {
        List<String> firstMessages = messages.subList(0, Math.min(5, messages.size()));
        report(task, firstMessages, state);
        return TaskExecuterResult.WITHOUT_OUTPUTS;
    }

    return executer.execute(task, state, context);
}

這里是在 Task 執(zhí)行前做一些校驗(yàn)。

2.2.5 執(zhí)行 Task

最后會(huì)執(zhí)行到 ExecuteActionsTaskExecuterexecute(),這里才是正真執(zhí)行 Task 的地方,先來(lái)看看它的源碼。

// ExecuteActionsTaskExecuter.java
public TaskExecuterResult execute(TaskInternal task, TaskStateInternal state, TaskExecutionContext context) {
    // 創(chuàng)建一個(gè) TaskExecution 實(shí)例
    TaskExecution work = new TaskExecution(task, context, executionHistoryStore, fingerprinterRegistry, classLoaderHierarchyHasher);
    // 調(diào)用 workExecutor  的 execute,最終會(huì)調(diào)用 getWork().execute(),即 TaskExecution 的 execute()
    CachingResult result = workExecutor.execute(new AfterPreviousExecutionContext() {
        @Override
        public UnitOfWork getWork() {
            return work;
        }
    });
    // ...
}

這里的 workExecutor 是通過(guò)反射調(diào)用的 ExecutionGradleServicescreateWorkExecutor()

// ExecutionGradleServices.java
public WorkExecutor<AfterPreviousExecutionContext, CachingResult> createWorkExecutor(
    BuildCacheCommandFactory buildCacheCommandFactory,
    BuildCacheController buildCacheController,
    BuildScanPluginApplied buildScanPlugin,
    BuildCancellationToken cancellationToken,
    BuildInvocationScopeId buildInvocationScopeId,
    ExecutionStateChangeDetector changeDetector,
    ClassLoaderHierarchyHasher classLoaderHierarchyHasher,
    ValueSnapshotter valueSnapshotter,
    OutputChangeListener outputChangeListener,
    OutputFilesRepository outputFilesRepository,
    TimeoutHandler timeoutHandler
) {
    return new DefaultWorkExecutor<AfterPreviousExecutionContext, CachingResult>(
        // 注意這里傳入的 Step 實(shí)例,最終會(huì)調(diào)用到 ExecuteStep 的 execute()
        new CaptureStateBeforeExecutionStep(classLoaderHierarchyHasher, valueSnapshotter,
            new ResolveCachingStateStep(buildCacheController, buildScanPlugin.isBuildScanPluginApplied(),
                new MarkSnapshottingInputsFinishedStep<UpToDateResult>(
                    new ResolveChangesStep<UpToDateResult>(changeDetector,
                        new SkipUpToDateStep<IncrementalChangesContext>(
                            new RecordOutputsStep<IncrementalChangesContext>(outputFilesRepository,
                                new StoreSnapshotsStep<IncrementalChangesContext>(
                                    new BroadcastChangingOutputsStep<IncrementalChangesContext, CurrentSnapshotResult>(outputChangeListener,
                                        new CacheStep(buildCacheController, buildCacheCommandFactory,
                                            new SnapshotOutputsStep<IncrementalChangesContext>(buildInvocationScopeId.getId(),
                                                new CreateOutputsStep<IncrementalChangesContext, Result>(
                                                    new CatchExceptionStep<IncrementalChangesContext>(
                                                        new TimeoutStep<IncrementalChangesContext>(timeoutHandler,
                                                            new CancelExecutionStep<IncrementalChangesContext>(cancellationToken,
                                                                new ResolveInputChangesStep<IncrementalChangesContext>(
                                                                    new CleanupOutputsStep<InputChangesContext, Result>(
                                                                        new ExecuteStep<InputChangesContext>()
                                                                    )
                                                                )
                                                            )
                                                        )
                                                    )
                                                )
                                            )
                                        )
                                    )
                                )
                            )
                        )
                    )
                )
            )
        )
    );
}

DefaultWorkExecutor 的實(shí)例,注意這里傳入的 Step,后面會(huì)用到。先來(lái)看看 DefaultWorkExecutorexecute()

// DefaultWorkExecutor.java
public R execute(C context) {
    return executeStep.execute(context);
}

這里直接調(diào)用了 executeStepexecute(),即上面?zhèn)魅氲?Stepexecute(),跟隨調(diào)用鏈發(fā)現(xiàn)它最終會(huì)調(diào)用到 ExecuteStepexecute(),來(lái)看看其源碼。

// ExecuteStep.java
public Result execute(C context) {
    // 前面你說(shuō)了 getWork() 即 TaskExecution,這里調(diào)用了它的 execute()
    UnitOfWork work = context.getWork();
    ExecutionOutcome outcome = context.getInputChanges()
        .map(inputChanges -> determineOutcome(work.execute(inputChanges), inputChanges.isIncremental()))
        .orElseGet(() -> determineOutcome(work.execute(null), false));
    return new Result() {
        @Override
        public Try<ExecutionOutcome> getOutcome() {
            return Try.successful(outcome);
        }
    };
}

這里會(huì)調(diào)用 TaskExecutionexecute(),來(lái)看看其源碼。

// TaskExecution(ExecuteActionsTaskExecuter.java的內(nèi)部類)
public WorkResult execute(@Nullable InputChangesInternal inputChanges) {
    task.getState().setExecuting(true);
    try {
        // 1. 調(diào)用 TaskActionListener 的 beforeActions()
        actionListener.beforeActions(task);
        // 2. 調(diào)用 executeActions()
        executeActions(task, inputChanges);
        return task.getState().getDidWork() ? WorkResult.DID_WORK : WorkResult.DID_NO_WORK;
    } finally {
        task.getState().setExecuting(false);
        // 3. 調(diào)用 TaskActionListener 的 afterActions()
        actionListener.afterActions(task);
    }
}

private void executeActions(TaskInternal task, @Nullable InputChangesInternal inputChanges) {
    boolean hasTaskListener = listenerManager.hasListeners(TaskActionListener.class) || listenerManager.hasListeners(TaskExecutionListener.class);
    Iterator<InputChangesAwareTaskAction> actions = new ArrayList<>(task.getTaskActions()).iterator();
    // 遍歷 actions,逐個(gè)調(diào)用 executeAction()
    while (actions.hasNext()) {
        InputChangesAwareTaskAction action = actions.next();
        task.getState().setDidWork(true);
        task.getStandardOutputCapture().start();
        boolean hasMoreWork = hasTaskListener || actions.hasNext();
        // 調(diào)用 executeAction()
        executeAction(action.getDisplayName(), task, action, inputChanges, hasMoreWork);
    }
}

private void executeAction(String actionDisplayName, TaskInternal task, InputChangesAwareTaskAction action, @Nullable InputChangesInternal inputChanges, boolean hasMoreWork) {
    if (inputChanges != null) {
        action.setInputChanges(inputChanges);
    }
    buildOperationExecutor.run(new RunnableBuildOperation() {
        @Override
        public void run(BuildOperationContext context) {
            // ...
            // 調(diào)用action 的execute()
            action.execute(task);
            // ...
        }
    });
}

這里的邏輯十分的清晰:

  1. 首先調(diào)用 TaskActionListenerbeforeActions()
  2. 然后遍歷 Task 所有的 Action ,逐個(gè)調(diào)用其 execute()(執(zhí)行 Task實(shí)際上就是執(zhí)行 Task 里面所有的 Action);
  3. 執(zhí)行完 Task 后會(huì)調(diào)用 TaskActionListenerafterActions()

執(zhí)行完 Task 后就會(huì)回到 DefaultGradleLauncherrunWork()

private void runWork() {
    // ...
    // 如果有失敗的,則拋出異常
    if (!taskFailures.isEmpty()) {
        throw new MultipleBuildFailures(taskFailures);
    }
    // 執(zhí)行成功則將狀態(tài)標(biāo)記為 RunTasks
    stage = Stage.RunTasks;
}

這里最后會(huì)將狀態(tài)標(biāo)記為 RunTasks,至此 Gradle 構(gòu)建流程的 RunTasks 就分析完了。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評(píng)論 6 544
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,694評(píng)論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事。” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 178,672評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 63,965評(píng)論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,690評(píng)論 6 413
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 56,019評(píng)論 1 329
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評(píng)論 3 449
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 43,188評(píng)論 0 290
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,718評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,438評(píng)論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,667評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評(píng)論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,845評(píng)論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 35,252評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 36,590評(píng)論 1 295
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,384評(píng)論 3 400
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,635評(píng)論 2 380

推薦閱讀更多精彩內(nèi)容