• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.annotations.VisibleForTesting;
20 import com.android.tradefed.build.IBuildInfo;
21 import com.android.tradefed.build.IDeviceBuildInfo;
22 import com.android.tradefed.config.GlobalConfiguration;
23 import com.android.tradefed.config.IConfiguration;
24 import com.android.tradefed.config.IConfigurationReceiver;
25 import com.android.tradefed.config.IDeviceConfiguration;
26 import com.android.tradefed.config.Option;
27 import com.android.tradefed.device.DeviceNotAvailableException;
28 import com.android.tradefed.device.ITestDevice;
29 import com.android.tradefed.device.ITestDevice.RecoveryMode;
30 import com.android.tradefed.device.NullDevice;
31 import com.android.tradefed.device.SnapuserdWaitPhase;
32 import com.android.tradefed.device.TestDeviceState;
33 import com.android.tradefed.error.HarnessRuntimeException;
34 import com.android.tradefed.host.IHostOptions;
35 import com.android.tradefed.host.IHostOptions.PermitLimitType;
36 import com.android.tradefed.invoker.TestInformation;
37 import com.android.tradefed.invoker.logger.CurrentInvocation.IsolationGrade;
38 import com.android.tradefed.invoker.logger.InvocationMetricLogger;
39 import com.android.tradefed.invoker.logger.InvocationMetricLogger.InvocationMetricKey;
40 import com.android.tradefed.invoker.tracing.CloseableTraceScope;
41 import com.android.tradefed.log.ITestLogger;
42 import com.android.tradefed.log.LogUtil.CLog;
43 import com.android.tradefed.result.ITestLoggerReceiver;
44 import com.android.tradefed.result.error.DeviceErrorIdentifier;
45 import com.android.tradefed.result.error.InfraErrorIdentifier;
46 import com.android.tradefed.retry.BaseRetryDecision;
47 import com.android.tradefed.targetprep.IDeviceFlasher.UserDataFlashOption;
48 import com.android.tradefed.util.CommandResult;
49 import com.android.tradefed.util.CommandStatus;
50 import com.android.tradefed.util.IRunUtil;
51 import com.android.tradefed.util.RunUtil;
52 import com.android.tradefed.util.image.DeviceImageTracker;
53 import com.android.tradefed.util.image.IncrementalImageUtil;
54 
55 import java.io.File;
56 import java.util.ArrayList;
57 import java.util.Collection;
58 import java.util.HashSet;
59 import java.util.Set;
60 import java.util.concurrent.TimeUnit;
61 
62 /** A {@link ITargetPreparer} that flashes an image on physical Android hardware. */
63 public abstract class DeviceFlashPreparer extends BaseTargetPreparer
64         implements IConfigurationReceiver, ITestLoggerReceiver {
65 
66     private static final int BOOT_POLL_TIME_MS = 5 * 1000;
67     private static final long SNAPSHOT_CANCEL_TIMEOUT = 20000L;
68 
69     @Option(
70         name = "device-boot-time",
71         description = "max time to wait for device to boot.",
72         isTimeVal = true
73     )
74     private long mDeviceBootTime = 5 * 60 * 1000;
75 
76     @Option(name = "userdata-flash", description =
77         "specify handling of userdata partition.")
78     private UserDataFlashOption mUserDataFlashOption = UserDataFlashOption.FLASH;
79 
80     @Option(name = "force-system-flash", description =
81         "specify if system should always be flashed even if already running desired build.")
82     private boolean mForceSystemFlash = false;
83 
84     /*
85      * A temporary workaround for special builds. Should be removed after changes from build team.
86      * Bug: 18078421
87      */
88     @Deprecated
89     @Option(
90             name = "skip-post-flash-flavor-check",
91             description = "specify if system flavor should not be checked after flash")
92     private boolean mSkipPostFlashFlavorCheck = false;
93 
94     /*
95      * Used for update testing
96      */
97     @Option(name = "skip-post-flash-build-id-check", description =
98             "specify if build ID should not be checked after flash")
99     private boolean mSkipPostFlashBuildIdCheck = false;
100 
101     @Option(name = "wipe-skip-list", description =
102         "list of /data subdirectories to NOT wipe when doing UserDataFlashOption.TESTS_ZIP")
103     private Collection<String> mDataWipeSkipList = new ArrayList<>();
104 
105     /**
106      * @deprecated use host-options:concurrent-flasher-limit.
107      */
108     @Deprecated
109     @Option(name = "concurrent-flasher-limit", description =
110         "No-op, do not use. Left for backwards compatibility.")
111     private Integer mConcurrentFlasherLimit = null;
112 
113     @Option(name = "skip-post-flashing-setup",
114             description = "whether or not to skip post-flashing setup steps")
115     private boolean mSkipPostFlashingSetup = false;
116 
117     @Option(name = "wipe-timeout",
118             description = "the timeout for the command of wiping user data.", isTimeVal = true)
119     private long mWipeTimeout = 4 * 60 * 1000;
120 
121     @Option(
122         name = "fastboot-flash-option",
123         description = "additional options to pass with fastboot flash/update command."
124     )
125     private Collection<String> mFastbootFlashOptions = new ArrayList<>();
126 
127     @Option(
128             name = "flash-ramdisk",
129             description =
130                     "flashes ramdisk (usually on boot partition) in addition to "
131                             + "regular system image")
132     private boolean mShouldFlashRamdisk = false;
133 
134     @Option(
135             name = "ramdisk-partition",
136             description =
137                     "the partition (such as boot, vendor_boot) that ramdisk image "
138                             + "should be flashed to")
139     private String mRamdiskPartition = "boot";
140 
141     @Option(
142             name = "cancel-ota-snapshot",
143             description = "In case an OTA snapshot is in progress, cancel it.")
144     private boolean mCancelSnapshot = false;
145 
146     @Option(
147             name = "incremental-flashing",
148             description = "Leverage the incremental flashing feature for device update.")
149     private boolean mUseIncrementalFlashing = false;
150 
151     @Option(
152             name = "force-disable-incremental-flashing",
153             description = "Ignore HostOptions and disable the feature if true.")
154     private boolean mForceDisableIncrementalFlashing = false;
155 
156     @Option(
157             name = "create-snapshot-binary",
158             description = "Override the create_snapshot binary for incremental flashing.")
159     private File mCreateSnapshotBinary = null;
160 
161     @Option(
162             name = "allow-incremental-same-build",
163             description = "Allow doing incremental update on same build.")
164     private boolean mAllowIncrementalOnSameBuild = false;
165 
166     @Option(
167             name = "allow-incremental-cross-release",
168             description = "Allow doing incremental update across release build configs.")
169     private boolean mAllowIncrementalCrossRelease = true;
170 
171     @Option(
172             name = "allow-trackerless-update",
173             description = "Allow doing incremental update without a baseline known on the host.")
174     private boolean mAllowTrackerlessUpdate = true;
175 
176     @Option(
177             name = "ignore-incremental-host-options",
178             description =
179                     "Ignore the HostOptions to disable incremental flashing. This can be useful for"
180                             + " boot tests in various environments.")
181     private boolean mIgnoreHostOptions = false;
182 
183     @Option(
184             name = "apply-snapshot",
185             description =
186                     "Whether to apply the snapshot after mounting it. "
187                             + "This changes the baseline and does require reverting.")
188     private boolean mApplySnapshot = true;
189 
190     @Option(
191             name = "wipe-after-apply-snapshot",
192             description = "Whether to issue a wipe after applying snapshots.")
193     private boolean mWipeAfterApplySnapshot = true;
194 
195     @Option(
196             name = "use-new-incremental-update-flow",
197             description = "A new update flow possible with latest incremental features.")
198     private boolean mNewIncrementalFlow = true;
199 
200     @Option(
201             name = "update-bootloader-in-userspace",
202             description = "Allow to update bootloader in userspace in new flow of incremental.")
203     private boolean mUpdateBootloaderFromUserspace = false;
204 
205     @Option(
206             name = "snapuserd-wait-phase",
207             description =
208                     "Only applicable to apply-snapshot, blocks snapuserd until a specified phase.")
209     private SnapuserdWaitPhase mWaitPhase = SnapuserdWaitPhase.BLOCK_BEFORE_RELEASING;
210 
211     @Option(
212             name = "allow-unzip-baseline",
213             description = "Whether to allow tracking the baseline as unzipped or not.")
214     private boolean mAllowUnzippedBaseline = true;
215 
216     @Option(
217             name = "enforce-snapshot-completed",
218             description = "Test mode was snapshot to ensure the logic was used and throw if not.")
219     private boolean mEnforceSnapshotCompleted = false;
220 
221     @Option(
222             name = "use-merkle-tree-comparison",
223             description = "Generate snapshot using the merkle tree on device instead of baseline.")
224     private boolean mUseMerkleTreeComparison = true;
225 
226     private IncrementalImageUtil mIncrementalImageUtil;
227     private IConfiguration mConfig;
228     private Set<String> mAllowedTransition = new HashSet<>();
229     private IDeviceFlasher mFlasher;
230     private ITestLogger mTestLogger;
231 
232     @Override
setConfiguration(IConfiguration configuration)233     public void setConfiguration(IConfiguration configuration) {
234         mConfig = configuration;
235     }
236 
237     /**
238      * Sets the device boot time
239      * <p/>
240      * Exposed for unit testing
241      */
setDeviceBootTime(long bootTime)242     void setDeviceBootTime(long bootTime) {
243         mDeviceBootTime = bootTime;
244     }
245 
246     /** Gets the device boot wait time */
getDeviceBootWaitTime()247     protected long getDeviceBootWaitTime() {
248         return mDeviceBootTime;
249     }
250 
251     /**
252      * Gets the interval between device boot poll attempts.
253      * <p/>
254      * Exposed for unit testing
255      */
getDeviceBootPollTimeMs()256     int getDeviceBootPollTimeMs() {
257         return BOOT_POLL_TIME_MS;
258     }
259 
260     /**
261      * Gets the {@link IRunUtil} instance to use.
262      * <p/>
263      * Exposed for unit testing
264      */
getRunUtil()265     IRunUtil getRunUtil() {
266         return RunUtil.getDefault();
267     }
268 
269     /**
270      * Gets the {@link IHostOptions} instance to use.
271      * <p/>
272      * Exposed for unit testing
273      */
getHostOptions()274     protected IHostOptions getHostOptions() {
275         return GlobalConfiguration.getInstance().getHostOptions();
276     }
277 
278     /**
279      * Set the userdata-flash option
280      *
281      * @param flashOption
282      */
setUserDataFlashOption(UserDataFlashOption flashOption)283     public void setUserDataFlashOption(UserDataFlashOption flashOption) {
284         mUserDataFlashOption = flashOption;
285     }
286 
287     /** Wrap the getBuildInfo so we have a change to override it for specific scenarios. */
getBuild(TestInformation testInfo)288     public IBuildInfo getBuild(TestInformation testInfo) {
289         return testInfo.getBuildInfo();
290     }
291 
292     /** {@inheritDoc} */
293     @Override
setUp(TestInformation testInfo)294     public void setUp(TestInformation testInfo)
295             throws TargetSetupError, DeviceNotAvailableException, BuildError {
296         if (testInfo.getDevice().getIDevice() instanceof NullDevice) {
297             CLog.i("Skipping device flashing, this is a null-device.");
298             return;
299         }
300         ITestDevice device = testInfo.getDevice();
301         IBuildInfo buildInfo = getBuild(testInfo);
302         CLog.i("Performing setup on %s", device.getSerialNumber());
303         if (!(buildInfo instanceof IDeviceBuildInfo)) {
304             throw new IllegalArgumentException("Provided buildInfo is not a IDeviceBuildInfo");
305         }
306         IDeviceBuildInfo deviceBuild = (IDeviceBuildInfo) buildInfo;
307         if (mShouldFlashRamdisk && deviceBuild.getRamdiskFile() == null) {
308             throw new HarnessRuntimeException(
309                     "ramdisk flashing enabled but no ramdisk file was found in build info",
310                     InfraErrorIdentifier.CONFIGURED_ARTIFACT_NOT_FOUND);
311         }
312         // For debugging: log the original build from the device
313         if (TestDeviceState.ONLINE.equals(testInfo.getDevice().getDeviceState())) {
314             buildInfo.addBuildAttribute(
315                     "original_build_fingerprint",
316                     device.getProperty("ro.product.build.fingerprint"));
317         }
318 
319         long queueTime = -1;
320         long flashingTime = -1;
321         long start = -1;
322         // HostOptions can force the incremental flashing to true.
323         if (!mIgnoreHostOptions) {
324             if (getHostOptions().isIncrementalFlashingEnabled()) {
325                 mUseIncrementalFlashing = true;
326             }
327             if (getHostOptions().isOptOutOfIncrementalFlashing()) {
328                 mUseIncrementalFlashing = false;
329             }
330         }
331         if (mConfig != null) {
332             for (IDeviceConfiguration deviceConfig : mConfig.getDeviceConfig()) {
333                 for (ITargetPreparer p : deviceConfig.getTargetPreparers()) {
334                     if (p instanceof GkiDeviceFlashPreparer
335                             && !((GkiDeviceFlashPreparer) p).isDisabled()
336                             && !mApplySnapshot) {
337                         CLog.d(
338                                 "Force disabling incremental flashing due to"
339                                         + " GkiDeviceFlashPreparer.");
340                         mForceDisableIncrementalFlashing = true;
341                     }
342                 }
343             }
344         }
345         if (mForceDisableIncrementalFlashing) {
346             // The local option disable the feature, and skip tracking baseline
347             // for this run to avoid tracking a potentially bad baseline.
348             mUseIncrementalFlashing = false;
349             // Do not keep a cache when we are about to override it
350             DeviceImageTracker.getDefaultCache().invalidateTracking(device.getSerialNumber());
351         }
352         boolean useIncrementalFlashing = mUseIncrementalFlashing;
353         boolean reEntry = false;
354         if (useIncrementalFlashing) {
355             boolean isIsolated = false;
356             if (mConfig.getRetryDecision() instanceof BaseRetryDecision) {
357                 isIsolated =
358                         IsolationGrade.FULLY_ISOLATED.equals(
359                                 ((BaseRetryDecision) mConfig.getRetryDecision())
360                                         .getIsolationGrade());
361             }
362             if (mIncrementalImageUtil != null) {
363                 // Re-entry can occur during reset isolation.
364                 reEntry = true;
365             } else {
366                 mIncrementalImageUtil =
367                         IncrementalImageUtil.initialize(
368                                 device,
369                                 deviceBuild,
370                                 mCreateSnapshotBinary,
371                                 isIsolated,
372                                 mAllowTrackerlessUpdate,
373                                 mAllowedTransition,
374                                 mNewIncrementalFlow,
375                                 mUpdateBootloaderFromUserspace,
376                                 mWaitPhase,
377                                 mUseMerkleTreeComparison);
378                 if (mIncrementalImageUtil == null) {
379                     useIncrementalFlashing = false;
380                 } else {
381                     if (mAllowIncrementalOnSameBuild) {
382                         mIncrementalImageUtil.allowSameBuildFlashing();
383                     }
384                     if (TestDeviceState.ONLINE.equals(device.getDeviceState())) {
385                         // No need to reboot yet, it will happen later in the sequence
386                         String verityOutput = device.executeAdbCommand("enable-verity");
387                         CLog.d("%s", verityOutput);
388                     }
389                 }
390             }
391         }
392         try {
393             checkDeviceProductType(device, deviceBuild);
394             device.setRecoveryMode(RecoveryMode.ONLINE);
395             IDeviceFlasher flasher = null;
396             if (mFlasher != null) {
397                 flasher = mFlasher;
398                 CLog.d("Reusing flasher object.");
399             } else {
400                 flasher = createFlasher(device);
401                 mFlasher = flasher;
402             }
403             flasher.setWipeTimeout(mWipeTimeout);
404             boolean tookPermit = false;
405             // only surround fastboot related operations with flashing permit restriction
406             try {
407                 flasher.overrideDeviceOptions(device);
408                 flasher.setUserDataFlashOption(mUserDataFlashOption);
409                 flasher.setForceSystemFlash(mForceSystemFlash);
410                 flasher.setDataWipeSkipList(mDataWipeSkipList);
411                 flasher.setShouldFlashRamdisk(mShouldFlashRamdisk);
412                 if (mShouldFlashRamdisk) {
413                     flasher.setRamdiskPartition(mRamdiskPartition);
414                 }
415                 if (flasher instanceof FastbootDeviceFlasher) {
416                     ((FastbootDeviceFlasher) flasher).setFlashOptions(mFastbootFlashOptions);
417                     if (!reEntry) {
418                         // Avoid using incremental during re-entry since it will just wipe
419                         ((FastbootDeviceFlasher) flasher)
420                                 .setIncrementalFlashing(mIncrementalImageUtil);
421                     }
422                     ((FastbootDeviceFlasher) flasher).setTestLogger(mTestLogger);
423                 }
424                 start = System.currentTimeMillis();
425                 flasher.preFlashOperations(device, deviceBuild);
426                 // After preFlashOperations device should be in bootloader
427                 if (mCancelSnapshot && TestDeviceState.FASTBOOT.equals(device.getDeviceState())) {
428                     CommandResult res =
429                             device.executeFastbootCommand(
430                                     SNAPSHOT_CANCEL_TIMEOUT, "snapshot-update", "cancel");
431                     if (!CommandStatus.SUCCESS.equals(res.getStatus())) {
432                         CLog.w(
433                                 "Failed to cancel snapshot: %s.\nstdout:%s\nstderr:%s",
434                                 res.getStatus(), res.getStdout(), res.getStderr());
435                     }
436                 }
437                 try (CloseableTraceScope ignored =
438                         new CloseableTraceScope("wait_for_flashing_permit")) {
439                     if (mIncrementalImageUtil == null) {
440                         // Only #flash is included in the critical section
441                         getHostOptions().takePermit(PermitLimitType.CONCURRENT_FLASHER);
442                         tookPermit = true;
443                     }
444                     queueTime = System.currentTimeMillis() - start;
445                     if (tookPermit) {
446                         CLog.v(
447                                 "Flashing permit obtained after %ds",
448                                 TimeUnit.MILLISECONDS.toSeconds(queueTime));
449                     }
450                     InvocationMetricLogger.addInvocationMetrics(
451                             InvocationMetricKey.FLASHING_PERMIT_LATENCY, queueTime);
452                 }
453                 // Don't allow interruptions during flashing operations.
454                 getRunUtil().allowInterrupt(false);
455                 start = System.currentTimeMillis();
456                 // Set flashing method as unknown here as a fallback, in case it wasn't overwritten
457                 // by subclass implementations
458                 InvocationMetricLogger.addInvocationMetrics(
459                         InvocationMetricKey.FLASHING_METHOD,
460                         FlashingMethod.FASTBOOT_UNCATEGORIZED.toString());
461                 flasher.flash(device, deviceBuild);
462             } catch (DeviceNotAvailableException | TargetSetupError | RuntimeException e) {
463                 CLog.e(e);
464                 // Clear tracking in case of error
465                 DeviceImageTracker.getDefaultCache().invalidateTracking(device.getSerialNumber());
466                 throw e;
467             } finally {
468                 flashingTime = System.currentTimeMillis() - start;
469                 if (tookPermit) {
470                     getHostOptions().returnPermit(PermitLimitType.CONCURRENT_FLASHER);
471                 }
472                 flasher.postFlashOperations(device, deviceBuild);
473                 // report flashing status
474                 CommandStatus status = flasher.getSystemFlashingStatus();
475                 if (status == null) {
476                     CLog.i("Skipped reporting metrics because system partitions were not flashed.");
477                 } else {
478                     if (mIncrementalImageUtil != null) {
479                         InvocationMetricLogger.addInvocationMetrics(
480                                 InvocationMetricKey.INCREMENTAL_FLASHING_TIME, flashingTime);
481                     }
482                     InvocationMetricLogger.addInvocationMetrics(
483                             InvocationMetricKey.FLASHING_TIME, flashingTime);
484                     reportFlashMetrics(buildInfo.getBuildBranch(), buildInfo.getBuildFlavor(),
485                             buildInfo.getBuildId(), device.getSerialNumber(), queueTime,
486                             flashingTime, status);
487                 }
488             }
489             if (mIncrementalImageUtil == null) {
490                 // only want logcat captured for current build, delete any accumulated log data
491                 device.clearLogcat();
492             }
493             // In case success with full flashing
494             if (!reEntry) {
495                 moveBaseline(deviceBuild, device.getSerialNumber(), useIncrementalFlashing);
496             }
497             if (mSkipPostFlashingSetup) {
498                 return;
499             }
500             // Temporary re-enable interruptable since the critical flashing operation is over.
501             getRunUtil().allowInterrupt(true);
502             device.waitForDeviceOnline();
503             // device may lose date setting if wiped, update with host side date in case anything on
504             // device side malfunction with an invalid date
505             if (device.enableAdbRoot()) {
506                 device.setDate(null);
507             }
508             // Disable interrupt for encryption operation.
509             getRunUtil().allowInterrupt(false);
510             checkBuild(device, deviceBuild);
511             // Once critical operation is done, we re-enable interruptable
512             getRunUtil().allowInterrupt(true);
513             try {
514                 boolean available = device.waitForDeviceAvailableInRecoverPath(mDeviceBootTime);
515                 if (!available) {
516                     // Clear tracking in case of error
517                     DeviceImageTracker.getDefaultCache()
518                             .invalidateTracking(device.getSerialNumber());
519                     throw new DeviceFailedToBootError(
520                             String.format(
521                                     "Device %s did not become available after flashing %s",
522                                     device.getSerialNumber(), deviceBuild.getDeviceBuildId()),
523                             device.getDeviceDescriptor(),
524                             DeviceErrorIdentifier.ERROR_AFTER_FLASHING);
525                 }
526             } catch (DeviceNotAvailableException e) {
527                 // Clear tracking in case of error
528                 DeviceImageTracker.getDefaultCache().invalidateTracking(device.getSerialNumber());
529                 // Assume this is a build problem
530                 throw new DeviceFailedToBootError(
531                         String.format(
532                                 "Device %s did not become available after flashing %s",
533                                 device.getSerialNumber(), deviceBuild.getDeviceBuildId()),
534                         device.getDeviceDescriptor(),
535                         e,
536                         DeviceErrorIdentifier.ERROR_AFTER_FLASHING);
537             }
538             device.postBootSetup();
539         } finally {
540             device.setRecoveryMode(RecoveryMode.AVAILABLE);
541             // Allow interruption at the end no matter what.
542             getRunUtil().allowInterrupt(true);
543             if (mIncrementalImageUtil != null) {
544                 mIncrementalImageUtil.cleanAfterSetup();
545             }
546         }
547     }
548 
moveBaseline( IDeviceBuildInfo deviceBuild, String serial, boolean useIncrementalFlashing)549     private void moveBaseline(
550             IDeviceBuildInfo deviceBuild, String serial, boolean useIncrementalFlashing) {
551         if (getHostOptions().isOptOutOfIncrementalFlashing()) {
552             CLog.d("Opt out of incremental via host_options");
553             return;
554         }
555         boolean moveBaseLine = true;
556         if (!mUseIncrementalFlashing || useIncrementalFlashing) {
557             // Do not move baseline if using incremental flashing
558             moveBaseLine = false;
559         }
560         if (mApplySnapshot) {
561             // Move baseline when going with incremental + apply update
562             moveBaseLine = true;
563         }
564         if (moveBaseLine) {
565             DeviceImageTracker.getDefaultCache()
566                     .trackUpdatedDeviceImage(
567                             serial,
568                             deviceBuild.getBuildId(),
569                             deviceBuild.getBuildBranch(),
570                             deviceBuild.getBuildFlavor());
571         }
572     }
573 
574     /**
575      * Possible check before flashing to ensure the device is as expected compare to the build info.
576      *
577      * @param device the {@link ITestDevice} to flash.
578      * @param deviceBuild the {@link IDeviceBuildInfo} used to flash.
579      * @throws BuildError
580      * @throws DeviceNotAvailableException
581      */
checkDeviceProductType(ITestDevice device, IDeviceBuildInfo deviceBuild)582     protected void checkDeviceProductType(ITestDevice device, IDeviceBuildInfo deviceBuild)
583             throws BuildError, DeviceNotAvailableException {
584         // empty of purpose
585     }
586 
587     /**
588      * Verifies the expected build matches the actual build on device after flashing
589      * @throws DeviceNotAvailableException
590      */
checkBuild(ITestDevice device, IDeviceBuildInfo deviceBuild)591     private void checkBuild(ITestDevice device, IDeviceBuildInfo deviceBuild)
592             throws DeviceNotAvailableException {
593         // Need to use deviceBuild.getDeviceBuildId instead of getBuildId because the build info
594         // could be an AppBuildInfo and return app build id. Need to be more explicit that we
595         // check for the device build here.
596         if (!mSkipPostFlashBuildIdCheck) {
597             String dbid = deviceBuild.getDeviceBuildId();
598             if (IDeviceBuildInfo.UNKNOWN_BUILD_ID.equals(dbid)) {
599                 // if the device build isn't set, use the build id instead
600                 // this happens when device image download is skipped, which could happen when
601                 // other kinds of build artifact is used instead for "flashing", e.g. OTA package
602                 dbid = deviceBuild.getBuildId();
603             }
604             checkBuildAttribute(dbid, device.getBuildId(), device.getSerialNumber());
605         }
606     }
607 
checkBuildAttribute(String expectedBuildAttr, String actualBuildAttr, String serial)608     private void checkBuildAttribute(String expectedBuildAttr, String actualBuildAttr,
609             String serial) throws DeviceNotAvailableException {
610         if (expectedBuildAttr == null || actualBuildAttr == null ||
611                 !expectedBuildAttr.equals(actualBuildAttr)) {
612             // throw DNAE - assume device hardware problem - we think flash was successful but
613             // device is not running right bits
614             throw new DeviceNotAvailableException(
615                     String.format(
616                             "Unexpected build after flashing. Expected %s, actual %s",
617                             expectedBuildAttr, actualBuildAttr),
618                     serial,
619                     DeviceErrorIdentifier.ERROR_AFTER_FLASHING);
620         }
621     }
622 
623     /**
624      * Create {@link IDeviceFlasher} to use. Subclasses can override
625      * @throws DeviceNotAvailableException
626      */
createFlasher(ITestDevice device)627     protected abstract IDeviceFlasher createFlasher(ITestDevice device)
628             throws DeviceNotAvailableException;
629 
630     @Override
tearDown(TestInformation testInfo, Throwable e)631     public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException {
632         if (testInfo.getDevice().getIDevice() instanceof NullDevice) {
633             CLog.i("Skipping device flashing tearDown, this is a null-device.");
634             return;
635         }
636         if (mIncrementalImageUtil != null) {
637             CLog.d("Teardown related to incremental update.");
638             RecoveryMode mode = testInfo.getDevice().getRecoveryMode();
639             try {
640                 testInfo.getDevice().setRecoveryMode(RecoveryMode.NONE);
641                 if (mAllowUnzippedBaseline) {
642                     mIncrementalImageUtil.allowUnzipBaseline();
643                 }
644                 mIncrementalImageUtil.teardownDevice(testInfo);
645             } finally {
646                 testInfo.getDevice().setRecoveryMode(mode);
647             }
648         }
649         if (mFlasher != null) {
650             mFlasher.tearDownFlasher();
651         }
652         if (mEnforceSnapshotCompleted && e == null) {
653             if (mIncrementalImageUtil == null || !mIncrementalImageUtil.updateCompleted()) {
654                 throw new RuntimeException(
655                         "We expected incremental-flashing to be used but wasn't.");
656             }
657         }
658     }
659 
660     @Override
setTestLogger(ITestLogger testLogger)661     public void setTestLogger(ITestLogger testLogger) {
662         mTestLogger = testLogger;
663     }
664 
getTestLogger()665     public ITestLogger getTestLogger() {
666         return mTestLogger;
667     }
668 
669     /**
670      * Reports device flashing timing data to metrics backend
671      * @param branch the branch where the device build originated from
672      * @param buildFlavor the build flavor of the device build
673      * @param buildId the build number of the device build
674      * @param serial the serial number of device
675      * @param queueTime the time spent waiting for a flashing limit to become available
676      * @param flashingTime the time spent in flashing device image zip
677      * @param flashingStatus the execution status of flashing command
678      */
reportFlashMetrics(String branch, String buildFlavor, String buildId, String serial, long queueTime, long flashingTime, CommandStatus flashingStatus)679     protected void reportFlashMetrics(String branch, String buildFlavor, String buildId,
680             String serial, long queueTime, long flashingTime, CommandStatus flashingStatus) {
681         // no-op as default implementation
682     }
683 
684     /**
685      * Sets the option for whether ramdisk should be flashed
686      *
687      * @param shouldFlashRamdisk
688      */
689     @VisibleForTesting
setShouldFlashRamdisk(boolean shouldFlashRamdisk)690     void setShouldFlashRamdisk(boolean shouldFlashRamdisk) {
691         mShouldFlashRamdisk = shouldFlashRamdisk;
692     }
693 
setSkipPostFlashBuildIdCheck(boolean skipPostFlashBuildIdCheck)694     protected void setSkipPostFlashBuildIdCheck(boolean skipPostFlashBuildIdCheck) {
695         mSkipPostFlashBuildIdCheck = skipPostFlashBuildIdCheck;
696     }
697 
setUseIncrementalFlashing(boolean incrementalFlashing)698     protected void setUseIncrementalFlashing(boolean incrementalFlashing) {
699         mUseIncrementalFlashing = incrementalFlashing;
700     }
701 
isIncrementalFlashingEnabled()702     public boolean isIncrementalFlashingEnabled() {
703         return mUseIncrementalFlashing;
704     }
705 
isIncrementalFlashingForceDisabled()706     public boolean isIncrementalFlashingForceDisabled() {
707         return mForceDisableIncrementalFlashing;
708     }
709 
setAllowCrossReleaseFlashing(boolean allowCrossReleaseFlashing)710     public void setAllowCrossReleaseFlashing(boolean allowCrossReleaseFlashing) {
711         mAllowIncrementalCrossRelease = allowCrossReleaseFlashing;
712     }
713 
setApplySnapshot(boolean applySnapshot)714     public void setApplySnapshot(boolean applySnapshot) {
715         mApplySnapshot = applySnapshot;
716     }
717 
setWipeAfterApplySnapshot(boolean wipeAfterApplySnapshot)718     public void setWipeAfterApplySnapshot(boolean wipeAfterApplySnapshot) {
719         mWipeAfterApplySnapshot = wipeAfterApplySnapshot;
720     }
721 
setUseIncrementalNewFlow(boolean useIncrementalNewFlow)722     public void setUseIncrementalNewFlow(boolean useIncrementalNewFlow) {
723         mNewIncrementalFlow = useIncrementalNewFlow;
724     }
725 
setUpdateBootloaderFromUserspace(boolean updateBootloaderFromUserspace)726     public void setUpdateBootloaderFromUserspace(boolean updateBootloaderFromUserspace) {
727         mUpdateBootloaderFromUserspace = updateBootloaderFromUserspace;
728     }
729 
setAllowUnzipBaseline(boolean allowUnzipBaseline)730     public void setAllowUnzipBaseline(boolean allowUnzipBaseline) {
731         mAllowUnzippedBaseline = allowUnzipBaseline;
732     }
733 
setIgnoreHostOptions(boolean ignoreHostOptions)734     public void setIgnoreHostOptions(boolean ignoreHostOptions) {
735         mIgnoreHostOptions = ignoreHostOptions;
736     }
737 
738     @Deprecated
addBranchTransitionInIncremental(String origin, String destination)739     public void addBranchTransitionInIncremental(String origin, String destination) {
740         mAllowedTransition.add(origin);
741         mAllowedTransition.add(destination);
742     }
743 
addAllowedBranchForTransitionInIncremental(String branch)744     public void addAllowedBranchForTransitionInIncremental(String branch) {
745         mAllowedTransition.add(branch);
746     }
747 
useMerkleTreeComparison(boolean enableMerkleTreeComparison)748     public void useMerkleTreeComparison(boolean enableMerkleTreeComparison) {
749         mUseMerkleTreeComparison = enableMerkleTreeComparison;
750     }
751 }
752