1 /* 2 * Copyright (C) 2010 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 17 package com.android.tradefed.targetprep; 18 19 import com.android.tradefed.build.IDeviceBuildInfo; 20 import com.android.tradefed.command.remote.DeviceDescriptor; 21 import com.android.tradefed.config.GlobalConfiguration; 22 import com.android.tradefed.device.DeviceNotAvailableException; 23 import com.android.tradefed.device.IManagedTestDevice; 24 import com.android.tradefed.device.ITestDevice; 25 import com.android.tradefed.device.TestDeviceState; 26 import com.android.tradefed.error.HarnessRuntimeException; 27 import com.android.tradefed.host.IHostOptions; 28 import com.android.tradefed.host.IHostOptions.PermitLimitType; 29 import com.android.tradefed.invoker.logger.InvocationMetricLogger; 30 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey; 31 import com.android.tradefed.invoker.tracing.CloseableTraceScope; 32 import com.android.tradefed.log.LogUtil.CLog; 33 import com.android.tradefed.result.error.DeviceErrorIdentifier; 34 import com.android.tradefed.result.error.ErrorIdentifier; 35 import com.android.tradefed.result.error.InfraErrorIdentifier; 36 import com.android.tradefed.util.CommandResult; 37 import com.android.tradefed.util.CommandStatus; 38 import com.android.tradefed.util.FileUtil; 39 import com.android.tradefed.util.FuseUtil; 40 import com.android.tradefed.util.IRunUtil; 41 import com.android.tradefed.util.RunUtil; 42 import com.android.tradefed.util.ZipUtil2; 43 import com.android.tradefed.util.image.DeviceImageTracker; 44 import com.android.tradefed.util.image.DeviceImageTracker.FileCacheTracker; 45 import com.android.tradefed.util.image.IncrementalImageUtil; 46 47 import com.google.common.annotations.VisibleForTesting; 48 import com.google.common.collect.ImmutableSet; 49 50 import org.apache.commons.compress.archivers.zip.ZipFile; 51 52 import java.io.File; 53 import java.io.IOException; 54 import java.util.ArrayList; 55 import java.util.Arrays; 56 import java.util.Collection; 57 import java.util.HashMap; 58 import java.util.List; 59 import java.util.Map; 60 import java.util.Random; 61 import java.util.concurrent.TimeUnit; 62 import java.util.regex.Matcher; 63 import java.util.regex.Pattern; 64 import java.util.stream.Collectors; 65 66 /** A class that relies on fastboot to flash an image on physical Android hardware. */ 67 public class FastbootDeviceFlasher implements IDeviceFlasher { 68 public static final String BASEBAND_IMAGE_NAME = "radio"; 69 70 private static final String FASTBOOT_VERSION = "fastboot_version"; 71 private static final int MAX_RETRY_ATTEMPTS = 3; 72 private static final int RETRY_SLEEP = 2 * 1000; // 2s sleep between retries 73 74 private static final String SLOT_PROP = "ro.boot.slot_suffix"; 75 private static final String SLOT_VAR = "current-slot"; 76 private static final String SKIP_REBOOT_PARAM = "--skip-reboot"; 77 private static final ImmutableSet<String> DISK_SPACE_ERRORS = 78 ImmutableSet.of("No space left on device", "failed to create temporary file"); 79 80 private long mWipeTimeout = 4 * 60 * 1000; 81 82 private UserDataFlashOption mUserDataFlashOption = UserDataFlashOption.FLASH; 83 84 private IFlashingResourcesRetriever mResourceRetriever; 85 86 private ITestsZipInstaller mTestsZipInstaller = null; 87 88 private Collection<String> mFlashOptions = new ArrayList<>(); 89 90 private Collection<String> mDataWipeSkipList = null; 91 92 private boolean mForceSystemFlash; 93 94 private CommandStatus mFbCmdStatus; 95 96 private CommandStatus mSystemFlashStatus; 97 98 private boolean mShouldFlashRamdisk = false; 99 100 private String mRamdiskPartition = "root"; 101 102 private String mSystemBuildId = null; 103 private String mSystemBuildFlavor = null; 104 105 private IncrementalImageUtil mIncrementalFlashing = null; 106 107 @VisibleForTesting getFuseUtil()108 protected FuseUtil getFuseUtil() { 109 return new FuseUtil(); 110 } 111 112 /** 113 * {@inheritDoc} 114 */ 115 @Override setFlashingResourcesRetriever(IFlashingResourcesRetriever retriever)116 public void setFlashingResourcesRetriever(IFlashingResourcesRetriever retriever) { 117 mResourceRetriever = retriever; 118 } 119 getFlashingResourcesRetriever()120 protected IFlashingResourcesRetriever getFlashingResourcesRetriever() { 121 return mResourceRetriever; 122 } 123 124 /** 125 * {@inheritDoc} 126 */ 127 @Override setUserDataFlashOption(UserDataFlashOption flashOption)128 public void setUserDataFlashOption(UserDataFlashOption flashOption) { 129 mUserDataFlashOption = flashOption; 130 } 131 132 /** 133 * {@inheritDoc} 134 */ 135 @Override getUserDataFlashOption()136 public UserDataFlashOption getUserDataFlashOption() { 137 return mUserDataFlashOption; 138 } 139 setTestsZipInstaller(ITestsZipInstaller testsZipInstaller)140 void setTestsZipInstaller(ITestsZipInstaller testsZipInstaller) { 141 mTestsZipInstaller = testsZipInstaller; 142 } 143 getTestsZipInstaller()144 ITestsZipInstaller getTestsZipInstaller() { 145 // Lazily initialize the TestZipInstaller. 146 if (mTestsZipInstaller == null) { 147 if (mDataWipeSkipList == null) { 148 mDataWipeSkipList = new ArrayList<String>(); 149 } 150 if (mDataWipeSkipList.isEmpty()) { 151 // To maintain backwards compatibility. Keep media by default. 152 // TODO: deprecate and remove this. 153 mDataWipeSkipList.add("media"); 154 } 155 mTestsZipInstaller = new DefaultTestsZipInstaller(mDataWipeSkipList); 156 } 157 return mTestsZipInstaller; 158 } 159 160 /** 161 * Sets a list of options to pass with flash/update commands. 162 * 163 * @param flashOptions 164 */ setFlashOptions(Collection<String> flashOptions)165 public void setFlashOptions(Collection<String> flashOptions) { 166 // HACK: To workaround TF's command line parsing, options starting with a dash 167 // needs to be prepended with a whitespace and trimmed before they are used. 168 mFlashOptions = flashOptions.stream().map(String::trim).collect(Collectors.toList()); 169 } 170 setIncrementalFlashing(IncrementalImageUtil incrementalUtil)171 public void setIncrementalFlashing(IncrementalImageUtil incrementalUtil) { 172 mIncrementalFlashing = incrementalUtil; 173 } 174 175 /** {@inheritDoc} */ 176 @Override preFlashOperations(ITestDevice device, IDeviceBuildInfo deviceBuild)177 public void preFlashOperations(ITestDevice device, IDeviceBuildInfo deviceBuild) 178 throws TargetSetupError, DeviceNotAvailableException { 179 boolean initialStateFastbootD = 180 supportsFlashingInFastbootD() && 181 TestDeviceState.FASTBOOTD.equals(device.getDeviceState()); 182 if (initialStateFastbootD) { 183 CLog.i("Using flashing from fastbootd"); 184 InvocationMetricLogger.addInvocationMetrics( 185 InvocationMetricKey.FLASHING_FROM_FASTBOOTD, 1); 186 } 187 188 CLog.i("Flashing device %s with build %s", device.getSerialNumber(), 189 deviceBuild.getDeviceBuildId()); 190 191 // Get system build id and build flavor before booting into fastboot 192 if (TestDeviceState.ONLINE.equals(device.getDeviceState())) { 193 setSystemBuildInfo(device.getBuildId(), device.getBuildFlavor()); 194 } 195 196 if (!initialStateFastbootD) { 197 device.rebootIntoBootloader(); 198 } 199 200 downloadFlashingResources(device, deviceBuild); 201 preFlashSetup(device, deviceBuild); 202 if (device instanceof IManagedTestDevice) { 203 String fastbootVersion = ((IManagedTestDevice) device).getFastbootVersion(); 204 if (fastbootVersion != null) { 205 deviceBuild.addBuildAttribute(FASTBOOT_VERSION, fastbootVersion); 206 } 207 } 208 } 209 210 /** {@inheritDoc} */ 211 @Override flash(ITestDevice device, IDeviceBuildInfo deviceBuild)212 public void flash(ITestDevice device, IDeviceBuildInfo deviceBuild) 213 throws TargetSetupError, DeviceNotAvailableException { 214 handleUserDataFlashing(device, deviceBuild); 215 checkAndFlashBootloader(device, deviceBuild); 216 checkAndFlashBaseband(device, deviceBuild); 217 flashExtraImages(device, deviceBuild); 218 checkAndFlashSystem(device, mSystemBuildId, mSystemBuildFlavor, deviceBuild); 219 } 220 buildFastbootCommand(String action, boolean skipReboot, String... args)221 private String[] buildFastbootCommand(String action, boolean skipReboot, String... args) { 222 List<String> cmdArgs = new ArrayList<>(); 223 if ("flash".equals(action) || "update".equals(action) || "flashall".equals(action)) { 224 if (skipReboot) { 225 // need to skip reboot if flashing root ramdisk, because this will be typically 226 // used together with flashing of user build, and 227 cmdArgs.add(SKIP_REBOOT_PARAM); 228 } 229 cmdArgs.addAll(mFlashOptions); 230 } 231 cmdArgs.add(action); 232 cmdArgs.addAll(Arrays.asList(args)); 233 return cmdArgs.toArray(new String[cmdArgs.size()]); 234 } 235 236 /** 237 * Perform any additional pre-flashing setup required. No-op unless overridden. 238 * 239 * @param device the {@link ITestDevice} to prepare 240 * @param deviceBuild the {@link IDeviceBuildInfo} containing the build files 241 * @throws DeviceNotAvailableException 242 * @throws TargetSetupError 243 */ preFlashSetup(ITestDevice device, IDeviceBuildInfo deviceBuild)244 protected void preFlashSetup(ITestDevice device, IDeviceBuildInfo deviceBuild) 245 throws DeviceNotAvailableException, TargetSetupError {} 246 247 /** 248 * Handle flashing of userdata/cache partition 249 * 250 * @param device the {@link ITestDevice} to flash 251 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the files to flash 252 * @throws DeviceNotAvailableException 253 * @throws TargetSetupError 254 */ handleUserDataFlashing(ITestDevice device, IDeviceBuildInfo deviceBuild)255 protected void handleUserDataFlashing(ITestDevice device, IDeviceBuildInfo deviceBuild) 256 throws DeviceNotAvailableException, TargetSetupError { 257 if (UserDataFlashOption.FORCE_WIPE.equals(mUserDataFlashOption) || 258 UserDataFlashOption.WIPE.equals(mUserDataFlashOption)) { 259 CommandResult result = device.executeFastbootCommand(mWipeTimeout, "-w"); 260 handleFastbootResult(device, result, "-w"); 261 } else { 262 flashUserData(device, deviceBuild); 263 wipeCache(device); 264 } 265 } 266 267 /** 268 * Flash an individual partition of a device 269 * 270 * @param device the {@link ITestDevice} to flash 271 * @param imgFile a {@link File} pointing to the image to be flashed 272 * @param partition the name of the partition to be flashed 273 */ flashPartition(ITestDevice device, File imgFile, String partition)274 protected void flashPartition(ITestDevice device, File imgFile, String partition) 275 throws DeviceNotAvailableException, TargetSetupError { 276 CLog.d( 277 "fastboot flash %s %s [size=%d]", 278 partition, imgFile.getAbsolutePath(), imgFile.length()); 279 executeLongFastbootCmd( 280 device, 281 buildFastbootCommand( 282 "flash", mShouldFlashRamdisk, partition, imgFile.getAbsolutePath())); 283 } 284 285 /** 286 * Wipe the specified partition with `fastboot erase <name>` 287 * 288 * @param device the {@link ITestDevice} to operate on 289 * @param partition the name of the partition to be wiped 290 */ wipePartition(ITestDevice device, String partition)291 protected void wipePartition(ITestDevice device, String partition) 292 throws DeviceNotAvailableException, TargetSetupError { 293 String wipeMethod = device.getUseFastbootErase() ? "erase" : "format"; 294 CLog.d("fastboot %s %s", wipeMethod, partition); 295 CommandResult result = device.fastbootWipePartition(partition); 296 handleFastbootResult(device, result, wipeMethod, partition); 297 } 298 299 /** 300 * Checks with the bootloader if the specified partition exists or not 301 * 302 * @param device the {@link ITestDevice} to operate on 303 * @param partition the name of the partition to be checked 304 */ hasPartition(ITestDevice device, String partition)305 protected boolean hasPartition(ITestDevice device, String partition) 306 throws DeviceNotAvailableException { 307 String partitionType = String.format("partition-type:%s", partition); 308 CommandResult result = device.executeFastbootCommand("getvar", partitionType); 309 if (!CommandStatus.SUCCESS.equals(result.getStatus()) 310 || result.getStderr().contains("FAILED")) { 311 return false; 312 } 313 Pattern regex = Pattern.compile(String.format("^%s:\\s*\\S+$", partitionType), 314 Pattern.MULTILINE); 315 return regex.matcher(result.getStderr()).find(); 316 } 317 318 /** 319 * Downloads extra flashing image files needed 320 * 321 * @param device the {@link ITestDevice} to download resources for 322 * @param localBuild the {@link IDeviceBuildInfo} to populate. Assumes device image file is 323 * already set 324 * @throws DeviceNotAvailableException if device is not available 325 * @throws TargetSetupError if failed to retrieve resources 326 */ downloadFlashingResources(ITestDevice device, IDeviceBuildInfo localBuild)327 protected void downloadFlashingResources(ITestDevice device, IDeviceBuildInfo localBuild) 328 throws TargetSetupError, DeviceNotAvailableException { 329 IFlashingResourcesParser resourceParser = createFlashingResourcesParser(localBuild, 330 device.getDeviceDescriptor()); 331 332 if (resourceParser.getRequiredBoards() == null) { 333 throw new TargetSetupError(String.format("Build %s is missing required board info.", 334 localBuild.getDeviceBuildId()), device.getDeviceDescriptor()); 335 } 336 String deviceProductType = device.getProductType(); 337 if (deviceProductType == null) { 338 // treat this as a fatal device error 339 throw new DeviceNotAvailableException( 340 String.format( 341 "Could not determine product type for device %s", 342 device.getSerialNumber()), 343 device.getSerialNumber(), 344 DeviceErrorIdentifier.DEVICE_UNEXPECTED_RESPONSE); 345 } 346 verifyRequiredBoards(device, resourceParser, deviceProductType); 347 348 String bootloaderVersion = resourceParser.getRequiredBootloaderVersion(); 349 // only set bootloader image if this build doesn't have one already 350 // TODO: move this logic to the BuildProvider step 351 if (bootloaderVersion != null && localBuild.getBootloaderImageFile() == null) { 352 CLog.v("Bootloader image was not included in the build artifacts (%s, %s), " 353 + "fetching from blob service instead.", 354 localBuild.getDeviceBuildId(), localBuild.getDeviceBuildFlavor()); 355 localBuild.setBootloaderImageFile( 356 getFlashingResourcesRetriever() 357 .retrieveFile(getBootloaderFilePrefix(device), bootloaderVersion), 358 bootloaderVersion); 359 } 360 String basebandVersion = resourceParser.getRequiredBasebandVersion(); 361 // only set baseband image if this build doesn't have one already 362 if (basebandVersion != null && localBuild.getBasebandImageFile() == null) { 363 CLog.v("Baseband image was not included in the build artifacts (%s, %s), " 364 + "fetching from blob service instead.", 365 localBuild.getDeviceBuildId(), localBuild.getDeviceBuildFlavor()); 366 localBuild.setBasebandImage(getFlashingResourcesRetriever().retrieveFile( 367 BASEBAND_IMAGE_NAME, basebandVersion), basebandVersion); 368 } 369 downloadExtraImageFiles(resourceParser, getFlashingResourcesRetriever(), localBuild); 370 } 371 372 /** 373 * Verify that the device's product type supports the build-to-be-flashed. 374 * 375 * <p>The base implementation will verify that the deviceProductType is included in the {@link 376 * IFlashingResourcesParser#getRequiredBoards()} collection. Subclasses may override as desired. 377 * 378 * @param device the {@link ITestDevice} to be flashed 379 * @param resourceParser the {@link IFlashingResourcesParser} 380 * @param deviceProductType the <var>device</var>'s product type 381 * @throws TargetSetupError if the build's required board info did not match the device 382 */ verifyRequiredBoards( ITestDevice device, IFlashingResourcesParser resourceParser, String deviceProductType)383 protected void verifyRequiredBoards( 384 ITestDevice device, IFlashingResourcesParser resourceParser, String deviceProductType) 385 throws TargetSetupError { 386 if (!containsIgnoreCase(resourceParser.getRequiredBoards(), deviceProductType)) { 387 throw new TargetSetupError( 388 String.format( 389 "Device %s is %s. Expected %s", 390 device.getSerialNumber(), 391 deviceProductType, 392 resourceParser.getRequiredBoards()), 393 device.getDeviceDescriptor(), 394 InfraErrorIdentifier.UNEXPECTED_DEVICE_CONFIGURED); 395 } 396 } 397 containsIgnoreCase(Collection<String> stringList, String anotherString)398 private static boolean containsIgnoreCase(Collection<String> stringList, String anotherString) { 399 for (String aString : stringList) { 400 if (aString != null && aString.equalsIgnoreCase(anotherString)) { 401 return true; 402 } 403 } 404 return false; 405 } 406 407 /** 408 * Hook to allow subclasses to download extra custom image files if needed. 409 * 410 * @param resourceParser the {@link IFlashingResourcesParser} 411 * @param retriever the {@link IFlashingResourcesRetriever} 412 * @param localBuild the {@link IDeviceBuildInfo} 413 * @throws TargetSetupError 414 */ downloadExtraImageFiles(IFlashingResourcesParser resourceParser, IFlashingResourcesRetriever retriever, IDeviceBuildInfo localBuild)415 protected void downloadExtraImageFiles(IFlashingResourcesParser resourceParser, 416 IFlashingResourcesRetriever retriever, IDeviceBuildInfo localBuild) 417 throws TargetSetupError { 418 } 419 420 /** 421 * Factory method for creating a {@link IFlashingResourcesParser}. 422 * <p/> 423 * Exposed for unit testing. 424 * 425 * @param localBuild the {@link IDeviceBuildInfo} to parse 426 * @param descriptor the descriptor of the device being flashed. 427 * @return a {@link IFlashingResourcesParser} created by the factory method. 428 * @throws TargetSetupError 429 */ createFlashingResourcesParser(IDeviceBuildInfo localBuild, DeviceDescriptor descriptor)430 protected IFlashingResourcesParser createFlashingResourcesParser(IDeviceBuildInfo localBuild, 431 DeviceDescriptor descriptor) throws TargetSetupError { 432 try { 433 return new FlashingResourcesParser(localBuild.getDeviceImageFile()); 434 } catch (TargetSetupError e) { 435 // Rethrow with descriptor since FlashingResourceParser doesn't have it. 436 throw new TargetSetupError(e.getMessage(), e, descriptor); 437 } 438 } 439 440 /** 441 * If needed, flash the bootloader image on device. 442 * 443 * <p>Will only flash bootloader if current version on device != required version. 444 * 445 * @param device the {@link ITestDevice} to flash 446 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the bootloader image to flash 447 * @return <code>true</code> if bootloader was flashed, <code>false</code> if it was skipped 448 * @throws DeviceNotAvailableException if device is not available 449 * @throws TargetSetupError if failed to flash bootloader 450 */ checkAndFlashBootloader(ITestDevice device, IDeviceBuildInfo deviceBuild)451 protected boolean checkAndFlashBootloader(ITestDevice device, IDeviceBuildInfo deviceBuild) 452 throws DeviceNotAvailableException, TargetSetupError { 453 String currentBootloaderVersion = getImageVersion(device, "bootloader"); 454 if (deviceBuild.getBootloaderVersion() != null && 455 !deviceBuild.getBootloaderVersion().equals(currentBootloaderVersion)) { 456 CLog.i("Flashing bootloader %s", deviceBuild.getBootloaderVersion()); 457 flashBootloader(device, deviceBuild.getBootloaderImageFile()); 458 if (mIncrementalFlashing != null) { 459 mIncrementalFlashing.notifyBootloaderNeedsRevert(); 460 } 461 return true; 462 } else { 463 CLog.i("Bootloader is already version %s, skipping flashing", currentBootloaderVersion); 464 return false; 465 } 466 } 467 468 /** 469 * Flashes the given bootloader image and reboots back into bootloader 470 * 471 * @param device the {@link ITestDevice} to flash 472 * @param bootloaderImageFile the bootloader image {@link File} 473 * @throws DeviceNotAvailableException if device is not available 474 * @throws TargetSetupError if failed to flash 475 */ flashBootloader(ITestDevice device, File bootloaderImageFile)476 protected void flashBootloader(ITestDevice device, File bootloaderImageFile) 477 throws DeviceNotAvailableException, TargetSetupError { 478 // bootloader images are small, and flash quickly. so use the 'normal' timeout 479 executeFastbootCmd( 480 device, 481 buildFastbootCommand( 482 "flash", 483 mShouldFlashRamdisk, 484 getBootPartitionName(), 485 bootloaderImageFile.getAbsolutePath())); 486 device.rebootIntoBootloader(); 487 } 488 489 /** 490 * Get the boot partition name for this device flasher. 491 * 492 * <p>Defaults to 'bootloader'. Subclasses should override if necessary. 493 */ getBootPartitionName()494 protected String getBootPartitionName() { 495 return "bootloader"; 496 } 497 498 /** 499 * Get the bootloader file prefix. 500 * <p/> 501 * Defaults to {@link #getBootPartitionName()}. Subclasses should override if necessary. 502 * 503 * @param device the {@link ITestDevice} to flash 504 * @throws DeviceNotAvailableException if device is not available 505 * @throws TargetSetupError if failed to get prefix 506 */ getBootloaderFilePrefix(ITestDevice device)507 protected String getBootloaderFilePrefix(ITestDevice device) throws TargetSetupError, 508 DeviceNotAvailableException { 509 return getBootPartitionName(); 510 } 511 512 /** 513 * If needed, flash the baseband image on device. Will only flash baseband if current version on 514 * device != required version 515 * 516 * @param device the {@link ITestDevice} to flash 517 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the baseband image to flash 518 * @throws DeviceNotAvailableException if device is not available 519 * @throws TargetSetupError if failed to flash baseband 520 */ checkAndFlashBaseband(ITestDevice device, IDeviceBuildInfo deviceBuild)521 protected void checkAndFlashBaseband(ITestDevice device, IDeviceBuildInfo deviceBuild) 522 throws DeviceNotAvailableException, TargetSetupError { 523 if (checkShouldFlashBaseband(device, deviceBuild)) { 524 CLog.i("Flashing baseband %s", deviceBuild.getBasebandVersion()); 525 flashBaseband(device, deviceBuild.getBasebandImageFile()); 526 if (mIncrementalFlashing != null) { 527 mIncrementalFlashing.notifyBasebadNeedsRevert(); 528 } 529 } 530 } 531 532 /** 533 * Check if the baseband on the provided device needs to be flashed. 534 * 535 * @param device the {@link ITestDevice} to check 536 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the baseband image to check 537 * @throws DeviceNotAvailableException if device is not available 538 * @throws TargetSetupError if failed to flash baseband 539 */ checkShouldFlashBaseband(ITestDevice device, IDeviceBuildInfo deviceBuild)540 protected boolean checkShouldFlashBaseband(ITestDevice device, IDeviceBuildInfo deviceBuild) 541 throws DeviceNotAvailableException, TargetSetupError { 542 String currentBasebandVersion = getImageVersion(device, "baseband"); 543 boolean shouldFlash = 544 (deviceBuild.getBasebandVersion() != null 545 && !deviceBuild.getBasebandVersion().equals(currentBasebandVersion)); 546 if (!shouldFlash) { 547 CLog.i("Baseband is already version %s, skipping flashing", currentBasebandVersion); 548 } 549 return shouldFlash; 550 } 551 552 /** 553 * Flashes the given baseband image and reboot back into bootloader 554 * 555 * @param device the {@link ITestDevice} to flash 556 * @param basebandImageFile the baseband image {@link File} 557 * @throws DeviceNotAvailableException if device is not available 558 * @throws TargetSetupError if failed to flash baseband 559 */ flashBaseband(ITestDevice device, File basebandImageFile)560 protected void flashBaseband(ITestDevice device, File basebandImageFile) 561 throws DeviceNotAvailableException, TargetSetupError { 562 flashPartition(device, basebandImageFile, BASEBAND_IMAGE_NAME); 563 device.rebootIntoBootloader(); 564 } 565 566 /** 567 * Wipe the cache partition on device. 568 * 569 * @param device the {@link ITestDevice} to flash 570 * @throws DeviceNotAvailableException if device is not available 571 * @throws TargetSetupError if failed to flash cache 572 */ wipeCache(ITestDevice device)573 protected void wipeCache(ITestDevice device) throws DeviceNotAvailableException, 574 TargetSetupError { 575 // only wipe cache if user data is being wiped 576 if (!mUserDataFlashOption.equals(UserDataFlashOption.RETAIN)) { 577 CLog.i("Wiping cache on %s", device.getSerialNumber()); 578 String partition = "cache"; 579 if (hasPartition(device, partition)) { 580 wipePartition(device, partition); 581 } 582 } else { 583 CLog.d("Skipping cache wipe on %s", device.getSerialNumber()); 584 } 585 } 586 587 /** 588 * Flash userdata partition on device. 589 * 590 * @param device the {@link ITestDevice} to flash 591 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the files to flash 592 * @throws DeviceNotAvailableException if device is not available 593 * @throws TargetSetupError if failed to flash user data 594 */ flashUserData(ITestDevice device, IDeviceBuildInfo deviceBuild)595 protected void flashUserData(ITestDevice device, IDeviceBuildInfo deviceBuild) 596 throws DeviceNotAvailableException, TargetSetupError { 597 switch (mUserDataFlashOption) { 598 case FLASH: 599 CLog.i("Flashing %s with userdata %s", device.getSerialNumber(), 600 deviceBuild.getUserDataImageFile().getAbsolutePath()); 601 flashPartition(device, deviceBuild.getUserDataImageFile(), "userdata"); 602 break; 603 case FLASH_IMG_ZIP: 604 flashUserDataFromDeviceImageFile(device, deviceBuild); 605 break; 606 case FORCE_WIPE: // intentional fallthrough 607 case WIPE: 608 CLog.i("Wiping userdata %s", device.getSerialNumber()); 609 wipePartition(device, "userdata"); 610 break; 611 612 case TESTS_ZIP: 613 device.rebootUntilOnline(); // required to install tests 614 if (device.isEncryptionSupported() && device.isDeviceEncrypted()) { 615 device.unlockDevice(); 616 } 617 getTestsZipInstaller().pushTestsZipOntoData(device, deviceBuild); 618 // Reboot into bootloader to continue the flashing process 619 device.rebootIntoBootloader(); 620 break; 621 622 case WIPE_RM: 623 device.rebootUntilOnline(); // required to install tests 624 getTestsZipInstaller().deleteData(device); 625 // Reboot into bootloader to continue the flashing process 626 device.rebootIntoBootloader(); 627 break; 628 629 default: 630 CLog.d("Skipping userdata flash for %s", device.getSerialNumber()); 631 } 632 } 633 634 /** 635 * Extracts the userdata.img from device image file and flashes it onto device 636 * 637 * @param device the {@link ITestDevice} to flash 638 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the files to flash 639 * @throws DeviceNotAvailableException if device is not available 640 * @throws TargetSetupError if failed to extract or flash user data 641 */ flashUserDataFromDeviceImageFile( ITestDevice device, IDeviceBuildInfo deviceBuild)642 protected void flashUserDataFromDeviceImageFile( 643 ITestDevice device, IDeviceBuildInfo deviceBuild) 644 throws DeviceNotAvailableException, TargetSetupError { 645 File userdataImg = null; 646 try { 647 try (ZipFile zip = new ZipFile(deviceBuild.getDeviceImageFile())) { 648 userdataImg = ZipUtil2.extractFileFromZip(zip, "userdata.img"); 649 } catch (IOException ioe) { 650 throw new TargetSetupError("failed to extract userdata.img from image file", ioe, 651 device.getDeviceDescriptor()); 652 } 653 CLog.i("Flashing %s with userdata %s", device.getSerialNumber(), userdataImg); 654 flashPartition(device, userdataImg, "userdata"); 655 } finally { 656 FileUtil.deleteFile(userdataImg); 657 } 658 } 659 660 /** 661 * Flash any device specific partitions before flashing system and rebooting. No-op unless 662 * overridden. 663 * 664 * @param device the {@link ITestDevice} to flash 665 * @param deviceBuild the {@link IDeviceBuildInfo} containing the build files 666 * @throws DeviceNotAvailableException 667 * @throws TargetSetupError 668 */ flashExtraImages(ITestDevice device, IDeviceBuildInfo deviceBuild)669 protected void flashExtraImages(ITestDevice device, IDeviceBuildInfo deviceBuild) 670 throws DeviceNotAvailableException, TargetSetupError {} 671 672 /** 673 * If needed, flash the system image on device. 674 * 675 * <p>Please look at {@link #shouldFlashSystem(String, String, IDeviceBuildInfo)} 676 * 677 * <p>Regardless of path chosen, after method execution device should be booting into userspace. 678 * 679 * @param device the {@link ITestDevice} to flash 680 * @param systemBuildId the current build id running on the device 681 * @param systemBuildFlavor the current build flavor running on the device 682 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the system image to flash 683 * @return <code>true</code> if system was flashed, <code>false</code> if it was skipped 684 * @throws DeviceNotAvailableException if device is not available 685 * @throws TargetSetupError if failed to flash bootloader 686 */ checkAndFlashSystem( ITestDevice device, String systemBuildId, String systemBuildFlavor, IDeviceBuildInfo deviceBuild)687 protected boolean checkAndFlashSystem( 688 ITestDevice device, 689 String systemBuildId, 690 String systemBuildFlavor, 691 IDeviceBuildInfo deviceBuild) 692 throws DeviceNotAvailableException, TargetSetupError { 693 if (shouldFlashSystem(systemBuildId, systemBuildFlavor, deviceBuild)) { 694 CLog.i("Flashing system %s", deviceBuild.getDeviceBuildId()); 695 flashSystem(device, deviceBuild); 696 return true; 697 } 698 CLog.i( 699 "System is already version %s and build flavor %s, skipping flashing", 700 systemBuildId, systemBuildFlavor); 701 if (mShouldFlashRamdisk) { 702 // even if we don't flash system, still flash ramdisk just in case: because the fact 703 // that the system had a different ramdisk won't be captured by a simple build check 704 flashRamdiskIfNeeded(device, deviceBuild); 705 CLog.i("Flashed ramdisk anyways per flasher settings."); 706 } 707 // reboot 708 device.rebootUntilOnline(); 709 return false; 710 } 711 712 /** 713 * Helper method used to determine if we need to flash the system image. 714 * 715 * @param systemBuildId the current build id running on the device 716 * @param systemBuildFlavor the current build flavor running on the device 717 * @param deviceBuild the {@link IDeviceBuildInfo} that contains the system image to flash 718 * @return <code>true</code> if we should flash the system, <code>false</code> otherwise. 719 */ shouldFlashSystem(String systemBuildId, String systemBuildFlavor, IDeviceBuildInfo deviceBuild)720 boolean shouldFlashSystem(String systemBuildId, String systemBuildFlavor, 721 IDeviceBuildInfo deviceBuild) { 722 if (mForceSystemFlash) { 723 // Flag overrides all logic. 724 return true; 725 } 726 // Err on the side of caution, if we failed to get the build id or build flavor, force a 727 // flash of the system. 728 if (systemBuildFlavor == null || systemBuildId == null) { 729 return true; 730 } 731 // If we have the same build id and build flavor we don't need to flash it. 732 if (systemBuildId.equals(deviceBuild.getDeviceBuildId())) { 733 FileCacheTracker tracker = 734 DeviceImageTracker.getDefaultCache() 735 .getBaselineDeviceImage(deviceBuild.getDeviceSerial()); 736 if (tracker != null 737 && tracker.buildId.equals(systemBuildId) 738 && tracker.flavor.equals(deviceBuild.getBuildFlavor())) { 739 if (mIncrementalFlashing != null 740 && mIncrementalFlashing.isSameBuildFlashingAllowed()) { 741 CLog.d("Same build incremental flashing is allowed"); 742 return true; 743 } 744 return false; 745 } 746 if (systemBuildFlavor.equalsIgnoreCase(deviceBuild.getBuildFlavor())) { 747 return false; 748 } 749 } 750 return true; 751 } 752 753 /** 754 * Flash the system image on device. 755 * 756 * @param device the {@link ITestDevice} to flash 757 * @param deviceBuild the {@link IDeviceBuildInfo} to flash 758 * @throws DeviceNotAvailableException if device is not available 759 * @throws TargetSetupError if fastboot command fails 760 */ flashSystem(ITestDevice device, IDeviceBuildInfo deviceBuild)761 protected void flashSystem(ITestDevice device, IDeviceBuildInfo deviceBuild) 762 throws DeviceNotAvailableException, TargetSetupError { 763 CLog.i( 764 "Flashing device %s with image %s", 765 device.getSerialNumber(), deviceBuild.getDeviceImageFile().getAbsolutePath()); 766 // give extra time to the update cmd 767 boolean tookPermit = false; 768 try (CloseableTraceScope ignored = new CloseableTraceScope("flash_system")) { 769 boolean shouldFlash = true; 770 if (mIncrementalFlashing != null) { 771 try { 772 mIncrementalFlashing.updateDevice( 773 deviceBuild.getBootloaderImageFile(), 774 deviceBuild.getBasebandImageFile()); 775 shouldFlash = false; 776 } catch (TargetSetupError e) { 777 // In case of TargetSetupError for incremental flashing, 778 // fallback to full flashing. 779 CLog.e(e); 780 DeviceImageTracker.getDefaultCache() 781 .invalidateTracking(device.getSerialNumber()); 782 if (TestDeviceState.ONLINE.equals(device.getDeviceState())) { 783 device.rebootIntoBootloader(); 784 } 785 } 786 } 787 long startWait = System.currentTimeMillis(); 788 if (shouldFlash && mIncrementalFlashing != null) { 789 // Take the permit in case of fallback from incremental 790 try (CloseableTraceScope waitFor = 791 new CloseableTraceScope("wait_for_flashing_permit")) { 792 // Only #flash is included in the critical section 793 getHostOptions().takePermit(PermitLimitType.CONCURRENT_FLASHER); 794 tookPermit = true; 795 long queueTime = System.currentTimeMillis() - startWait; 796 CLog.v( 797 "Flashing permit obtained after %ds", 798 TimeUnit.MILLISECONDS.toSeconds(queueTime)); 799 InvocationMetricLogger.addInvocationMetrics( 800 InvocationMetricKey.FLASHING_PERMIT_LATENCY, queueTime); 801 } 802 } 803 if (shouldFlash) { 804 if (deviceBuild.getDeviceImageFile().isDirectory()) { 805 InvocationMetricLogger.addInvocationMetrics( 806 InvocationMetricKey.FLASHING_METHOD, 807 FlashingMethod.FASTBOOT_FLASH_ALL.toString()); 808 flashWithAll(device, deviceBuild); 809 } else if (getHostOptions().shouldFlashWithFuseZip() 810 && getFuseUtil().canMountZip()) { 811 InvocationMetricLogger.addInvocationMetrics( 812 InvocationMetricKey.FLASHING_METHOD, 813 FlashingMethod.FASTBOOT_FLASH_ALL_FUSE_ZIP.toString()); 814 flashWithFuseZip(device, deviceBuild); 815 } else { 816 InvocationMetricLogger.addInvocationMetrics( 817 InvocationMetricKey.FLASHING_METHOD, 818 FlashingMethod.FASTBOOT_UPDATE.toString()); 819 flashWithUpdateCommand(device, deviceBuild); 820 } 821 } 822 flashRamdiskIfNeeded(device, deviceBuild); 823 // only transfer last fastboot command status over to system flash status after having 824 // flashing the system partitions 825 mSystemFlashStatus = mFbCmdStatus; 826 } finally { 827 // if system flash status is still null here, an exception has happened 828 if (mSystemFlashStatus == null) { 829 mSystemFlashStatus = CommandStatus.EXCEPTION; 830 } 831 if (tookPermit) { 832 getHostOptions().returnPermit(PermitLimitType.CONCURRENT_FLASHER); 833 } 834 } 835 } 836 837 /** 838 * Flash the system image on device by using an image directory with fastboot flashall command. 839 * 840 * @param device the {@link ITestDevice} to flash 841 * @param deviceBuild the {@link IDeviceBuildInfo} to flash 842 * @throws DeviceNotAvailableException if device is not available 843 * @throws TargetSetupError if fastboot command fails 844 */ flashWithAll(ITestDevice device, IDeviceBuildInfo deviceBuild)845 private void flashWithAll(ITestDevice device, IDeviceBuildInfo deviceBuild) 846 throws DeviceNotAvailableException, TargetSetupError { 847 try { 848 Map<String, String> systemVarMap = new HashMap<>(); 849 systemVarMap.put( 850 "ANDROID_PRODUCT_OUT", deviceBuild.getDeviceImageFile().getAbsolutePath()); 851 String[] fastbootArgs = buildFastbootCommand("flashall", mShouldFlashRamdisk); 852 executeLongFastbootCmd(device, systemVarMap, fastbootArgs); 853 } catch (DeviceNotAvailableException e) { 854 // We wrap the exception from recovery if it fails to provide a clear message 855 throw new DeviceNotAvailableException( 856 "Device became unavailable during fastboot 'flashall'. Please verify that " 857 + "the image you are flashing can boot properly.", 858 e, 859 device.getSerialNumber()); 860 } 861 } 862 863 /** 864 * Flash the system image on device by using fuse-zip mounting with fastboot flashall command. 865 * 866 * @param device the {@link ITestDevice} to flash 867 * @param deviceBuild the {@link IDeviceBuildInfo} to flash 868 * @throws DeviceNotAvailableException if device is not available 869 * @throws TargetSetupError if fastboot command fails 870 */ flashWithFuseZip(ITestDevice device, IDeviceBuildInfo deviceBuild)871 private void flashWithFuseZip(ITestDevice device, IDeviceBuildInfo deviceBuild) 872 throws DeviceNotAvailableException, TargetSetupError { 873 FuseUtil fuseUtil = getFuseUtil(); 874 File mountPoint = null; 875 Throwable exception = null; 876 try { 877 mountPoint = FileUtil.createTempDir("FlashAllMountPoint"); 878 fuseUtil.mountZip(deviceBuild.getDeviceImageFile().getAbsoluteFile(), mountPoint); 879 Map<String, String> systemVarMap = new HashMap<>(); 880 systemVarMap.put("ANDROID_PRODUCT_OUT", mountPoint.getAbsolutePath()); 881 String[] fastbootArgs = buildFastbootCommand("flashall", mShouldFlashRamdisk); 882 executeLongFastbootCmd(device, systemVarMap, fastbootArgs); 883 } catch (DeviceNotAvailableException e) { 884 // We wrap the exception from recovery if it fails to provide a clear message 885 exception = e; 886 throw new DeviceNotAvailableException( 887 "Device became unavailable during fastboot 'flashall'. Please verify that " 888 + "the image you are flashing can boot properly.", 889 e, 890 device.getSerialNumber()); 891 } catch (IOException e) { 892 exception = e; 893 throw new TargetSetupError( 894 String.format( 895 "Unable to create a temp dir for fuse zip to mount on, error: %s", 896 e.getMessage()), 897 InfraErrorIdentifier.FAIL_TO_CREATE_FILE); 898 } finally { 899 if (mountPoint != null) { 900 fuseUtil.unmountZip(mountPoint); 901 FileUtil.recursiveDelete(mountPoint); 902 } 903 // In case the unmount operation fails, deleting the mount point will fail as well. 904 if (mountPoint.exists()) { 905 String mountErrorMsg = 906 String.format( 907 "Failed to delete mount point %s, unmount operation might failed.", 908 mountPoint); 909 if (exception != null) { 910 // If a previous exception happened, surface the previous exception only 911 CLog.e(mountErrorMsg); 912 } else { 913 throw new HarnessRuntimeException( 914 mountErrorMsg, InfraErrorIdentifier.LAB_HOST_FILESYSTEM_ERROR); 915 } 916 } 917 } 918 } 919 920 /** 921 * Flash the system image on device by using fastboot update command. 922 * 923 * @param device the {@link ITestDevice} to flash 924 * @param deviceBuild the {@link IDeviceBuildInfo} to flash 925 * @throws DeviceNotAvailableException if device is not available 926 * @throws TargetSetupError if fastboot command fails 927 */ flashWithUpdateCommand(ITestDevice device, IDeviceBuildInfo deviceBuild)928 private void flashWithUpdateCommand(ITestDevice device, IDeviceBuildInfo deviceBuild) 929 throws DeviceNotAvailableException, TargetSetupError { 930 try { 931 executeLongFastbootCmd( 932 device, 933 buildFastbootCommand( 934 "update", 935 mShouldFlashRamdisk, 936 deviceBuild.getDeviceImageFile().getAbsolutePath())); 937 } catch (DeviceNotAvailableException e) { 938 // We wrap the exception from recovery if it fails to provide a clear message 939 throw new DeviceNotAvailableException( 940 "Device became unavailable during fastboot 'update'. Please verify that " 941 + "the image you are flashing can boot properly.", 942 e, 943 device.getSerialNumber()); 944 } 945 } 946 947 /** 948 * Helper method to get the current image version on device. 949 * 950 * @param device the {@link ITestDevice} to execute command on 951 * @param imageName the name of image to get. 952 * @return String the stdout output from command 953 * @throws DeviceNotAvailableException if device is not available 954 * @throws TargetSetupError if fastboot command fails or version could not be determined 955 */ getImageVersion(ITestDevice device, String imageName)956 protected String getImageVersion(ITestDevice device, String imageName) 957 throws DeviceNotAvailableException, TargetSetupError { 958 int attempts = 0; 959 String versionQuery = String.format("version-%s", imageName); 960 String patternString = String.format("%s:\\s(.*)\\s", versionQuery); 961 Pattern versionOutputPattern = Pattern.compile(patternString); 962 963 while (attempts < MAX_RETRY_ATTEMPTS) { 964 String queryOutput = executeFastbootCmd(device, "getvar", versionQuery); 965 Matcher matcher = versionOutputPattern.matcher(queryOutput); 966 if (matcher.find()) { 967 return matcher.group(1); 968 } else { 969 attempts++; 970 CLog.w( 971 "Could not find version for '%s'. Output '%s', retrying.", 972 imageName, queryOutput); 973 getRunUtil().sleep(RETRY_SLEEP * (attempts - 1) 974 + new Random(System.currentTimeMillis()).nextInt(RETRY_SLEEP)); 975 continue; 976 } 977 } 978 throw new TargetSetupError(String.format( 979 "Could not find version for '%s' after %d retry attempts", imageName, attempts), 980 device.getDeviceDescriptor()); 981 } 982 983 /** 984 * Helper method to retrieve the current slot (for A/B capable devices). 985 * 986 * @param device the {@link ITestDevice} to execute command on. 987 * @return "a", "b" or null (if device is not A/B capable) 988 * @throws DeviceNotAvailableException 989 * @throws TargetSetupError 990 */ getCurrentSlot(ITestDevice device)991 protected String getCurrentSlot(ITestDevice device) 992 throws DeviceNotAvailableException, TargetSetupError { 993 Matcher matcher; 994 if (device.getDeviceState().equals(TestDeviceState.FASTBOOT)) { 995 String queryOutput = executeFastbootCmd(device, "getvar", SLOT_VAR); 996 Pattern outputPattern = Pattern.compile(String.format("^%s: _?([ab])", SLOT_VAR)); 997 matcher = outputPattern.matcher(queryOutput); 998 } else { 999 String queryOutput = device.executeShellCommand(String.format("getprop %s", SLOT_PROP)); 1000 Pattern outputPattern = 1001 Pattern.compile(String.format("^\\[%s\\]: \\[_?([ab])\\]", SLOT_PROP)); 1002 matcher = outputPattern.matcher(queryOutput); 1003 } 1004 if (matcher.find()) { 1005 return matcher.group(1); 1006 } else { 1007 return null; 1008 } 1009 } 1010 1011 /** Exposed for testing. */ getRunUtil()1012 protected IRunUtil getRunUtil() { 1013 return RunUtil.getDefault(); 1014 } 1015 1016 /** 1017 * Helper method to execute fastboot command. 1018 * 1019 * @param device the {@link ITestDevice} to execute command on 1020 * @param cmdArgs the arguments to provide to fastboot 1021 * @return String the stderr output from command if non-empty. Otherwise returns the stdout Some 1022 * fastboot commands are weird in that they dump output to stderr on success case 1023 * @throws DeviceNotAvailableException if device is not available 1024 * @throws TargetSetupError if fastboot command fails 1025 */ executeFastbootCmd(ITestDevice device, String... cmdArgs)1026 protected String executeFastbootCmd(ITestDevice device, String... cmdArgs) 1027 throws DeviceNotAvailableException, TargetSetupError { 1028 CLog.v("Executing short fastboot command %s", java.util.Arrays.toString(cmdArgs)); 1029 CommandResult result = device.executeFastbootCommand(cmdArgs); 1030 return handleFastbootResult(device, result, cmdArgs); 1031 } 1032 1033 /** 1034 * Helper method to execute a long-running fastboot command. 1035 * 1036 * <p>Note: Most fastboot commands normally execute within the timeout allowed by {@link 1037 * ITestDevice#executeFastbootCommand(String...)}. However, when multiple devices are flashing 1038 * devices at once, fastboot commands can take much longer than normal. 1039 * 1040 * @param device the {@link ITestDevice} to execute command on 1041 * @param cmdArgs the arguments to provide to fastboot 1042 * @return String the stderr output from command if non-empty. Otherwise returns the stdout Some 1043 * fastboot commands are weird in that they dump output to stderr on success case 1044 * @throws DeviceNotAvailableException if device is not available 1045 * @throws TargetSetupError if fastboot command fails 1046 */ executeLongFastbootCmd(ITestDevice device, String... cmdArgs)1047 protected String executeLongFastbootCmd(ITestDevice device, String... cmdArgs) 1048 throws DeviceNotAvailableException, TargetSetupError { 1049 return executeLongFastbootCmd(device, new HashMap<>(), cmdArgs); 1050 } 1051 1052 /** 1053 * Helper method to execute a long-running fastboot command with environment variables. 1054 * 1055 * <p>Note: Most fastboot commands normally execute within the timeout allowed by {@link 1056 * ITestDevice#executeFastbootCommand(String...)}. However, when multiple devices are flashing 1057 * devices at once, fastboot commands can take much longer than normal. 1058 * 1059 * @param device the {@link ITestDevice} to execute command on 1060 * @param envVarMap the map which carries environment variables which need to be set before 1061 * running the fastboot command 1062 * @param cmdArgs the arguments to provide to fastboot 1063 * @return String the stderr output from command if non-empty. Otherwise returns the stdout Some 1064 * fastboot commands are weird in that they dump output to stderr on success case 1065 * @throws DeviceNotAvailableException if device is not available 1066 * @throws TargetSetupError if fastboot command fails 1067 */ executeLongFastbootCmd( ITestDevice device, Map<String, String> envVarMap, String... cmdArgs)1068 protected String executeLongFastbootCmd( 1069 ITestDevice device, Map<String, String> envVarMap, String... cmdArgs) 1070 throws DeviceNotAvailableException, TargetSetupError { 1071 CommandResult result = device.executeLongFastbootCommand(envVarMap, cmdArgs); 1072 return handleFastbootResult(device, result, cmdArgs); 1073 } 1074 1075 /** 1076 * Interpret the result of a fastboot command 1077 * 1078 * @param device 1079 * @param result 1080 * @param cmdArgs 1081 * @return the stderr output from command if non-empty. Otherwise returns the stdout 1082 * @throws TargetSetupError 1083 */ 1084 @VisibleForTesting handleFastbootResult(ITestDevice device, CommandResult result, String... cmdArgs)1085 String handleFastbootResult(ITestDevice device, CommandResult result, String... cmdArgs) 1086 throws TargetSetupError { 1087 CLog.v("fastboot stdout: " + result.getStdout()); 1088 CLog.v("fastboot stderr: " + result.getStderr()); 1089 mFbCmdStatus = result.getStatus(); 1090 ErrorIdentifier errorIdentifier = null; 1091 boolean diskErrorIdentified = false; 1092 for (String diskError : DISK_SPACE_ERRORS) { 1093 if (result.getStderr().contains(diskError)) { 1094 errorIdentifier = InfraErrorIdentifier.NO_DISK_SPACE; 1095 mFbCmdStatus = CommandStatus.FAILED; 1096 diskErrorIdentified = true; 1097 break; 1098 } 1099 } 1100 1101 if (!diskErrorIdentified && result.getStderr().contains("FAILED")) { 1102 // if output contains "FAILED", just override to failure 1103 mFbCmdStatus = CommandStatus.FAILED; 1104 } 1105 if (mFbCmdStatus != CommandStatus.SUCCESS) { 1106 if (errorIdentifier == null) { 1107 errorIdentifier = DeviceErrorIdentifier.ERROR_AFTER_FLASHING; 1108 } 1109 throw new TargetSetupError( 1110 String.format( 1111 "fastboot command %s failed in device %s. stdout: %s, stderr: %s", 1112 cmdArgs[0], 1113 device.getSerialNumber(), 1114 result.getStdout(), 1115 result.getStderr()), 1116 device.getDeviceDescriptor(), 1117 errorIdentifier); 1118 } 1119 if (result.getStderr().length() > 0) { 1120 return result.getStderr(); 1121 } else { 1122 return result.getStdout(); 1123 } 1124 } 1125 1126 /** 1127 * {@inheritDoc} 1128 */ 1129 @Override overrideDeviceOptions(ITestDevice device)1130 public void overrideDeviceOptions(ITestDevice device) { 1131 // ignore 1132 } 1133 1134 /** 1135 * {@inheritDoc} 1136 */ 1137 @Override setForceSystemFlash(boolean forceSystemFlash)1138 public void setForceSystemFlash(boolean forceSystemFlash) { 1139 mForceSystemFlash = forceSystemFlash; 1140 } 1141 1142 /** 1143 * {@inheritDoc} 1144 */ 1145 @Override setDataWipeSkipList(Collection<String> dataWipeSkipList)1146 public void setDataWipeSkipList(Collection<String> dataWipeSkipList) { 1147 if (dataWipeSkipList == null) { 1148 dataWipeSkipList = new ArrayList<String>(); 1149 } 1150 if (dataWipeSkipList.isEmpty()) { 1151 // To maintain backwards compatibility. 1152 // TODO: deprecate and remove. 1153 dataWipeSkipList.add("media"); 1154 } 1155 mDataWipeSkipList = dataWipeSkipList; 1156 } 1157 1158 /** 1159 * {@inheritDoc} 1160 */ 1161 @Override setWipeTimeout(long timeout)1162 public void setWipeTimeout(long timeout) { 1163 mWipeTimeout = timeout; 1164 } 1165 1166 /** 1167 * {@inheritDoc} 1168 */ 1169 @Override getSystemFlashingStatus()1170 public CommandStatus getSystemFlashingStatus() { 1171 return mSystemFlashStatus; 1172 } 1173 1174 /** {@inheritDoc} */ 1175 @Override setShouldFlashRamdisk(boolean shouldFlashRamdisk)1176 public void setShouldFlashRamdisk(boolean shouldFlashRamdisk) { 1177 mShouldFlashRamdisk = shouldFlashRamdisk; 1178 } 1179 1180 /** {@inheritDoc} */ 1181 @Override setRamdiskPartition(String ramdiskPartition)1182 public void setRamdiskPartition(String ramdiskPartition) { 1183 mRamdiskPartition = ramdiskPartition; 1184 } 1185 1186 /** {@inheritDoc} */ 1187 @Override shouldFlashRamdisk()1188 public boolean shouldFlashRamdisk() { 1189 return mShouldFlashRamdisk; 1190 } 1191 flashRamdiskIfNeeded(ITestDevice device, IDeviceBuildInfo deviceBuild)1192 protected void flashRamdiskIfNeeded(ITestDevice device, IDeviceBuildInfo deviceBuild) 1193 throws TargetSetupError, DeviceNotAvailableException { 1194 if (mShouldFlashRamdisk) { 1195 // Flash ramdisk in bootloader 1196 device.rebootIntoBootloader(); 1197 executeLongFastbootCmd( 1198 device, 1199 "flash", 1200 mRamdiskPartition, 1201 deviceBuild.getRamdiskFile().getAbsolutePath()); 1202 device.reboot(); 1203 } 1204 } 1205 setSystemBuildInfo(String systemBuildId, String systemBuildFlavor)1206 protected void setSystemBuildInfo(String systemBuildId, String systemBuildFlavor) { 1207 mSystemBuildId = systemBuildId; 1208 mSystemBuildFlavor = systemBuildFlavor; 1209 } 1210 1211 /** Gets the {@link IHostOptions} instance to use. */ 1212 @VisibleForTesting getHostOptions()1213 IHostOptions getHostOptions() { 1214 return GlobalConfiguration.getInstance().getHostOptions(); 1215 } 1216 } 1217