blob: 55f2439f852488e3f0351e82f1aba783b23a4ed0 [file] [log] [blame]
/*
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tradefed.targetprep;
import com.android.tradefed.config.GlobalConfiguration;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.DeviceUnresponsiveException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.ITestDevice.RecoveryMode;
import com.android.tradefed.host.IHostOptions;
import com.android.tradefed.host.IHostOptions.PermitLimitType;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.result.error.DeviceErrorIdentifier;
import com.android.tradefed.result.error.InfraErrorIdentifier;
import java.io.File;
import java.util.concurrent.TimeUnit;
/**
* An abstract {@link ITargetPreparer} that takes care of common steps around updating devices with
* a device image file from an external source (as opposed to a build service). The actual update
* mechanism is delegated to implementor of subclasses.
*/
public abstract class DeviceUpdateTargetPreparer extends DeviceBuildInfoBootStrapper {
@Option(
name = "device-boot-time",
description = "max time to wait for device to boot.",
isTimeVal = true
)
private long mDeviceBootTime = 5 * 60 * 1000;
@Option(
name = "bootstrap-build-info",
description =
"whether build info should be"
+ "bootstrapped based on device attributes after flashing"
)
private boolean mBootStrapBuildInfo = true;
/** {@inheritDoc} */
@Override
public void setUp(TestInformation testInfo)
throws TargetSetupError, BuildError, DeviceNotAvailableException {
ITestDevice device = testInfo.getDevice();
File deviceUpdateImage = getDeviceUpdateImage();
if (deviceUpdateImage == null) {
CLog.i("No device image zip file provided, assuming no-op; skipping ...");
return;
}
if (!deviceUpdateImage.exists()) {
throw new TargetSetupError(
"Device image file not found: " + deviceUpdateImage.getAbsolutePath(),
device.getDeviceDescriptor(),
InfraErrorIdentifier.CONFIGURED_ARTIFACT_NOT_FOUND);
}
preUpdateActions(deviceUpdateImage, device);
// flashing concurrency control
long start = System.currentTimeMillis();
IHostOptions hostOptions = GlobalConfiguration.getInstance().getHostOptions();
hostOptions.takePermit(PermitLimitType.CONCURRENT_FLASHER);
CLog.v(
"Flashing permit obtained after %ds",
TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis() - start)));
try {
performDeviceUpdate(deviceUpdateImage, device);
} finally {
CLog.v(
"Flashing finished after %ds",
TimeUnit.MILLISECONDS.toSeconds((System.currentTimeMillis() - start)));
hostOptions.returnPermit(PermitLimitType.CONCURRENT_FLASHER);
}
postUpdateActions(deviceUpdateImage, device);
CLog.i(
"Flashing completed successfully on %s, waiting for device to boot up.",
device.getSerialNumber());
device.waitForDeviceOnline();
// device may lose date setting if wiped, update with host side date in case anything on
// device side malfunction with an invalid date
if (device.getOptions().isEnableAdbRoot()) {
boolean rootEnabled = device.enableAdbRoot();
if (rootEnabled) {
device.setDate(null);
}
}
try {
device.setRecoveryMode(RecoveryMode.AVAILABLE);
device.waitForDeviceAvailable(mDeviceBootTime);
} catch (DeviceUnresponsiveException e) {
// assume this is a build problem
throw new DeviceFailedToBootError(
String.format(
"Device %s did not become available after flashing %s",
device.getSerialNumber(), deviceUpdateImage.getAbsolutePath()),
device.getDeviceDescriptor(),
DeviceErrorIdentifier.ERROR_AFTER_FLASHING);
}
CLog.i("Device update completed on %s", device.getDeviceDescriptor());
// calling this last because we want to inject device side build info after device boots up
if (mBootStrapBuildInfo) {
super.setUp(testInfo);
}
}
/**
* Provides a {@link File} instance representing the device image file to be used for updating
*/
protected abstract File getDeviceUpdateImage();
/**
* Actions to be performed before the device is updated. This method will be called outside of
* flashing concurrency control.
*
* @param deviceUpdateImage
* @param device
* @throws TargetSetupError
*/
protected abstract void preUpdateActions(File deviceUpdateImage, ITestDevice device)
throws DeviceNotAvailableException, TargetSetupError;
/**
* Performs the device image update on device
*
* @param deviceUpdateImage
* @param device
* @throws TargetSetupError
*/
protected abstract void performDeviceUpdate(File deviceUpdateImage, ITestDevice device)
throws DeviceNotAvailableException, TargetSetupError;
/**
* Actions to be performed after the device is updated but before post update setup steps are
* performed. This method will be called outside of flashing concurrency control.
*
* @param deviceUpdateImage
* @param device
* @throws TargetSetupError
*/
protected abstract void postUpdateActions(File deviceUpdateImage, ITestDevice device)
throws DeviceNotAvailableException, TargetSetupError;
}