blob: e2d1c184d776d6a6f763d07884f1edfcde1b2132 [file] [log] [blame]
/*
* Copyright (C) 2013 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.build.IBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.DeviceUnresponsiveException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.device.TestDeviceState;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.RunUtil;
/**
* Performs reboot or format as cleanup action after test, and optionally turns screen off
*/
@OptionClass(alias = "device-cleaner")
public class DeviceCleaner implements ITargetCleaner {
public static enum CleanupAction {
/** no cleanup action */
NONE,
/** reboot the device as post test cleanup */
REBOOT,
/** format userdata and cache partitions as post test cleanup */
FORMAT,
}
public static enum PostCleanupAction {
/** no post cleanup action */
NONE,
/** turns screen off after the cleanup action */
SCREEN_OFF,
/** turns off screen and stops runtime after the cleanup action */
SCREEN_OFF_AND_STOP,
}
private static final int MAX_SCREEN_OFF_RETRY = 5;
private static final int SCREEN_OFF_RETRY_DELAY_MS = 2 * 1000;
@Option(name = "cleanup-action",
description = "Type of action to perform as a post test cleanup; options are: "
+ "NONE, REBOOT or FORMAT; defaults to NONE")
private CleanupAction mCleanupAction = CleanupAction.NONE;
@Deprecated
@Option(name = "screen-off", description = "After cleanup action, "
+ "if screen should be turned off; defaults to false; "
+ "[deprecated] use --post-cleanup SCREEN_OFF instead")
private boolean mScreenOff = false;
@Option(name = "post-cleanup",
description = "Type of action to perform after the cleanup action;"
+ "this will override the deprecated screen-off action if specified")
private PostCleanupAction mPostCleanupAction = PostCleanupAction.NONE;
@Override
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
// no op since this is a target cleaner
}
@Override
public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
throws DeviceNotAvailableException {
if (e instanceof DeviceFailedToBootError) {
CLog.w("boot failure: attempting to stop runtime instead of cleanup");
try {
device.executeShellCommand("stop");
} catch (DeviceUnresponsiveException due) {
CLog.w("boot failure: ignored DeviceUnresponsiveException during forced cleanup");
}
} else {
clean(device);
}
}
/**
* Execute cleanup action followed by post cleanup action
*/
protected void clean(ITestDevice device) throws DeviceNotAvailableException {
if (TestDeviceState.ONLINE.equals(device.getDeviceState())) {
switch (mCleanupAction) {
case NONE:
// do nothing here
break;
case REBOOT:
device.reboot();
break;
case FORMAT:
device.rebootIntoBootloader();
device.executeLongFastbootCommand("format", "cache");
device.executeLongFastbootCommand("format", "userdata");
device.executeFastbootCommand("reboot");
device.waitForDeviceAvailable();
break;
}
if (mScreenOff && mPostCleanupAction == PostCleanupAction.NONE) {
mPostCleanupAction = PostCleanupAction.SCREEN_OFF;
}
// perform post cleanup action
switch (mPostCleanupAction) {
case NONE:
// do nothing here
break;
case SCREEN_OFF:
turnScreenOff(device);
break;
case SCREEN_OFF_AND_STOP:
turnScreenOff(device);
device.executeShellCommand("stop");
break;
}
}
}
private void turnScreenOff(ITestDevice device) throws DeviceNotAvailableException {
String output = device.executeShellCommand("dumpsys power");
int retries = 1;
// screen on semantics have changed in newest API platform, checking for both signatures
// to detect screen on state
while (output.contains("mScreenOn=true") || output.contains("mInteractive=true")) {
// KEYCODE_POWER = 26
device.executeShellCommand("input keyevent 26");
// due to framework initialization, device may not actually turn off screen
// after boot, recheck screen status with linear backoff
RunUtil.getDefault().sleep(SCREEN_OFF_RETRY_DELAY_MS * retries);
output = device.executeShellCommand("dumpsys power");
retries++;
if (retries > MAX_SCREEN_OFF_RETRY) {
CLog.w(String.format("screen still on after %d retries", retries));
break;
}
}
}
}