|
30 | 30 | import static com.google.devtools.mobileharness.shared.util.time.TimeUtils.toProtoTimestamp; |
31 | 31 | import static java.util.Arrays.stream; |
32 | 32 |
|
| 33 | +import com.google.common.annotations.VisibleForTesting; |
| 34 | +import com.google.common.base.Ascii; |
33 | 35 | import com.google.common.collect.ImmutableList; |
34 | 36 | import com.google.common.collect.ImmutableSet; |
35 | 37 | import com.google.common.eventbus.Subscribe; |
|
41 | 43 | import com.google.devtools.mobileharness.api.model.job.out.Result.ResultTypeWithCause; |
42 | 44 | import com.google.devtools.mobileharness.api.model.lab.LabLocator; |
43 | 45 | import com.google.devtools.mobileharness.api.model.proto.Test.TestResult; |
| 46 | +import com.google.devtools.mobileharness.infra.ats.common.SessionHandlerHelper; |
44 | 47 | import com.google.devtools.mobileharness.infra.ats.common.jobcreator.XtsJobCreator; |
45 | 48 | import com.google.devtools.mobileharness.infra.ats.console.controller.proto.SessionPluginProto.AtsSessionCancellation; |
46 | 49 | import com.google.devtools.mobileharness.infra.ats.console.controller.proto.SessionPluginProto.AtsSessionPluginConfig; |
@@ -126,7 +129,7 @@ public class AtsSessionPlugin { |
126 | 129 |
|
127 | 130 | private static final FluentLogger logger = FluentLogger.forEnclosingClass(); |
128 | 131 |
|
129 | | - private static final AtomicInteger NEXT_RUN_COMMAND_ID = new AtomicInteger(1); |
| 132 | + @VisibleForTesting static final AtomicInteger NEXT_RUN_COMMAND_ID = new AtomicInteger(1); |
130 | 133 |
|
131 | 134 | private final Object testCancellationLock = new Object(); |
132 | 135 | private final Object runningTestsLock = new Object(); |
@@ -173,7 +176,13 @@ public class AtsSessionPlugin { |
173 | 176 | /** Set in {@link #onSessionStarting}. */ |
174 | 177 | private volatile AtsSessionPluginConfig config; |
175 | 178 |
|
176 | | - private ImmutableList<JobInfo> nonTradefedJobs = ImmutableList.of(); |
| 179 | + private volatile ImmutableList<JobInfo> tradefedJobs = ImmutableList.of(); |
| 180 | + private volatile ImmutableList<JobInfo> nonTradefedJobs = ImmutableList.of(); |
| 181 | + |
| 182 | + private final Object setupJobLock = new Object(); |
| 183 | + |
| 184 | + @GuardedBy("setupJobLock") |
| 185 | + private Optional<String> runningSetupJobId = Optional.empty(); |
177 | 186 |
|
178 | 187 | @Inject |
179 | 188 | AtsSessionPlugin( |
@@ -293,7 +302,6 @@ public void onSessionStarted(SessionStartedEvent event) |
293 | 302 | runCommandHandler.initialize(runCommand); |
294 | 303 |
|
295 | 304 | // Create tradefed jobs. |
296 | | - ImmutableList<JobInfo> tradefedJobs; |
297 | 305 | try { |
298 | 306 | tradefedJobs = runCommandHandler.createTradefedJobs(runCommand); |
299 | 307 | } catch (MobileHarnessException e) { |
@@ -332,44 +340,12 @@ public void onSessionStarted(SessionStartedEvent event) |
332 | 340 | /* cause= */ null); |
333 | 341 | } |
334 | 342 |
|
335 | | - boolean startedTfJobs = false; |
336 | | - if (tradefedJobs.size() <= 1) { |
337 | | - startedTfJobs = addAndTrackTradefedJobs(tradefedJobs); |
338 | | - } else { |
339 | | - // If there are multiple tradefed jobs, add them to the session sequentially. |
340 | | - // Prioritize static XTS jobs. Other jobs are added to additional tradefed jobs list. |
341 | | - List<JobInfo> staticXtsJobs = new ArrayList<>(); |
342 | | - |
343 | | - synchronized (additionalTradefedJobs) { |
344 | | - tradefedJobs.forEach( |
345 | | - tradefedJob -> { |
346 | | - if (tradefedJob.locator().getName().contains(XtsConstants.STATIC_XTS_JOB_NAME)) { |
347 | | - staticXtsJobs.add(tradefedJob); |
348 | | - } else { |
349 | | - additionalTradefedJobs.add(tradefedJob); |
350 | | - } |
351 | | - }); |
352 | | - } |
| 343 | + Optional<JobInfo> setupJobOpt = nonTradefedJobs.stream().filter(this::isSetupJob).findFirst(); |
353 | 344 |
|
354 | | - if (!staticXtsJobs.isEmpty()) { |
355 | | - startedTfJobs = addAndTrackTradefedJobs(staticXtsJobs); |
356 | | - } else { |
357 | | - // No static XTS jobs found, add the first of the additional jobs. |
358 | | - synchronized (additionalTradefedJobs) { |
359 | | - if (!additionalTradefedJobs.isEmpty()) { |
360 | | - startedTfJobs = |
361 | | - addAndTrackTradefedJobs(ImmutableList.of(additionalTradefedJobs.remove(0))); |
362 | | - } |
363 | | - } |
364 | | - } |
365 | | - } |
366 | | - |
367 | | - if (!startedTfJobs) { |
368 | | - logger.atInfo().log( |
369 | | - "On session [%s] starting, no tradefed job was added, try add non-tradefed jobs if" |
370 | | - + " needed.", |
371 | | - sessionInfo.getSessionId()); |
372 | | - addJobsToSession(nonTradefedJobs); |
| 345 | + if (setupJobOpt.isPresent()) { |
| 346 | + addSetupJob(setupJobOpt.get()); |
| 347 | + } else { |
| 348 | + addMainJobs(); |
373 | 349 | } |
374 | 350 |
|
375 | 351 | // Starts TF runtime info updater. |
@@ -443,8 +419,21 @@ public void onJobEnd(JobEndEvent jobEndEvent) |
443 | 419 | } |
444 | 420 | } |
445 | 421 |
|
| 422 | + String jobId = currentJob.locator().getId(); |
| 423 | + boolean isSetupJobEnd = false; |
| 424 | + synchronized (setupJobLock) { |
| 425 | + if (runningSetupJobId.isPresent() && runningSetupJobId.get().equals(jobId)) { |
| 426 | + runningSetupJobId = Optional.empty(); |
| 427 | + isSetupJobEnd = true; |
| 428 | + } |
| 429 | + } |
| 430 | + if (isSetupJobEnd) { |
| 431 | + logger.atInfo().log("Setup job [%s] ended, starting main jobs.", jobId); |
| 432 | + addMainJobs(); |
| 433 | + return; |
| 434 | + } |
| 435 | + |
446 | 436 | synchronized (runningTradefedJobs) { |
447 | | - String jobId = currentJob.locator().getId(); |
448 | 437 | if (!runningTradefedJobs.containsKey(jobId)) { |
449 | 438 | return; |
450 | 439 | } |
@@ -828,6 +817,78 @@ private void addDeviceIdsToSubDeviceSpecs( |
828 | 817 | } |
829 | 818 | } |
830 | 819 |
|
| 820 | + private boolean isSetupJob(JobInfo jobInfo) { |
| 821 | + return Ascii.equalsIgnoreCase(jobInfo.locator().getName(), XtsConstants.SETUP_JOB_NAME) |
| 822 | + || Ascii.equalsIgnoreCase( |
| 823 | + jobInfo.properties().getOptional(SessionHandlerHelper.XTS_MODULE_NAME_PROP).orElse(""), |
| 824 | + XtsConstants.SETUP_JOB_NAME); |
| 825 | + } |
| 826 | + |
| 827 | + /** |
| 828 | + * Adds the ATS setup job to the session and records its execution ID in {@code |
| 829 | + * runningSetupJobId}. |
| 830 | + */ |
| 831 | + private void addSetupJob(JobInfo setupJob) { |
| 832 | + nonTradefedJobs = |
| 833 | + nonTradefedJobs.stream().filter(job -> !job.equals(setupJob)).collect(toImmutableList()); |
| 834 | + ImmutableList<String> setupJobIds = addJobsToSession(ImmutableList.of(setupJob)); |
| 835 | + if (!setupJobIds.isEmpty()) { |
| 836 | + synchronized (setupJobLock) { |
| 837 | + runningSetupJobId = Optional.of(setupJobIds.get(0)); |
| 838 | + } |
| 839 | + } |
| 840 | + } |
| 841 | + |
| 842 | + /** |
| 843 | + * Adds main Tradefed jobs to the session. |
| 844 | + * |
| 845 | + * <p>If multiple Tradefed jobs exist, they are partitioned: |
| 846 | + * |
| 847 | + * <ul> |
| 848 | + * <li><b>Static xTS jobs</b> are prioritized and added immediately to run concurrently. |
| 849 | + * <li><b>Additional Tradefed jobs</b> are queued in {@code additionalTradefedJobs} to execute |
| 850 | + * sequentially as previous jobs finish in {@link #onJobEnd}. |
| 851 | + * </ul> |
| 852 | + * |
| 853 | + * <p>If no Tradefed jobs could be started, falls back to adding non-Tradefed jobs. |
| 854 | + */ |
| 855 | + private void addMainJobs() { |
| 856 | + boolean startedTfJobs = false; |
| 857 | + if (tradefedJobs.size() <= 1) { |
| 858 | + startedTfJobs = addAndTrackTradefedJobs(tradefedJobs); |
| 859 | + } else { |
| 860 | + List<JobInfo> staticXtsJobs = new ArrayList<>(); |
| 861 | + synchronized (additionalTradefedJobs) { |
| 862 | + tradefedJobs.forEach( |
| 863 | + tradefedJob -> { |
| 864 | + if (tradefedJob.locator().getName().contains(XtsConstants.STATIC_XTS_JOB_NAME)) { |
| 865 | + staticXtsJobs.add(tradefedJob); |
| 866 | + } else { |
| 867 | + additionalTradefedJobs.add(tradefedJob); |
| 868 | + } |
| 869 | + }); |
| 870 | + } |
| 871 | + if (!staticXtsJobs.isEmpty()) { |
| 872 | + startedTfJobs = addAndTrackTradefedJobs(staticXtsJobs); |
| 873 | + } else { |
| 874 | + synchronized (additionalTradefedJobs) { |
| 875 | + if (!additionalTradefedJobs.isEmpty()) { |
| 876 | + startedTfJobs = |
| 877 | + addAndTrackTradefedJobs(ImmutableList.of(additionalTradefedJobs.remove(0))); |
| 878 | + } |
| 879 | + } |
| 880 | + } |
| 881 | + } |
| 882 | + |
| 883 | + if (!startedTfJobs) { |
| 884 | + logger.atInfo().log( |
| 885 | + "On session [%s] starting, no tradefed job was added, try add non-tradefed jobs if" |
| 886 | + + " needed.", |
| 887 | + sessionInfo.getSessionId()); |
| 888 | + addJobsToSession(nonTradefedJobs); |
| 889 | + } |
| 890 | + } |
| 891 | + |
831 | 892 | /** |
832 | 893 | * Adds Tradefed jobs to the session and records them in {@code runningTradefedJobs}. |
833 | 894 | * |
|
0 commit comments