1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.tradefed.invoker; 17 18 import com.android.ddmlib.IDevice; 19 import com.android.ddmlib.Log.LogLevel; 20 import com.android.tradefed.build.BuildInfo; 21 import com.android.tradefed.build.BuildInfoKey.BuildInfoFileKey; 22 import com.android.tradefed.build.BuildRetrievalError; 23 import com.android.tradefed.build.IBuildInfo; 24 import com.android.tradefed.build.IBuildInfo.BuildInfoProperties; 25 import com.android.tradefed.build.IBuildProvider; 26 import com.android.tradefed.build.IDeviceBuildInfo; 27 import com.android.tradefed.build.IDeviceBuildProvider; 28 import com.android.tradefed.command.ICommandOptions; 29 import com.android.tradefed.config.GlobalConfiguration; 30 import com.android.tradefed.config.IConfiguration; 31 import com.android.tradefed.config.IConfigurationReceiver; 32 import com.android.tradefed.config.IDeviceConfiguration; 33 import com.android.tradefed.config.filter.GetPreviousPassedHelper; 34 import com.android.tradefed.device.DeviceNotAvailableException; 35 import com.android.tradefed.device.ITestDevice; 36 import com.android.tradefed.device.NativeDevice; 37 import com.android.tradefed.device.StubDevice; 38 import com.android.tradefed.device.cloud.GceAvdInfo; 39 import com.android.tradefed.device.cloud.GceManager; 40 import com.android.tradefed.device.cloud.OxygenUtil; 41 import com.android.tradefed.device.metric.AutoLogCollector; 42 import com.android.tradefed.device.metric.CollectorHelper; 43 import com.android.tradefed.device.metric.CountTestCasesCollector; 44 import com.android.tradefed.device.metric.IMetricCollector; 45 import com.android.tradefed.device.metric.IMetricCollectorReceiver; 46 import com.android.tradefed.error.HarnessRuntimeException; 47 import com.android.tradefed.invoker.ExecutionFiles.FilesKey; 48 import com.android.tradefed.invoker.TestInvocation.Stage; 49 import com.android.tradefed.invoker.logger.CurrentInvocation; 50 import com.android.tradefed.invoker.logger.CurrentInvocation.IsolationGrade; 51 import com.android.tradefed.invoker.logger.InvocationMetricLogger; 52 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationGroupMetricKey; 53 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey; 54 import com.android.tradefed.invoker.logger.TfObjectTracker; 55 import com.android.tradefed.invoker.shard.IShardHelper; 56 import com.android.tradefed.invoker.shard.TestsPoolPoller; 57 import com.android.tradefed.invoker.tracing.CloseableTraceScope; 58 import com.android.tradefed.log.ITestLogger; 59 import com.android.tradefed.log.LogUtil.CLog; 60 import com.android.tradefed.result.ByteArrayInputStreamSource; 61 import com.android.tradefed.result.ITestInvocationListener; 62 import com.android.tradefed.result.ITestLoggerReceiver; 63 import com.android.tradefed.result.InputStreamSource; 64 import com.android.tradefed.result.LogDataType; 65 import com.android.tradefed.result.error.TestErrorIdentifier; 66 import com.android.tradefed.retry.IRetryDecision; 67 import com.android.tradefed.retry.RetryLogSaverResultForwarder; 68 import com.android.tradefed.retry.RetryStatistics; 69 import com.android.tradefed.retry.RetryStrategy; 70 import com.android.tradefed.suite.checker.ISystemStatusCheckerReceiver; 71 import com.android.tradefed.targetprep.BuildError; 72 import com.android.tradefed.targetprep.IHostCleaner; 73 import com.android.tradefed.targetprep.ILabPreparer; 74 import com.android.tradefed.targetprep.ITargetPreparer; 75 import com.android.tradefed.targetprep.TargetSetupError; 76 import com.android.tradefed.targetprep.multi.IMultiTargetPreparer; 77 import com.android.tradefed.testtype.IBuildReceiver; 78 import com.android.tradefed.testtype.IDeviceTest; 79 import com.android.tradefed.testtype.IInvocationContextReceiver; 80 import com.android.tradefed.testtype.IRemoteTest; 81 import com.android.tradefed.testtype.ITestFilterReceiver; 82 import com.android.tradefed.testtype.retry.IAutoRetriableTest; 83 import com.android.tradefed.testtype.suite.BaseTestSuite; 84 import com.android.tradefed.testtype.suite.ITestSuite; 85 import com.android.tradefed.testtype.suite.ModuleListener; 86 import com.android.tradefed.util.CommandResult; 87 import com.android.tradefed.util.CommandStatus; 88 import com.android.tradefed.util.FileUtil; 89 import com.android.tradefed.util.PrettyPrintDelimiter; 90 import com.android.tradefed.util.RunInterruptedException; 91 import com.android.tradefed.util.RunUtil; 92 import com.android.tradefed.util.SystemUtil; 93 import com.android.tradefed.util.SystemUtil.EnvVariable; 94 import com.android.tradefed.util.TimeUtil; 95 import com.android.tradefed.util.executor.ParallelDeviceExecutor; 96 97 import com.google.common.annotations.VisibleForTesting; 98 import com.google.common.base.Strings; 99 100 import java.io.File; 101 import java.io.IOException; 102 import java.time.Duration; 103 import java.util.ArrayList; 104 import java.util.HashSet; 105 import java.util.List; 106 import java.util.ListIterator; 107 import java.util.Map; 108 import java.util.Set; 109 import java.util.Timer; 110 import java.util.TimerTask; 111 import java.util.concurrent.Callable; 112 import java.util.concurrent.ConcurrentHashMap; 113 import java.util.concurrent.TimeUnit; 114 115 /** 116 * Class that describes all the invocation steps: build download, target_prep, run tests, clean up. 117 * Can be extended to override the default behavior of some steps. Order of the steps is driven by 118 * {@link TestInvocation}. 119 */ 120 public class InvocationExecution implements IInvocationExecution { 121 122 public static final String ADB_VERSION_KEY = "adb_version"; 123 public static final String JAVA_VERSION_KEY = "java_version"; 124 public static final String JAVA_CLASSPATH_KEY = "java_classpath"; 125 // Track which preparer ran in setup to ensure we don't trigger tearDown if setup was skipped. 126 private Set<IMultiTargetPreparer> mTrackMultiPreparers = null; 127 private Map<String, Set<ITargetPreparer>> mTrackLabPreparers = null; 128 private Map<String, Set<ITargetPreparer>> mTrackTargetPreparers = null; 129 // GceManager for multi-device leasing. It's needed for releasing the devices. 130 private GceManager mMultiDeviceRequester = null; 131 132 /** Timer to make sure Test Phase does not run for too long. */ 133 private class TestPhaseMonitor extends TimerTask { 134 135 private TestThread mTestThread; 136 TestPhaseMonitor(TestThread toMonitor)137 public TestPhaseMonitor(TestThread toMonitor) { 138 mTestThread = toMonitor; 139 } 140 141 @Override run()142 public void run() { 143 if (mTestThread != null) { 144 mTestThread.stopTestThread(); 145 } 146 } 147 } 148 149 /** A Thread to execute {@link IRemoteTest} */ 150 private class TestThread extends Thread { 151 private TestInformation mTestInfo; 152 private ITestInvocationListener mTestListener; 153 private IRemoteTest mTest; 154 private Throwable lastThrownException; 155 TestThread( TestInformation info, ITestInvocationListener listener, IRemoteTest test)156 public TestThread( 157 TestInformation info, ITestInvocationListener listener, IRemoteTest test) { 158 mTestInfo = info; 159 mTestListener = listener; 160 mTest = test; 161 } 162 163 @Override run()164 public void run() { 165 try { 166 mTest.run(mTestInfo, mTestListener); 167 } catch (Exception e) { 168 lastThrownException = e; 169 } 170 } 171 getLastThrownException()172 public Throwable getLastThrownException() { 173 return lastThrownException; 174 } 175 stopTestThread()176 public void stopTestThread() { 177 this.interrupt(); 178 mTestInfo.notifyTimeout(); 179 // record this interrupt as an exception so that TestInvocation thread can throw this. 180 lastThrownException = 181 new RunInterruptedException( 182 "Test Phase Timeout Reached.", 183 TestErrorIdentifier.TEST_PHASE_TIMED_OUT); 184 } 185 } 186 187 @Override fetchBuild( TestInformation testInfo, IConfiguration config, IRescheduler rescheduler, ITestInvocationListener listener)188 public boolean fetchBuild( 189 TestInformation testInfo, 190 IConfiguration config, 191 IRescheduler rescheduler, 192 ITestInvocationListener listener) 193 throws DeviceNotAvailableException, BuildRetrievalError { 194 String currentDeviceName = null; 195 IBuildInfo buildReplicat = null; 196 try { 197 // TODO: evaluate fetching build in parallel 198 for (int i = 0; i < testInfo.getContext().getDeviceConfigNames().size(); i++) { 199 currentDeviceName = testInfo.getContext().getDeviceConfigNames().get(i); 200 if (buildReplicat != null) { 201 // TODO: evaluate if cloning the build is needed 202 testInfo.getContext().addDeviceBuildInfo(currentDeviceName, buildReplicat); 203 continue; 204 } 205 IBuildInfo info = null; 206 ITestDevice device = testInfo.getContext().getDevice(currentDeviceName); 207 IDeviceConfiguration deviceConfig = config.getDeviceConfigByName(currentDeviceName); 208 IBuildProvider provider = deviceConfig.getBuildProvider(); 209 TfObjectTracker.countWithParents(provider.getClass()); 210 // Inject the context to the provider if it can receive it 211 if (provider instanceof IInvocationContextReceiver) { 212 ((IInvocationContextReceiver) provider) 213 .setInvocationContext(testInfo.getContext()); 214 } 215 if (provider instanceof ITestLoggerReceiver) { 216 ((ITestLoggerReceiver) provider).setTestLogger(listener); 217 } 218 // Get the build 219 if (provider instanceof IDeviceBuildProvider) { 220 // Download a device build if the provider can handle it. 221 info = ((IDeviceBuildProvider) provider).getBuild(device); 222 } else { 223 info = provider.getBuild(); 224 } 225 if (info != null) { 226 info.setDeviceSerial(device.getSerialNumber()); 227 testInfo.getContext().addDeviceBuildInfo(currentDeviceName, info); 228 device.setRecovery(deviceConfig.getDeviceRecovery()); 229 } else { 230 CLog.logAndDisplay( 231 LogLevel.WARN, 232 "No build found to test for device: %s", 233 device.getSerialNumber()); 234 IBuildInfo notFoundStub = new BuildInfo(); 235 updateBuild(notFoundStub, config); 236 testInfo.getContext().addDeviceBuildInfo(currentDeviceName, notFoundStub); 237 return false; 238 } 239 // TODO: remove build update when reporting is done on context 240 updateBuild(info, config); 241 linkExternalDirs(info, testInfo); 242 243 if (config.getCommandOptions().shouldUseReplicateSetup()) { 244 buildReplicat = info; 245 } 246 } 247 } catch (BuildRetrievalError e) { 248 CLog.e(e); 249 if (currentDeviceName != null) { 250 IBuildInfo errorBuild = e.getBuildInfo(); 251 updateBuild(errorBuild, config); 252 testInfo.getContext().addDeviceBuildInfo(currentDeviceName, errorBuild); 253 } 254 throw e; 255 } catch (RuntimeException re) { 256 if (currentDeviceName != null) { 257 IBuildInfo errorBuild = 258 TestInvocation.backFillBuildInfoForReporting(config.getCommandLine()); 259 updateBuild(errorBuild, config); 260 testInfo.getContext().addDeviceBuildInfo(currentDeviceName, errorBuild); 261 } 262 throw re; 263 } 264 setBinariesVersion(testInfo.getContext()); 265 copyRemoteFiles(config.getCommandOptions(), testInfo.getBuildInfo()); 266 return true; 267 } 268 269 @Override cleanUpBuilds(IInvocationContext context, IConfiguration config)270 public void cleanUpBuilds(IInvocationContext context, IConfiguration config) { 271 // Ensure build infos are always cleaned up at the end of invocation. 272 for (String cleanUpDevice : context.getDeviceConfigNames()) { 273 if (context.getBuildInfo(cleanUpDevice) != null) { 274 try { 275 config.getDeviceConfigByName(cleanUpDevice) 276 .getBuildProvider() 277 .cleanUp(context.getBuildInfo(cleanUpDevice)); 278 } catch (RuntimeException e) { 279 // We catch an simply log exception in cleanUp to avoid missing any final 280 // step of the invocation. 281 CLog.e(e); 282 } 283 } 284 } 285 } 286 287 @Override shardConfig( IConfiguration config, TestInformation testInfo, IRescheduler rescheduler, ITestLogger logger)288 public boolean shardConfig( 289 IConfiguration config, 290 TestInformation testInfo, 291 IRescheduler rescheduler, 292 ITestLogger logger) { 293 IShardHelper helper = createShardHelper(); 294 CLog.d("IShardHelper selected: %s", helper); 295 return helper.shardConfig(config, testInfo, rescheduler, logger); 296 } 297 298 /** Create an return the {@link IShardHelper} to be used. */ 299 @VisibleForTesting createShardHelper()300 protected IShardHelper createShardHelper() { 301 return GlobalConfiguration.getInstance().getShardingStrategy(); 302 } 303 304 /** 305 * Retrieve a list of target preparers to run on this device. 306 * 307 * <p>Overridden in sandbox classes to restrict lab preparers from being run inside the sandbox 308 * child 309 */ getTargetPreparersToRun( IConfiguration config, String deviceName)310 protected List<ITargetPreparer> getTargetPreparersToRun( 311 IConfiguration config, String deviceName) { 312 List<ITargetPreparer> preparersToRun = new ArrayList<>(); 313 preparersToRun.addAll(config.getDeviceConfigByName(deviceName).getTargetPreparers()); 314 return preparersToRun; 315 } 316 317 /** 318 * Retrieve a list of lab preparers to run on this device. 319 * 320 * <p>Overridden in sandbox classes to restrict lab preparers from being run inside the sandbox 321 * child 322 */ getLabPreparersToRun(IConfiguration config, String deviceName)323 protected List<ITargetPreparer> getLabPreparersToRun(IConfiguration config, String deviceName) { 324 List<ITargetPreparer> preparersToRun = new ArrayList<>(); 325 preparersToRun.addAll(config.getDeviceConfigByName(deviceName).getLabPreparers()); 326 return preparersToRun; 327 } 328 329 @Override doSetup(TestInformation testInfo, IConfiguration config, final ITestLogger listener)330 public void doSetup(TestInformation testInfo, IConfiguration config, final ITestLogger listener) 331 throws TargetSetupError, BuildError, DeviceNotAvailableException { 332 long start = System.currentTimeMillis(); 333 mTrackLabPreparers = new ConcurrentHashMap<>(); 334 mTrackTargetPreparers = new ConcurrentHashMap<>(); 335 InvocationMetricLogger.addInvocationMetrics(InvocationMetricKey.SETUP_START, start); 336 337 for (String deviceName : testInfo.getContext().getDeviceConfigNames()) { 338 ITestDevice device = testInfo.getContext().getDevice(deviceName); 339 CLog.d("Starting setup for device: '%s'", device.getSerialNumber()); 340 if (device instanceof ITestLoggerReceiver) { 341 ((ITestLoggerReceiver) testInfo.getContext().getDevice(deviceName)) 342 .setTestLogger(listener); 343 } 344 mTrackLabPreparers.put(deviceName, new HashSet<>()); 345 mTrackTargetPreparers.put(deviceName, new HashSet<>()); 346 } 347 try { 348 try (CloseableTraceScope ignored = 349 new CloseableTraceScope(InvocationMetricKey.pre_multi_preparer.name())) { 350 // Before all the individual setup, make the multi-pre-target-preparer devices setup 351 runMultiTargetPreparers( 352 config.getMultiPreTargetPreparers(), 353 listener, 354 testInfo, 355 "multi pre target preparer setup"); 356 } finally { 357 long end = System.currentTimeMillis(); 358 // Pre-multi-preparer are test specific and account toward test setup 359 InvocationMetricLogger.addInvocationPairMetrics( 360 InvocationMetricKey.TEST_SETUP_PAIR, start, end); 361 } 362 start = System.currentTimeMillis(); 363 try (CloseableTraceScope ignored = 364 new CloseableTraceScope(InvocationMetricKey.lab_setup.name())) { 365 runLabPreparersSetup(testInfo, config, listener); 366 } finally { 367 long end = System.currentTimeMillis(); 368 InvocationMetricLogger.addInvocationMetrics(InvocationMetricKey.SETUP_END, end); 369 InvocationMetricLogger.addInvocationPairMetrics( 370 InvocationMetricKey.SETUP_PAIR, start, end); 371 } 372 long startPreparer = System.currentTimeMillis(); 373 try (CloseableTraceScope ignored = 374 new CloseableTraceScope(InvocationMetricKey.test_setup.name())) { 375 runPreparersSetup(testInfo, config, listener); 376 377 // After all the individual setup, make the multi-devices setup 378 runMultiTargetPreparers( 379 config.getMultiTargetPreparers(), 380 listener, 381 testInfo, 382 "multi target preparer setup"); 383 // Collect some info automatically after setup 384 collectAutoInfo(config, testInfo); 385 } finally { 386 // Note: These metrics are handled in a try in case of a kernel reset or device 387 // issue. 388 // Setup timing metric. It does not include flashing time on boot tests. 389 long end = System.currentTimeMillis(); 390 InvocationMetricLogger.addInvocationPairMetrics( 391 InvocationMetricKey.TEST_SETUP_PAIR, startPreparer, end); 392 long setupDuration = end - start; 393 InvocationMetricLogger.addInvocationMetrics( 394 InvocationMetricKey.SETUP, setupDuration); 395 CLog.d("Total setup duration: %s'", TimeUtil.formatElapsedTime(setupDuration)); 396 } 397 } finally { 398 // Upload the setup logcat after setup is complete. 399 for (ITestDevice device : testInfo.getDevices()) { 400 reportLogs(device, listener, Stage.SETUP); 401 } 402 } 403 } 404 runLabPreparersSetup( TestInformation testInfo, IConfiguration config, ITestLogger listener)405 private void runLabPreparersSetup( 406 TestInformation testInfo, IConfiguration config, ITestLogger listener) 407 throws TargetSetupError, BuildError, DeviceNotAvailableException { 408 int index = 0; 409 if ((config.getCommandOptions().shouldUseParallelSetup() 410 || config.getCommandOptions().shouldUseReplicateSetup()) 411 && config.getDeviceConfig().size() > 1) { 412 CLog.d("Using parallel setup."); 413 ParallelDeviceExecutor<Boolean> executor = 414 new ParallelDeviceExecutor<>(testInfo.getContext().getDevices().size()); 415 List<Callable<Boolean>> callableTasks = new ArrayList<>(); 416 for (String deviceName : testInfo.getContext().getDeviceConfigNames()) { 417 final int deviceIndex = index; 418 // Replicate TestInfo 419 TestInformation replicated = 420 TestInformation.createModuleTestInfo(testInfo, testInfo.getContext()); 421 Callable<Boolean> callableTask = 422 () -> { 423 // Lab preparer then target preparer 424 runLabPreparationOnDevice( 425 replicated, 426 deviceName, 427 deviceIndex, 428 getLabPreparersToRun(config, deviceName), 429 mTrackLabPreparers.get(deviceName), 430 listener); 431 return true; 432 }; 433 callableTasks.add(callableTask); 434 index++; 435 } 436 Duration timeout = config.getCommandOptions().getParallelSetupTimeout(); 437 executor.invokeAll(callableTasks, timeout.toMillis(), TimeUnit.MILLISECONDS); 438 if (executor.hasErrors()) { 439 List<Throwable> errors = executor.getErrors(); 440 // TODO: Handle throwing multi-exceptions, right now throw the first one. 441 for (Throwable error : errors) { 442 if (error instanceof TargetSetupError) { 443 throw (TargetSetupError) error; 444 } 445 if (error instanceof BuildError) { 446 throw (BuildError) error; 447 } 448 if (error instanceof DeviceNotAvailableException) { 449 throw (DeviceNotAvailableException) error; 450 } 451 if (error instanceof HarnessRuntimeException) { 452 throw (HarnessRuntimeException) error; 453 } 454 throw new RuntimeException(error); 455 } 456 } 457 } else { 458 for (String deviceName : testInfo.getContext().getDeviceConfigNames()) { 459 // Lab preparer then target preparer 460 runLabPreparationOnDevice( 461 testInfo, 462 deviceName, 463 index, 464 getLabPreparersToRun(config, deviceName), 465 mTrackLabPreparers.get(deviceName), 466 listener); 467 index++; 468 } 469 } 470 } 471 runPreparersSetup( TestInformation testInfo, IConfiguration config, ITestLogger listener)472 private void runPreparersSetup( 473 TestInformation testInfo, IConfiguration config, ITestLogger listener) 474 throws TargetSetupError, BuildError, DeviceNotAvailableException { 475 int index = 0; 476 if ((config.getCommandOptions().shouldUseParallelSetup() 477 || config.getCommandOptions().shouldUseReplicateSetup()) 478 && config.getDeviceConfig().size() > 1) { 479 CLog.d("Using parallel setup."); 480 ParallelDeviceExecutor<Boolean> executor = 481 new ParallelDeviceExecutor<>(testInfo.getContext().getDevices().size()); 482 List<Callable<Boolean>> callableTasks = new ArrayList<>(); 483 for (String deviceName : testInfo.getContext().getDeviceConfigNames()) { 484 final int deviceIndex = index; 485 // Replicate TestInfo 486 TestInformation replicated = 487 TestInformation.createModuleTestInfo(testInfo, testInfo.getContext()); 488 Callable<Boolean> callableTask = 489 () -> { 490 runPreparationOnDevice( 491 replicated, 492 deviceName, 493 deviceIndex, 494 getTargetPreparersToRun(config, deviceName), 495 mTrackTargetPreparers.get(deviceName), 496 listener); 497 return true; 498 }; 499 callableTasks.add(callableTask); 500 index++; 501 } 502 Duration timeout = config.getCommandOptions().getParallelSetupTimeout(); 503 executor.invokeAll(callableTasks, timeout.toMillis(), TimeUnit.MILLISECONDS); 504 if (executor.hasErrors()) { 505 List<Throwable> errors = executor.getErrors(); 506 // TODO: Handle throwing multi-exceptions, right now throw the first one. 507 for (Throwable error : errors) { 508 if (error instanceof TargetSetupError) { 509 throw (TargetSetupError) error; 510 } 511 if (error instanceof BuildError) { 512 throw (BuildError) error; 513 } 514 if (error instanceof DeviceNotAvailableException) { 515 throw (DeviceNotAvailableException) error; 516 } 517 throw new RuntimeException(error); 518 } 519 } 520 } else { 521 for (String deviceName : testInfo.getContext().getDeviceConfigNames()) { 522 runPreparationOnDevice( 523 testInfo, 524 deviceName, 525 index, 526 getTargetPreparersToRun(config, deviceName), 527 mTrackTargetPreparers.get(deviceName), 528 listener); 529 index++; 530 } 531 } 532 } 533 runLabPreparationOnDevice( TestInformation testInfo, String deviceName, int index, List<ITargetPreparer> labPreparersToRun, Set<ITargetPreparer> trackLabPreparers, ITestLogger logger)534 private void runLabPreparationOnDevice( 535 TestInformation testInfo, 536 String deviceName, 537 int index, 538 List<ITargetPreparer> labPreparersToRun, 539 Set<ITargetPreparer> trackLabPreparers, 540 ITestLogger logger) 541 throws TargetSetupError, BuildError, DeviceNotAvailableException { 542 ITestDevice device = testInfo.getContext().getDevice(deviceName); 543 544 // Run lab preparers on the device 545 for (ITargetPreparer preparer : labPreparersToRun) { 546 if (preparer.isDisabled()) { 547 CLog.d("%s has been disabled. skipping.", preparer); 548 continue; 549 } 550 // Track object invoked as lab_preparer that are not ILabPreparer 551 if (!(preparer instanceof ILabPreparer)) { 552 InvocationMetricLogger.addInvocationMetrics( 553 InvocationMetricKey.LAB_PREPARER_NOT_ILAB, 554 preparer.getClass().getCanonicalName()); 555 } 556 557 TfObjectTracker.countWithParents(preparer.getClass()); 558 if (preparer instanceof ITestLoggerReceiver) { 559 ((ITestLoggerReceiver) preparer).setTestLogger(logger); 560 } 561 562 long startTime = System.currentTimeMillis(); 563 CLog.d( 564 "starting lab preparer '%s' on device: '%s'", 565 preparer, device.getSerialNumber()); 566 try (CloseableTraceScope ignore = 567 new CloseableTraceScope(preparer.getClass().getSimpleName())) { 568 testInfo.setActiveDeviceIndex(index); 569 preparer.setUp(testInfo); 570 } finally { 571 testInfo.setActiveDeviceIndex(0); 572 long elapsedTime = System.currentTimeMillis() - startTime; 573 574 CLog.d( 575 "done with lab preparer '%s' on device: '%s' in %s", 576 preparer, 577 device.getSerialNumber(), 578 TimeUtil.formatElapsedTime(elapsedTime)); 579 580 InvocationMetricLogger.addInvocationMetrics( 581 InvocationGroupMetricKey.LAB_PREPARER_SETUP_LATENCY, 582 preparer.getClass().getName(), 583 elapsedTime); 584 } 585 // Track which lab preparers were executed separately from the target preparers 586 trackLabPreparers.add(preparer); 587 } 588 } 589 runPreparationOnDevice( TestInformation testInfo, String deviceName, int index, List<ITargetPreparer> targetPreparersToRun, Set<ITargetPreparer> trackPreparers, ITestLogger logger)590 private void runPreparationOnDevice( 591 TestInformation testInfo, 592 String deviceName, 593 int index, 594 List<ITargetPreparer> targetPreparersToRun, 595 Set<ITargetPreparer> trackPreparers, 596 ITestLogger logger) 597 throws TargetSetupError, BuildError, DeviceNotAvailableException { 598 ITestDevice device = testInfo.getContext().getDevice(deviceName); 599 for (ITargetPreparer preparer : targetPreparersToRun) { 600 if (preparer.isDisabled()) { 601 CLog.d("%s has been disabled. skipping.", preparer); 602 continue; 603 } 604 // Track object invoked as target_preparer but is ILabPreparer 605 if (preparer instanceof ILabPreparer) { 606 InvocationMetricLogger.addInvocationMetrics( 607 InvocationMetricKey.TARGET_PREPARER_IS_ILAB, 608 preparer.getClass().getCanonicalName()); 609 } 610 611 TfObjectTracker.countWithParents(preparer.getClass()); 612 if (preparer instanceof ITestLoggerReceiver) { 613 ((ITestLoggerReceiver) preparer).setTestLogger(logger); 614 } 615 616 long startTime = System.currentTimeMillis(); 617 CLog.d("starting preparer '%s' on device: '%s'", preparer, device.getSerialNumber()); 618 try (CloseableTraceScope ignore = 619 new CloseableTraceScope(preparer.getClass().getSimpleName())) { 620 testInfo.setActiveDeviceIndex(index); 621 preparer.setUp(testInfo); 622 } finally { 623 testInfo.setActiveDeviceIndex(0); 624 } 625 626 trackPreparers.add(preparer); 627 long elapsedTime = System.currentTimeMillis() - startTime; 628 629 CLog.d( 630 "done with preparer '%s' on device: '%s' in %s", 631 preparer, device.getSerialNumber(), TimeUtil.formatElapsedTime(elapsedTime)); 632 633 InvocationMetricLogger.addInvocationMetrics( 634 InvocationGroupMetricKey.TARGET_PREPARER_SETUP_LATENCY, 635 preparer.getClass().getName(), 636 elapsedTime); 637 } 638 639 CLog.d("Done with setup of device: '%s'", device.getSerialNumber()); 640 } 641 642 /** {@inheritDoc} */ 643 @Override runDevicePreInvocationSetup( IInvocationContext context, IConfiguration config, ITestLogger logger)644 public void runDevicePreInvocationSetup( 645 IInvocationContext context, IConfiguration config, ITestLogger logger) 646 throws DeviceNotAvailableException, TargetSetupError { 647 if (config.getCommandOptions().shouldDisableInvocationSetupAndTeardown()) { 648 CLog.i("--disable-invocation-setup-and-teardown, skipping pre-invocation setup."); 649 return; 650 } 651 long start = System.currentTimeMillis(); 652 customizeDevicePreInvocation(config, context); 653 654 // Multi-device test scenario 655 Integer multiDeviceCount = config.getCommandOptions().getMultiDeviceCount(); 656 boolean allVirtualDevices = true; 657 for (IDeviceConfiguration deviceConfig : config.getDeviceConfig()) { 658 if (!deviceConfig.getDeviceRequirements().gceDeviceRequested()) { 659 allVirtualDevices = false; 660 break; 661 } 662 } 663 if (multiDeviceCount != null && multiDeviceCount != 1 && allVirtualDevices) { 664 try (CloseableTraceScope ignore = 665 new CloseableTraceScope("runMultiVirtualDevicesPreInvocationSetup")) { 666 runMultiVirtualDevicesPreInvocationSetup(context, config, logger); 667 } catch (TargetSetupError e) { 668 // TODO(b/353826394): Refactor when avd_util wrapping is ready. 669 if (context.getDevices().get(0).getOptions().useCvdCF()) { 670 // TODO(b/353649277): Flesh out this section when it's ready. 671 // Basically, the rough processes to pull CF host logs are 672 // 1. establish the CURL connection via LHP or SSH. 673 // 2. Compose CURL command and execute it to pull CF logs. 674 } else { 675 OxygenUtil util = new OxygenUtil(); 676 util.downloadLaunchFailureLogs(e, logger); 677 } 678 throw e; 679 } 680 } else { 681 try (CloseableTraceScope ignore = 682 new CloseableTraceScope("device_pre_invocation_setup")) { 683 List<String> deviceNames = context.getDeviceConfigNames(); 684 if (config.getCommandOptions().shouldUseParallelPreInvocationSetup() 685 && deviceNames.size() > 1) { 686 CLog.d("Using parallel preInvocationSetup."); 687 List<Callable<Void>> callableTasks = new ArrayList<>(); 688 for (String deviceName : deviceNames) { 689 callableTasks.add( 690 () -> { 691 runSingleDevicePreInvocationSetup( 692 deviceName, context, config, logger); 693 return null; 694 }); 695 } 696 // The threads are also controlled by 697 // host_options:concurrent-virtual-device-startup-limit. 698 ParallelDeviceExecutor<Void> executor = 699 new ParallelDeviceExecutor<>(callableTasks.size()); 700 executor.invokeAll( 701 callableTasks, 702 config.getCommandOptions() 703 .getParallelPreInvocationSetupTimeout() 704 .toMillis(), 705 TimeUnit.MILLISECONDS); 706 // TODO: Handle throwing multi-exceptions, right now throw the first one. 707 for (Throwable error : executor.getErrors()) { 708 if (error instanceof DeviceNotAvailableException) { 709 throw (DeviceNotAvailableException) error; 710 } 711 if (error instanceof TargetSetupError) { 712 throw (TargetSetupError) error; 713 } 714 throw new RuntimeException(error); 715 } 716 } else { 717 if (config.getCommandOptions().shouldUseParallelPreInvocationSetup()) { 718 CLog.w("Parallel pre-invocation setup is enabled but device count <= 1."); 719 } 720 for (String deviceName : deviceNames) { 721 runSingleDevicePreInvocationSetup(deviceName, context, config, logger); 722 } 723 } 724 } 725 } 726 // Also report device pre invocation into setup 727 InvocationMetricLogger.addInvocationPairMetrics( 728 InvocationMetricKey.SETUP_PAIR, start, System.currentTimeMillis()); 729 } 730 731 /** 732 * Launch multiple virtual devices together, then invoke the {@link 733 * ITestDevice#preInvocationSetup(IBuildInfo)} for each device part of the invocation with 734 * setting the GceAvdInfo of the device beforehand. 735 * 736 * @param context the {@link IInvocationContext} of the invocation. 737 * @param config the {@link IConfiguration} of this test run. 738 * @param logger the {@link ITestLogger} to report logs. 739 * @throws DeviceNotAvailableException 740 * @throws TargetSetupError 741 */ runMultiVirtualDevicesPreInvocationSetup( IInvocationContext context, IConfiguration config, ITestLogger logger)742 private void runMultiVirtualDevicesPreInvocationSetup( 743 IInvocationContext context, IConfiguration config, ITestLogger logger) 744 throws TargetSetupError, DeviceNotAvailableException { 745 // One GceManager is needed to lease the whole device group 746 String firstDeviceName = context.getDeviceConfigNames().get(0); 747 ITestDevice firstDevice = context.getDevice(firstDeviceName); 748 mMultiDeviceRequester = 749 new GceManager( 750 firstDevice.getDeviceDescriptor(), 751 firstDevice.getOptions(), 752 context.getBuildInfo(firstDeviceName)); 753 754 List<ITestDevice> devices = context.getDevices(); 755 List<IBuildInfo> buildInfos = context.getBuildInfos(); 756 // Set logger on all devices first 757 for (ITestDevice device : devices) { 758 if (device instanceof ITestLoggerReceiver) { 759 ((ITestLoggerReceiver) device).setTestLogger(logger); 760 } 761 } 762 763 // Start multiple devices in a group 764 List<GceAvdInfo> gceAvdInfoList = 765 mMultiDeviceRequester.startMultiDevicesGce(buildInfos, context.getAttributes()); 766 for (int i = 0; i < devices.size(); i++) { 767 // For each device, do setup with its GceAvdInfo 768 CLog.d( 769 "Starting device pre invocation launched device setup with GceAvdInfo %s" 770 + " for : '%s'", 771 gceAvdInfoList.get(i), devices.get(i).getSerialNumber()); 772 // Use the most common basic interface for device connection setup 773 NativeDevice device = (NativeDevice) devices.get(i); 774 775 device.setConnectionAvdInfo(gceAvdInfoList.get(i)); 776 device.preInvocationSetup(buildInfos.get(i), context.getAttributes()); 777 778 // Last device in the group is responsible for releasing the whole device group 779 if (i != devices.size() - 1) { 780 CLog.d( 781 "Set device %s to skip tear down because only the last device in the" 782 + " device group will be responsible for tearing down the whole" 783 + " device group", 784 device.getSerialNumber()); 785 device.getOptions().setSkipTearDown(true); 786 } 787 } 788 } 789 790 /** 791 * Run preInvocationSetup for one device. 792 * 793 * @param deviceName the name of the device to be set up. 794 * @param context the {@link IInvocationContext} of the invocation. 795 * @param config the {@link IConfiguration} of this test run. 796 * @param logger the {@link ITestLogger} to report logs. 797 * @throws DeviceNotAvailableException 798 * @throws TargetSetupError 799 */ runSingleDevicePreInvocationSetup( String deviceName, IInvocationContext context, IConfiguration config, ITestLogger logger)800 private void runSingleDevicePreInvocationSetup( 801 String deviceName, 802 IInvocationContext context, 803 IConfiguration config, 804 ITestLogger logger) 805 throws DeviceNotAvailableException, TargetSetupError { 806 ITestDevice device = context.getDevice(deviceName); 807 CLog.d("Starting device pre invocation setup for : '%s'", device.getSerialNumber()); 808 if (device instanceof ITestLoggerReceiver) { 809 ((ITestLoggerReceiver) context.getDevice(deviceName)).setTestLogger(logger); 810 } 811 IDeviceConfiguration deviceConfig = config.getDeviceConfigByName(deviceName); 812 if (deviceConfig != null && deviceConfig.isFake()) { 813 CLog.d("Skip preInvocationSetup on fake device %s", device); 814 } else { 815 device.preInvocationSetup(context.getBuildInfo(deviceName), context.getAttributes()); 816 } 817 } 818 819 /** 820 * Give a chance to customize some of the device before preInvocationSetup. 821 * 822 * @param config The config of the invocation. 823 * @param context The current invocation context. 824 */ customizeDevicePreInvocation(IConfiguration config, IInvocationContext context)825 protected void customizeDevicePreInvocation(IConfiguration config, IInvocationContext context) { 826 // Empty by default 827 } 828 829 /** {@inheritDoc} */ 830 @Override runDevicePostInvocationTearDown( IInvocationContext context, IConfiguration config, Throwable exception)831 public void runDevicePostInvocationTearDown( 832 IInvocationContext context, IConfiguration config, Throwable exception) { 833 // Extra tear down step for the device 834 if (config.getCommandOptions().shouldDisableInvocationSetupAndTeardown()) { 835 CLog.i("--disable-invocation-setup-and-teardown, skipping post-invocation teardown."); 836 return; 837 } 838 // Check if device tear down is needed for multi-device tests. 839 boolean shouldTearDown = false; 840 for (String deviceName : context.getDeviceConfigNames()) { 841 ITestDevice device = context.getDevice(deviceName); 842 IDeviceConfiguration deviceConfig = config.getDeviceConfigByName(deviceName); 843 if (deviceConfig != null && deviceConfig.isFake()) { 844 CLog.d("Skip postInvocationTearDown on fake device %s", device); 845 continue; 846 } 847 // For multi-device tests, only the last device is flagged to be tear down if needed. 848 shouldTearDown |= !device.getOptions().shouldSkipTearDown(); 849 device.postInvocationTearDown(exception); 850 } 851 if (mMultiDeviceRequester != null && shouldTearDown) { 852 mMultiDeviceRequester.shutdownGce(); 853 } 854 } 855 856 /** Runs the {@link IMultiTargetPreparer} specified. */ runMultiTargetPreparers( List<IMultiTargetPreparer> multiPreparers, ITestLogger logger, TestInformation testInfo, String description)857 private void runMultiTargetPreparers( 858 List<IMultiTargetPreparer> multiPreparers, 859 ITestLogger logger, 860 TestInformation testInfo, 861 String description) 862 throws TargetSetupError, BuildError, DeviceNotAvailableException { 863 if (mTrackMultiPreparers == null) { 864 mTrackMultiPreparers = new HashSet<>(); 865 } 866 for (IMultiTargetPreparer multiPreparer : multiPreparers) { 867 // do not call the preparer if it was disabled 868 if (multiPreparer.isDisabled()) { 869 CLog.d("%s has been disabled. skipping.", multiPreparer); 870 continue; 871 } 872 TfObjectTracker.countWithParents(multiPreparer.getClass()); 873 if (multiPreparer instanceof ITestLoggerReceiver) { 874 ((ITestLoggerReceiver) multiPreparer).setTestLogger(logger); 875 } 876 long startTime = System.currentTimeMillis(); 877 try (CloseableTraceScope ignore = 878 new CloseableTraceScope(multiPreparer.getClass().getSimpleName())) { 879 CLog.d("Starting %s '%s'", description, multiPreparer); 880 multiPreparer.setUp(testInfo); 881 mTrackMultiPreparers.add(multiPreparer); 882 long elapsedTime = System.currentTimeMillis() - startTime; 883 CLog.d( 884 "Done with %s '%s' in %s", 885 description, multiPreparer, TimeUtil.formatElapsedTime(elapsedTime)); 886 } 887 } 888 } 889 890 /** Runs the {@link IMultiTargetPreparer} specified tearDown. */ runMultiTargetPreparersTearDown( List<IMultiTargetPreparer> multiPreparers, TestInformation testInfo, ITestLogger logger, Throwable throwable, String description)891 private Throwable runMultiTargetPreparersTearDown( 892 List<IMultiTargetPreparer> multiPreparers, 893 TestInformation testInfo, 894 ITestLogger logger, 895 Throwable throwable, 896 String description) 897 throws Throwable { 898 ListIterator<IMultiTargetPreparer> iterator = 899 multiPreparers.listIterator(multiPreparers.size()); 900 Throwable deferredThrowable = null; 901 902 while (iterator.hasPrevious()) { 903 IMultiTargetPreparer multipreparer = iterator.previous(); 904 if (multipreparer.isDisabled() || multipreparer.isTearDownDisabled()) { 905 CLog.d("%s has been disabled. skipping.", multipreparer); 906 continue; 907 } 908 if (mTrackMultiPreparers == null || !mTrackMultiPreparers.contains(multipreparer)) { 909 CLog.d("%s didn't run setUp, skipping tearDown.", multipreparer); 910 continue; 911 } 912 if (multipreparer instanceof ITestLoggerReceiver) { 913 ((ITestLoggerReceiver) multipreparer).setTestLogger(logger); 914 } 915 long startTime = System.currentTimeMillis(); 916 CLog.d("Starting %s '%s'", description, multipreparer); 917 try (CloseableTraceScope ignore = 918 new CloseableTraceScope(multipreparer.getClass().getSimpleName())) { 919 multipreparer.tearDown(testInfo, throwable); 920 } catch (Throwable t) { 921 // We catch it and rethrow later to allow each multi_targetprep to be attempted. 922 // Only the first one will be thrown but all should be logged. 923 CLog.e("Deferring throw for:"); 924 CLog.e(t); 925 if (deferredThrowable == null) { 926 deferredThrowable = t; 927 } 928 } 929 long elapsedTime = System.currentTimeMillis() - startTime; 930 931 CLog.d( 932 "Done with %s '%s' in %s", 933 description, multipreparer, TimeUtil.formatElapsedTime(elapsedTime)); 934 InvocationMetricLogger.addInvocationMetrics( 935 InvocationGroupMetricKey.MULTI_TARGET_PREPARER_TEARDOWN_LATENCY, 936 multipreparer.getClass().getName(), 937 elapsedTime); 938 } 939 940 return deferredThrowable; 941 } 942 943 @Override doTeardown( TestInformation testInfo, IConfiguration config, ITestLogger logger, Throwable exception)944 public void doTeardown( 945 TestInformation testInfo, 946 IConfiguration config, 947 ITestLogger logger, 948 Throwable exception) 949 throws Throwable { 950 IInvocationContext context = testInfo.getContext(); 951 Throwable deferredThrowable; 952 long start = System.currentTimeMillis(); 953 InvocationMetricLogger.addInvocationMetrics(InvocationMetricKey.TEARDOWN_START, start); 954 try { 955 int deviceIndex = 0; 956 try { 957 List<IMultiTargetPreparer> multiPreparers = config.getMultiTargetPreparers(); 958 deferredThrowable = 959 runMultiTargetPreparersTearDown( 960 multiPreparers, 961 testInfo, 962 logger, 963 exception, 964 "multi target preparer teardown"); 965 966 for (String deviceName : context.getDeviceConfigNames()) { 967 ITestDevice device = context.getDevice(deviceName); 968 device.clearLastConnectedWifiNetwork(); 969 970 List<ITargetPreparer> targetPreparersToRun = 971 getTargetPreparersToRun(config, deviceName); 972 Throwable firstLocalThrowable = 973 runPreparersTearDown( 974 testInfo, 975 device, 976 deviceName, 977 deviceIndex, 978 logger, 979 exception, 980 targetPreparersToRun, 981 mTrackTargetPreparers); 982 if (deferredThrowable == null) { 983 deferredThrowable = firstLocalThrowable; 984 } 985 986 deviceIndex++; 987 } 988 989 if (exception == null) { 990 exception = deferredThrowable; 991 } 992 } finally { 993 InvocationMetricLogger.addInvocationPairMetrics( 994 InvocationMetricKey.TEST_TEARDOWN_PAIR, start, System.currentTimeMillis()); 995 } 996 997 start = System.currentTimeMillis(); 998 try { 999 deviceIndex = 0; 1000 for (String deviceName : context.getDeviceConfigNames()) { 1001 ITestDevice device = context.getDevice(deviceName); 1002 List<ITargetPreparer> labPreparersToRun = 1003 getLabPreparersToRun(config, deviceName); 1004 Throwable secondLocalThrowable = 1005 runPreparersTearDown( 1006 testInfo, 1007 device, 1008 deviceName, 1009 deviceIndex, 1010 logger, 1011 exception, 1012 labPreparersToRun, 1013 mTrackLabPreparers); 1014 if (deferredThrowable == null) { 1015 deferredThrowable = secondLocalThrowable; 1016 } 1017 1018 deviceIndex++; 1019 } 1020 1021 if (exception == null) { 1022 exception = deferredThrowable; 1023 } 1024 // Extra tear down step for the device 1025 runDevicePostInvocationTearDown(context, config, exception); 1026 1027 // After all, run the multi_pre_target_preparer tearDown. 1028 List<IMultiTargetPreparer> multiPrePreparers = config.getMultiPreTargetPreparers(); 1029 Throwable preTargetTearDownException = 1030 runMultiTargetPreparersTearDown( 1031 multiPrePreparers, 1032 testInfo, 1033 logger, 1034 exception, 1035 "multi pre target preparer teardown"); 1036 if (deferredThrowable == null) { 1037 deferredThrowable = preTargetTearDownException; 1038 } 1039 } finally { 1040 InvocationMetricLogger.addInvocationPairMetrics( 1041 InvocationMetricKey.TEARDOWN_PAIR, start, System.currentTimeMillis()); 1042 } 1043 } finally { 1044 // Collect adb logs. 1045 logHostAdb(config, logger); 1046 InvocationMetricLogger.addInvocationMetrics( 1047 InvocationMetricKey.TEARDOWN_END, System.currentTimeMillis()); 1048 } 1049 1050 if (deferredThrowable != null) { 1051 throw deferredThrowable; 1052 } 1053 } 1054 runPreparersTearDown( TestInformation testInfo, ITestDevice device, String deviceName, int deviceIndex, ITestLogger logger, Throwable exception, List<ITargetPreparer> preparersToRun, Map<String, Set<ITargetPreparer>> trackPreparersMap)1055 protected Throwable runPreparersTearDown( 1056 TestInformation testInfo, 1057 ITestDevice device, 1058 String deviceName, 1059 int deviceIndex, 1060 ITestLogger logger, 1061 Throwable exception, 1062 List<ITargetPreparer> preparersToRun, 1063 Map<String, Set<ITargetPreparer>> trackPreparersMap) { 1064 Throwable deferredThrowable = null; 1065 ListIterator<ITargetPreparer> itr = preparersToRun.listIterator(preparersToRun.size()); 1066 while (itr.hasPrevious()) { 1067 ITargetPreparer preparer = itr.previous(); 1068 // do not call the cleaner if it was disabled 1069 if (preparer.isDisabled() || preparer.isTearDownDisabled()) { 1070 CLog.d("%s has been disabled. skipping.", preparer); 1071 continue; 1072 } 1073 if (trackPreparersMap == null 1074 || !trackPreparersMap.containsKey(deviceName) 1075 || !trackPreparersMap.get(deviceName).contains(preparer)) { 1076 CLog.d("%s didn't run setUp, skipping tearDown.", preparer); 1077 continue; 1078 } 1079 // If setup hit a targetSetupError, the setUp() and setTestLogger might not have 1080 // run, ensure we still have the logger. 1081 if (preparer instanceof ITestLoggerReceiver) { 1082 ((ITestLoggerReceiver) preparer).setTestLogger(logger); 1083 } 1084 long startTime = System.currentTimeMillis(); 1085 try (CloseableTraceScope remoteTest = 1086 new CloseableTraceScope(preparer.getClass().getSimpleName())) { 1087 CLog.d( 1088 "starting tearDown '%s' on device: '%s'", 1089 preparer, device.getSerialNumber()); 1090 testInfo.setActiveDeviceIndex(deviceIndex); 1091 Throwable tearDownException = exception; 1092 // If a previous teardown fail, still notify following ones. 1093 if (exception == null && deferredThrowable != null) { 1094 tearDownException = deferredThrowable; 1095 } 1096 preparer.tearDown(testInfo, tearDownException); 1097 } catch (Throwable e) { 1098 // We catch it and rethrow later to allow each targetprep to be attempted. 1099 // Only the first one will be thrown but all should be logged. 1100 CLog.e("Deferring throw for:"); 1101 CLog.e(e); 1102 if (deferredThrowable == null) { 1103 deferredThrowable = e; 1104 } 1105 } finally { 1106 testInfo.setActiveDeviceIndex(0); 1107 long elapsedTime = System.currentTimeMillis() - startTime; 1108 CLog.d( 1109 "done with tearDown '%s' on device: '%s' in %s", 1110 preparer, 1111 device.getSerialNumber(), 1112 TimeUtil.formatElapsedTime(elapsedTime)); 1113 InvocationMetricLogger.addInvocationMetrics( 1114 InvocationGroupMetricKey.TARGET_PREPARER_TEARDOWN_LATENCY, 1115 preparer.getClass().getName(), 1116 elapsedTime); 1117 } 1118 } 1119 return deferredThrowable; 1120 } 1121 1122 @Override doCleanUp(IInvocationContext context, IConfiguration config, Throwable exception)1123 public void doCleanUp(IInvocationContext context, IConfiguration config, Throwable exception) { 1124 for (String deviceName : context.getDeviceConfigNames()) { 1125 1126 List<ITargetPreparer> targetPreparers = getTargetPreparersToRun(config, deviceName); 1127 1128 ListIterator<ITargetPreparer> itr = 1129 targetPreparers.listIterator(targetPreparers.size()); 1130 while (itr.hasPrevious()) { 1131 ITargetPreparer preparer = itr.previous(); 1132 if (preparer instanceof IHostCleaner) { 1133 IHostCleaner cleaner = (IHostCleaner) preparer; 1134 if (preparer.isDisabled() || preparer.isTearDownDisabled()) { 1135 CLog.d("%s has been disabled. skipping.", cleaner); 1136 continue; 1137 } 1138 cleaner.cleanUp(context.getBuildInfo(deviceName), exception); 1139 } 1140 } 1141 1142 List<ITargetPreparer> labPreparers = getLabPreparersToRun(config, deviceName); 1143 1144 // Yes this ends up very redundant to the above stanza, but 8 lines isn't really worth 1145 // extracting to a helper method. 1146 itr = labPreparers.listIterator(labPreparers.size()); 1147 while (itr.hasPrevious()) { 1148 ITargetPreparer preparer = itr.previous(); 1149 if (preparer instanceof IHostCleaner) { 1150 IHostCleaner cleaner = (IHostCleaner) preparer; 1151 if (preparer.isDisabled() || preparer.isTearDownDisabled()) { 1152 CLog.d("%s has been disabled. skipping.", cleaner); 1153 continue; 1154 } 1155 cleaner.cleanUp(context.getBuildInfo(deviceName), exception); 1156 } 1157 } 1158 } 1159 } 1160 1161 @Override runTests( TestInformation info, IConfiguration config, ITestInvocationListener listener)1162 public void runTests( 1163 TestInformation info, IConfiguration config, ITestInvocationListener listener) 1164 throws Throwable { 1165 Timer testPhaseTimer = new Timer(true); 1166 long remainingTestPhaseTime = 1167 GlobalConfiguration.getInstance().getHostOptions().getTestPhaseTimeout(); 1168 boolean testPhaseTimeoutNeeded = remainingTestPhaseTime > 0; 1169 // Make sure Test Phase timeout is less than or equal to invocation timeout 1170 long invocationTimeout = config.getCommandOptions().getInvocationTimeout(); 1171 if (testPhaseTimeoutNeeded && invocationTimeout > 0) { 1172 remainingTestPhaseTime = Math.min(remainingTestPhaseTime, invocationTimeout); 1173 } 1174 1175 List<IRemoteTest> remainingTests = new ArrayList<>(config.getTests()); 1176 UnexecutedTestReporterThread reporterThread = 1177 new UnexecutedTestReporterThread(listener, remainingTests); 1178 Runtime.getRuntime().addShutdownHook(reporterThread); 1179 TestInvocation.printStageDelimiter(Stage.TEST, false); 1180 long start = System.currentTimeMillis(); 1181 try (CloseableTraceScope ignored = 1182 new CloseableTraceScope(InvocationMetricKey.test_execution.name())) { 1183 GetPreviousPassedHelper previousPassHelper = new GetPreviousPassedHelper(); 1184 // Add new exclude filters to global filters 1185 Set<String> previousPassedFilters = previousPassHelper.getPreviousPassedFilters(config); 1186 // TODO: Ensure global filters are cloned for local sharding 1187 config.getGlobalFilters().addPreviousPassedTests(previousPassedFilters); 1188 for (IRemoteTest test : config.getTests()) { 1189 try (CloseableTraceScope remoteTest = 1190 new CloseableTraceScope(test.getClass().getSimpleName())) { 1191 TfObjectTracker.countWithParents(test.getClass()); 1192 // For compatibility of those receivers, they are assumed to be single device 1193 // alloc. 1194 if (test instanceof IDeviceTest) { 1195 ((IDeviceTest) test).setDevice(info.getDevice()); 1196 } 1197 if (test instanceof IBuildReceiver) { 1198 ((IBuildReceiver) test).setBuild(info.getBuildInfo()); 1199 } 1200 if (test instanceof ISystemStatusCheckerReceiver) { 1201 ((ISystemStatusCheckerReceiver) test) 1202 .setSystemStatusChecker(config.getSystemStatusCheckers()); 1203 } 1204 if (test instanceof IInvocationContextReceiver) { 1205 ((IInvocationContextReceiver) test).setInvocationContext(info.getContext()); 1206 } 1207 1208 updateAutoCollectors(config); 1209 1210 IRetryDecision decision = config.getRetryDecision(); 1211 // Apply the filters 1212 if (test instanceof ITestFilterReceiver) { 1213 config.getGlobalFilters().applyFiltersToTest((ITestFilterReceiver) test); 1214 } else if (test instanceof BaseTestSuite) { 1215 config.getGlobalFilters().applyFiltersToTest((BaseTestSuite) test); 1216 } 1217 // Handle the no-retry use case 1218 if (!decision.isAutoRetryEnabled() 1219 || RetryStrategy.NO_RETRY.equals(decision.getRetryStrategy()) 1220 || test instanceof ITestSuite 1221 // Exclude special launcher 1222 || test.getClass().getSimpleName().equals("CtsTestLauncher") 1223 // TODO: Handle auto-retry in local-sharding for non-suite 1224 || test instanceof TestsPoolPoller 1225 // If test doesn't support auto-retry 1226 || (!(test instanceof ITestFilterReceiver) 1227 && !(test instanceof IAutoRetriableTest) 1228 && !RetryStrategy.ITERATIONS.equals( 1229 decision.getRetryStrategy()))) { 1230 try { 1231 long timeSpentOnTest = 1232 runTest( 1233 config, 1234 info, 1235 listener, 1236 test, 1237 testPhaseTimer, 1238 remainingTestPhaseTime, 1239 testPhaseTimeoutNeeded); 1240 remainingTestPhaseTime -= timeSpentOnTest; 1241 } finally { 1242 CurrentInvocation.setRunIsolation(IsolationGrade.NOT_ISOLATED); 1243 CurrentInvocation.setModuleIsolation(IsolationGrade.NOT_ISOLATED); 1244 // Clean the suite internals once done 1245 if (test instanceof BaseTestSuite) { 1246 ((BaseTestSuite) test).cleanUpSuiteSetup(); 1247 } 1248 } 1249 remainingTests.remove(test); 1250 continue; 1251 } 1252 CLog.d("Using RetryLogSaverResultForwarder to forward results."); 1253 ModuleListener mainGranularRunListener = 1254 new ModuleListener(null, info.getContext()); 1255 RetryLogSaverResultForwarder runListener = 1256 initializeListeners(config, listener, mainGranularRunListener); 1257 mainGranularRunListener.setAttemptIsolation( 1258 CurrentInvocation.runCurrentIsolation()); 1259 try { 1260 long timeSpentOnTest = 1261 runTest( 1262 config, 1263 info, 1264 runListener, 1265 test, 1266 testPhaseTimer, 1267 remainingTestPhaseTime, 1268 testPhaseTimeoutNeeded); 1269 remainingTestPhaseTime -= timeSpentOnTest; 1270 } finally { 1271 CurrentInvocation.setRunIsolation(IsolationGrade.NOT_ISOLATED); 1272 CurrentInvocation.setModuleIsolation(IsolationGrade.NOT_ISOLATED); 1273 } 1274 remainingTests.remove(test); 1275 runListener.incrementAttempt(); 1276 1277 // Avoid entering the loop if no retry to be done. 1278 if (!decision.shouldRetry( 1279 test, 0, mainGranularRunListener.getTestRunForAttempts(0))) { 1280 continue; 1281 } 1282 // Avoid rechecking the shouldRetry below the first time as it could retrigger 1283 // reboot. 1284 boolean firstCheck = true; 1285 long startTime = System.currentTimeMillis(); 1286 try { 1287 PrettyPrintDelimiter.printStageDelimiter("Starting auto-retry"); 1288 for (int attemptNumber = 1; 1289 attemptNumber < decision.getMaxTestRunAttempts(); 1290 attemptNumber++) { 1291 if (!firstCheck) { 1292 boolean retry = 1293 decision.shouldRetry( 1294 test, 1295 attemptNumber - 1, 1296 mainGranularRunListener.getTestRunForAttempts( 1297 attemptNumber - 1)); 1298 if (!retry) { 1299 continue; 1300 } 1301 } 1302 firstCheck = false; 1303 CLog.d("auto-retry attempt number '%s'", attemptNumber); 1304 mainGranularRunListener.setAttemptIsolation( 1305 CurrentInvocation.runCurrentIsolation()); 1306 try { 1307 // Run the tests again 1308 long timeSpent = 1309 runTest( 1310 config, 1311 info, 1312 runListener, 1313 test, 1314 testPhaseTimer, 1315 remainingTestPhaseTime, 1316 testPhaseTimeoutNeeded); 1317 remainingTestPhaseTime -= timeSpent; 1318 } finally { 1319 CurrentInvocation.setRunIsolation(IsolationGrade.NOT_ISOLATED); 1320 CurrentInvocation.setModuleIsolation(IsolationGrade.NOT_ISOLATED); 1321 } 1322 runListener.incrementAttempt(); 1323 } 1324 // Feed the last attempt if we reached here. 1325 decision.addLastAttempt( 1326 mainGranularRunListener.getTestRunForAttempts( 1327 decision.getMaxTestRunAttempts() - 1)); 1328 } finally { 1329 RetryStatistics retryStats = decision.getRetryStatistics(); 1330 // Track how long we spend in retry 1331 retryStats.mRetryTime = System.currentTimeMillis() - startTime; 1332 addRetryTime(retryStats.mRetryTime); 1333 } 1334 } 1335 } 1336 } finally { 1337 testPhaseTimer.cancel(); 1338 TestInvocation.printStageDelimiter(Stage.TEST, true); 1339 // TODO: Look if this can be improved to DeviceNotAvailableException too. 1340 try { 1341 Runtime.getRuntime().removeShutdownHook(reporterThread); 1342 } catch (IllegalStateException e) { 1343 // Ignore as it would throw only if JVM shutdown is in progress. 1344 } 1345 // Only log if it was no already logged to keep the value closest to execution 1346 if (!InvocationMetricLogger.getInvocationMetrics() 1347 .containsKey(InvocationMetricKey.TEST_PAIR.toString())) { 1348 InvocationMetricLogger.addInvocationPairMetrics( 1349 InvocationMetricKey.TEST_PAIR, start, System.currentTimeMillis()); 1350 } 1351 } 1352 } 1353 1354 @Override reportLogs(ITestDevice device, ITestLogger listener, Stage stage)1355 public void reportLogs(ITestDevice device, ITestLogger listener, Stage stage) { 1356 if (device == null) { 1357 return; 1358 } 1359 IDevice idevice = device.getIDevice(); 1360 try (InputStreamSource logcatSource = device.getLogcat()) { 1361 device.clearLogcat(); 1362 if (logcatSource != null && logcatSource.size() > 0L) { 1363 String name = 1364 String.format( 1365 "%s_%s", 1366 TestInvocation.getDeviceLogName(stage), device.getSerialNumber()); 1367 listener.testLog(name, LogDataType.LOGCAT, logcatSource); 1368 } 1369 } 1370 // Emulator logs 1371 if (idevice != null && idevice.isEmulator()) { 1372 try (InputStreamSource emulatorOutput = device.getEmulatorOutput()) { 1373 // TODO: Clear the emulator log 1374 String name = TestInvocation.getEmulatorLogName(stage); 1375 listener.testLog(name, LogDataType.TEXT, emulatorOutput); 1376 } 1377 } 1378 } 1379 1380 /** Helper to create the test tag from the configuration. */ getTestTag(IConfiguration config)1381 private String getTestTag(IConfiguration config) { 1382 String testTag = config.getCommandOptions().getTestTag(); 1383 if (config.getCommandOptions().getTestTagSuffix() != null) { 1384 testTag = 1385 String.format("%s-%s", testTag, config.getCommandOptions().getTestTagSuffix()); 1386 } 1387 return testTag; 1388 } 1389 1390 /** Handle setting the test tag on the build info. */ setTestTag(IBuildInfo info, IConfiguration config)1391 protected void setTestTag(IBuildInfo info, IConfiguration config) { 1392 // When CommandOption is set, it overrides any test-tag from build_providers 1393 if (!"stub".equals(config.getCommandOptions().getTestTag())) { 1394 info.setTestTag(getTestTag(config)); 1395 } else if (Strings.isNullOrEmpty(info.getTestTag())) { 1396 // We ensure that that a default test-tag is always available. 1397 info.setTestTag("stub"); 1398 } 1399 } 1400 1401 /** 1402 * Update the {@link IBuildInfo} with additional info from the {@link IConfiguration}. 1403 * 1404 * @param info the {@link IBuildInfo} 1405 * @param config the {@link IConfiguration} 1406 */ updateBuild(IBuildInfo info, IConfiguration config)1407 void updateBuild(IBuildInfo info, IConfiguration config) { 1408 setTestTag(info, config); 1409 if (config.getCommandOptions().getInvocationData().containsKey("subprocess")) { 1410 // Avoid relogging the properties in a subprocess 1411 return; 1412 } 1413 if (config.getCommandLine() != null) { 1414 // TODO: obfuscate the password if any. 1415 info.addBuildAttribute(TestInvocation.COMMAND_ARGS_KEY, config.getCommandLine()); 1416 } 1417 if (config.getCommandOptions().getShardCount() != null) { 1418 info.addBuildAttribute( 1419 "shard_count", config.getCommandOptions().getShardCount().toString()); 1420 } 1421 if (config.getCommandOptions().getShardIndex() != null) { 1422 info.addBuildAttribute( 1423 "shard_index", config.getCommandOptions().getShardIndex().toString()); 1424 } 1425 } 1426 1427 /** 1428 * Runs a test and returns the time taken to finish the test. 1429 * 1430 * <p>Tests will be run on a separate thread with a timer when test phase level timeout is 1431 * needed. 1432 */ runTest( IConfiguration config, TestInformation info, ITestInvocationListener listener, IRemoteTest test, Timer timer, long testPhaseTimeout, boolean testPhaseTimeoutNeeded)1433 private long runTest( 1434 IConfiguration config, 1435 TestInformation info, 1436 ITestInvocationListener listener, 1437 IRemoteTest test, 1438 Timer timer, 1439 long testPhaseTimeout, 1440 boolean testPhaseTimeoutNeeded) 1441 throws DeviceNotAvailableException, Throwable { 1442 // We clone the collectors for each IRemoteTest to ensure no state conflicts. 1443 List<IMetricCollector> clonedCollectors = new ArrayList<>(); 1444 // Add automated collectors 1445 for (AutoLogCollector auto : config.getCommandOptions().getAutoLogCollectors()) { 1446 clonedCollectors.add(auto.getInstanceForValue()); 1447 } 1448 // Add the collector from the configuration 1449 clonedCollectors.addAll(CollectorHelper.cloneCollectors(config.getMetricCollectors())); 1450 if (test instanceof IMetricCollectorReceiver) { 1451 ((IMetricCollectorReceiver) test).setMetricCollectors(clonedCollectors); 1452 // If test can receive collectors then let it handle the how to set them up 1453 if (testPhaseTimeoutNeeded) { 1454 return runTestThread(info, listener, test, timer, testPhaseTimeout); 1455 } else { 1456 long startTime = System.currentTimeMillis(); 1457 test.run(info, listener); 1458 return System.currentTimeMillis() - startTime; 1459 } 1460 } else { 1461 // Wrap collectors in each other and collection will be sequential, do this in the 1462 // loop to ensure they are always initialized against the right context. 1463 ITestInvocationListener listenerWithCollectors = listener; 1464 if (config.getCommandOptions().reportTestCaseCount()) { 1465 CountTestCasesCollector counter = new CountTestCasesCollector(test); 1466 clonedCollectors.add(counter); 1467 } 1468 for (IMetricCollector collector : clonedCollectors) { 1469 if (collector.isDisabled()) { 1470 CLog.d("%s has been disabled. Skipping.", collector); 1471 } else { 1472 if (collector instanceof IConfigurationReceiver) { 1473 ((IConfigurationReceiver) collector).setConfiguration(config); 1474 } 1475 listenerWithCollectors = 1476 collector.init(info.getContext(), listenerWithCollectors); 1477 TfObjectTracker.countWithParents(collector.getClass()); 1478 } 1479 } 1480 if (testPhaseTimeoutNeeded) { 1481 return runTestThread(info, listenerWithCollectors, test, timer, testPhaseTimeout); 1482 } else { 1483 long startTime = System.currentTimeMillis(); 1484 test.run(info, listenerWithCollectors); 1485 return System.currentTimeMillis() - startTime; 1486 } 1487 } 1488 } 1489 1490 /** Runs a test in a separate thread and returns the time spent on running the test. */ runTestThread( TestInformation info, ITestInvocationListener listener, IRemoteTest test, Timer timer, long testPhaseTimeout)1491 private long runTestThread( 1492 TestInformation info, 1493 ITestInvocationListener listener, 1494 IRemoteTest test, 1495 Timer timer, 1496 long testPhaseTimeout) 1497 throws Throwable { 1498 if (testPhaseTimeout <= 0) { 1499 // throw run interrupted exception so that it can be handled the same way as TestThreads 1500 // when timeout is reached. 1501 throw new RunInterruptedException( 1502 "Test Phase Timeout Reached.", TestErrorIdentifier.TEST_PHASE_TIMED_OUT); 1503 } 1504 TestThread testThread = new TestThread(info, listener, test); 1505 TestPhaseMonitor testPhaseMonitor = new TestPhaseMonitor(testThread); 1506 timer.schedule(testPhaseMonitor, testPhaseTimeout); 1507 long startTime = System.currentTimeMillis(); 1508 testThread.start(); 1509 try { 1510 testThread.join(); 1511 } catch (InterruptedException e) { 1512 CLog.e(e); 1513 } finally { 1514 testPhaseMonitor.cancel(); 1515 long timeSpent = System.currentTimeMillis() - startTime; 1516 if (testThread.getLastThrownException() != null) { 1517 throw testThread.getLastThrownException(); 1518 } 1519 return timeSpent; 1520 } 1521 } 1522 initializeListeners( IConfiguration config, ITestInvocationListener mainListener, ITestInvocationListener mainGranularLevelListener)1523 private RetryLogSaverResultForwarder initializeListeners( 1524 IConfiguration config, 1525 ITestInvocationListener mainListener, 1526 ITestInvocationListener mainGranularLevelListener) { 1527 List<ITestInvocationListener> currentTestListeners = new ArrayList<>(); 1528 currentTestListeners.add(mainGranularLevelListener); 1529 currentTestListeners.add(mainListener); 1530 return new RetryLogSaverResultForwarder( 1531 config.getLogSaver(), currentTestListeners, config) { 1532 @Override 1533 public void testLog( 1534 String dataName, LogDataType dataType, InputStreamSource dataStream) { 1535 // We know for sure that the sub-listeners are LogSaverResultForwarder 1536 // so we delegate to them to save and generate the logAssociation. 1537 testLogForward(dataName, dataType, dataStream); 1538 } 1539 }; 1540 } 1541 1542 private void addRetryTime(long retryTimeMs) { 1543 // InvocationMetricLogger automatically adds the auto retry time. 1544 InvocationMetricLogger.addInvocationMetrics( 1545 InvocationMetricKey.AUTO_RETRY_TIME, retryTimeMs); 1546 } 1547 1548 protected void linkExternalDirs(IBuildInfo info, TestInformation testInfo) { 1549 if (info.getProperties().contains(BuildInfoProperties.DO_NOT_LINK_TESTS_DIR)) { 1550 CLog.d("Skip linking external directory as FileProperty was set."); 1551 return; 1552 } 1553 // Load environment tests dir. 1554 if (info instanceof IDeviceBuildInfo) { 1555 // TODO: Use tests directory from TestInformation instead. 1556 File testsDir = ((IDeviceBuildInfo) info).getTestsDir(); 1557 if (testsDir != null && testsDir.exists()) { 1558 if (testInfo.executionFiles().get(FilesKey.TARGET_TESTS_DIRECTORY) == null) { 1559 File targetTestCases = 1560 handleLinkingExternalDirs( 1561 (IDeviceBuildInfo) info, 1562 testsDir, 1563 EnvVariable.ANDROID_TARGET_OUT_TESTCASES, 1564 BuildInfoFileKey.TARGET_LINKED_DIR.getFileKey()); 1565 if (targetTestCases != null) { 1566 testInfo.executionFiles() 1567 .put(FilesKey.TARGET_TESTS_DIRECTORY, targetTestCases, true); 1568 } 1569 } 1570 if (testInfo.executionFiles().get(FilesKey.HOST_TESTS_DIRECTORY) == null) { 1571 File hostTestCases = 1572 handleLinkingExternalDirs( 1573 (IDeviceBuildInfo) info, 1574 testsDir, 1575 EnvVariable.ANDROID_HOST_OUT_TESTCASES, 1576 BuildInfoFileKey.HOST_LINKED_DIR.getFileKey()); 1577 if (hostTestCases != null) { 1578 testInfo.executionFiles() 1579 .put(FilesKey.HOST_TESTS_DIRECTORY, hostTestCases, true); 1580 } 1581 } 1582 } 1583 } 1584 } 1585 1586 private File handleLinkingExternalDirs( 1587 IDeviceBuildInfo info, File testsDir, EnvVariable var, String baseName) { 1588 File externalDir = getExternalTestCasesDirs(var); 1589 if (externalDir == null) { 1590 String path = SystemUtil.ENV_VARIABLE_PATHS_IN_TESTS_DIR.get(var); 1591 File varDir = FileUtil.getFileForPath(testsDir, path); 1592 if (varDir.exists()) { 1593 // If we found a dir already in the tests dir we keep track of it 1594 info.setFile( 1595 baseName, 1596 varDir, 1597 /** version */ 1598 "v1"); 1599 return varDir; 1600 } 1601 return null; 1602 } 1603 try { 1604 // Avoid conflict by creating a randomized name for the arriving symlink file. 1605 File subDir = FileUtil.createTempDir(baseName, testsDir); 1606 subDir.delete(); 1607 FileUtil.symlinkFile(externalDir, subDir); 1608 // Tag the dir in the build info to be possibly cleaned. 1609 info.setFile( 1610 baseName, 1611 subDir, 1612 /** version */ 1613 "v1"); 1614 // Ensure we always delete the linking, no matter how the JVM exits. 1615 subDir.deleteOnExit(); 1616 return subDir; 1617 } catch (IOException e) { 1618 CLog.e("Failed to load external test dir %s. Ignoring it.", externalDir); 1619 CLog.e(e); 1620 } 1621 return null; 1622 } 1623 1624 private void setBinariesVersion(IInvocationContext context) { 1625 String version = getAdbVersion(); 1626 if (version != null) { 1627 context.addInvocationAttribute(ADB_VERSION_KEY, version); 1628 } 1629 String javaVersion = System.getProperty("java.version"); 1630 if (javaVersion != null && !javaVersion.isEmpty()) { 1631 context.addInvocationAttribute(JAVA_VERSION_KEY, javaVersion); 1632 } 1633 String javaClasspath = System.getProperty("java.class.path"); 1634 if (javaClasspath != null && !javaClasspath.isEmpty()) { 1635 context.addInvocationAttribute(JAVA_CLASSPATH_KEY, javaClasspath); 1636 } 1637 } 1638 1639 private void copyRemoteFiles(ICommandOptions options, IBuildInfo info) { 1640 for (String remoteFile : options.getRemoteFiles()) { 1641 info.setFile( 1642 IBuildInfo.REMOTE_FILE_PREFIX, 1643 new File(remoteFile), 1644 IBuildInfo.REMOTE_FILE_VERSION); 1645 } 1646 } 1647 1648 /** Convert the legacy *-on-failure options to the new auto-collect. */ 1649 private void updateAutoCollectors(IConfiguration config) { 1650 if (config.getCommandOptions().captureScreenshotOnFailure()) { 1651 config.getCommandOptions() 1652 .getAutoLogCollectors() 1653 .add(AutoLogCollector.SCREENSHOT_ON_FAILURE); 1654 } 1655 if (config.getCommandOptions().captureLogcatOnFailure()) { 1656 config.getCommandOptions() 1657 .getAutoLogCollectors() 1658 .add(AutoLogCollector.LOGCAT_ON_FAILURE); 1659 } 1660 } 1661 1662 /** Collect the logs from $TMPDIR/adb.$UID.log. */ 1663 @VisibleForTesting 1664 protected void logHostAdb(IConfiguration config, ITestLogger logger) { 1665 if (SystemUtil.isLocalMode()) { 1666 // Skip logging host adb locally 1667 return; 1668 } 1669 if (config.getCommandOptions().getInvocationData().containsKey("subprocess")) { 1670 // Avoid relogging the adb log in a subprocess 1671 return; 1672 } 1673 String tmpDir = "/tmp"; 1674 if (System.getenv("TMPDIR") != null) { 1675 tmpDir = System.getenv("TMPDIR"); 1676 } 1677 CommandResult uidRes = 1678 RunUtil.getDefault() 1679 .runTimedCmd(60000, "id", "-u", System.getProperty("user.name")); 1680 if (!CommandStatus.SUCCESS.equals(uidRes.getStatus())) { 1681 CLog.e("Failed to collect UID for adb logs: %s", uidRes.getStderr()); 1682 return; 1683 } 1684 String uid = uidRes.getStdout().trim(); 1685 File adbLog = new File(tmpDir, String.format("adb.%s.log", uid)); 1686 if (!adbLog.exists()) { 1687 CLog.i("Did not find adb log file: %s, upload skipped.", adbLog); 1688 return; 1689 } 1690 CommandResult truncAdb = 1691 RunUtil.getDefault() 1692 .runTimedCmd(60000, "tail", "-c", "10MB", adbLog.getAbsolutePath()); 1693 if (!CommandStatus.SUCCESS.equals(truncAdb.getStatus())) { 1694 CLog.e("Failed to truncate the adb log: %s\n%s", adbLog, truncAdb.getStderr()); 1695 return; 1696 } 1697 try (InputStreamSource source = 1698 new ByteArrayInputStreamSource(truncAdb.getStdout().getBytes())) { 1699 logger.testLog("host_adb_log", LogDataType.ADB_HOST_LOG, source); 1700 } 1701 } 1702 1703 /** Returns the external directory coming from the environment. */ 1704 @VisibleForTesting 1705 File getExternalTestCasesDirs(EnvVariable envVar) { 1706 return SystemUtil.getExternalTestCasesDir(envVar); 1707 } 1708 1709 /** Returns the adb version in use for the invocation. */ 1710 protected String getAdbVersion() { 1711 return GlobalConfiguration.getDeviceManagerInstance().getAdbVersion(); 1712 } 1713 1714 /** Collect automatically some information on the primary device under test. */ 1715 protected void collectAutoInfo(IConfiguration config, TestInformation info) 1716 throws DeviceNotAvailableException { 1717 if (SystemUtil.isLocalMode()) { 1718 // Avoid collecting for local modes since data collected in this method is used 1719 // in CI only. 1720 return; 1721 } 1722 if (config.getCommandOptions().getInvocationData().containsKey("subprocess")) { 1723 // Avoid logging in the subprocess 1724 return; 1725 } 1726 ITestDevice device = info.getDevice(); 1727 if (device.getIDevice() instanceof StubDevice) { 1728 return; 1729 } 1730 try (CloseableTraceScope ignored = new CloseableTraceScope("collect_device_info")) { 1731 CommandResult kernelInfoResult = device.executeShellV2Command("uname -a"); 1732 if (kernelInfoResult != null 1733 && CommandStatus.SUCCESS.equals(kernelInfoResult.getStatus())) { 1734 CLog.i( 1735 "Device %s kernel information: '%s'", 1736 device.getSerialNumber(), kernelInfoResult.getStdout().trim()); 1737 info.getBuildInfo() 1738 .addBuildAttribute( 1739 "device_kernel_info", kernelInfoResult.getStdout().trim()); 1740 } 1741 String system_img_info = device.getProperty("ro.system.build.fingerprint"); 1742 if (system_img_info != null) { 1743 CLog.i( 1744 "Device %s system image build information: '%s'", 1745 device.getSerialNumber(), system_img_info); 1746 info.getBuildInfo().addBuildAttribute("system_img_info", system_img_info); 1747 } 1748 String vendor_img_info = device.getProperty("ro.vendor.build.fingerprint"); 1749 if (vendor_img_info != null) { 1750 CLog.i( 1751 "Device %s vendor image build information: '%s'", 1752 device.getSerialNumber(), vendor_img_info); 1753 info.getBuildInfo().addBuildAttribute("vendor_img_info", vendor_img_info); 1754 } 1755 } 1756 } 1757 } 1758