1 /* 2 * Copyright (C) 2013 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.IBuildInfo; 20 import com.android.tradefed.config.Option; 21 import com.android.tradefed.config.OptionClass; 22 import com.android.tradefed.device.DeviceNotAvailableException; 23 import com.android.tradefed.device.DeviceUnresponsiveException; 24 import com.android.tradefed.device.ITestDevice; 25 import com.android.tradefed.device.TestDeviceState; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.util.RunUtil; 28 29 /** Performs reboot or format as cleanup action after test, and optionally turns screen off */ 30 @OptionClass(alias = "device-cleaner") 31 public class DeviceCleaner extends BaseTargetPreparer implements ITargetCleaner { 32 33 public static enum CleanupAction { 34 /** no cleanup action */ 35 NONE, 36 /** reboot the device as post test cleanup */ 37 REBOOT, 38 /** format userdata and cache partitions as post test cleanup */ 39 FORMAT, 40 } 41 42 public static enum PostCleanupAction { 43 /** no post cleanup action */ 44 NONE, 45 /** turns screen off after the cleanup action */ 46 SCREEN_OFF, 47 /** turns off screen and stops runtime after the cleanup action */ 48 SCREEN_OFF_AND_STOP, 49 } 50 51 private static final int MAX_SCREEN_OFF_RETRY = 5; 52 private static final int SCREEN_OFF_RETRY_DELAY_MS = 2 * 1000; 53 54 @Option(name = "cleanup-action", 55 description = "Type of action to perform as a post test cleanup; options are: " 56 + "NONE, REBOOT or FORMAT; defaults to NONE") 57 private CleanupAction mCleanupAction = CleanupAction.NONE; 58 59 /** 60 * @deprecated use --post-cleanup SCREEN_OFF option instead. 61 */ 62 @Deprecated 63 @Option(name = "screen-off", description = "After cleanup action, " 64 + "if screen should be turned off; defaults to false; " 65 + "[deprecated] use --post-cleanup SCREEN_OFF instead") 66 private boolean mScreenOff = false; 67 68 @Option(name = "post-cleanup", 69 description = "Type of action to perform after the cleanup action;" 70 + "this will override the deprecated screen-off action if specified") 71 private PostCleanupAction mPostCleanupAction = PostCleanupAction.NONE; 72 73 @Override setUp(ITestDevice device, IBuildInfo buildInfo)74 public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, 75 BuildError, DeviceNotAvailableException { 76 // no op since this is a target cleaner 77 } 78 79 @Override tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)80 public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e) 81 throws DeviceNotAvailableException { 82 if (e instanceof DeviceFailedToBootError) { 83 CLog.w("boot failure: attempting to stop runtime instead of cleanup"); 84 try { 85 device.executeShellCommand("stop"); 86 } catch (DeviceUnresponsiveException due) { 87 CLog.w("boot failure: ignored DeviceUnresponsiveException during forced cleanup"); 88 } 89 } else { 90 clean(device); 91 } 92 } 93 94 /** 95 * Execute cleanup action followed by post cleanup action 96 */ clean(ITestDevice device)97 protected void clean(ITestDevice device) throws DeviceNotAvailableException { 98 if (TestDeviceState.ONLINE.equals(device.getDeviceState())) { 99 switch (mCleanupAction) { 100 case NONE: 101 // do nothing here 102 break; 103 case REBOOT: 104 device.reboot(); 105 break; 106 case FORMAT: 107 device.rebootIntoBootloader(); 108 device.executeLongFastbootCommand("-w"); 109 device.executeFastbootCommand("reboot"); 110 device.waitForDeviceAvailable(); 111 break; 112 } 113 if (mScreenOff && mPostCleanupAction == PostCleanupAction.NONE) { 114 mPostCleanupAction = PostCleanupAction.SCREEN_OFF; 115 } 116 // perform post cleanup action 117 switch (mPostCleanupAction) { 118 case NONE: 119 // do nothing here 120 break; 121 case SCREEN_OFF: 122 turnScreenOff(device); 123 break; 124 case SCREEN_OFF_AND_STOP: 125 turnScreenOff(device); 126 device.executeShellCommand("stop"); 127 break; 128 } 129 } 130 } 131 turnScreenOff(ITestDevice device)132 private void turnScreenOff(ITestDevice device) throws DeviceNotAvailableException { 133 String output = 134 device.executeShellCommand("dumpsys power | grep -e mScreenOn -e mInteractive"); 135 int retries = 1; 136 // screen on semantics have changed in newest API platform, checking for both signatures 137 // to detect screen on state 138 while (output.contains("mScreenOn=true") || output.contains("mInteractive=true")) { 139 // KEYCODE_POWER = 26 140 device.executeShellCommand("input keyevent 26"); 141 // due to framework initialization, device may not actually turn off screen 142 // after boot, recheck screen status with linear backoff 143 RunUtil.getDefault().sleep(SCREEN_OFF_RETRY_DELAY_MS * retries); 144 output = 145 device.executeShellCommand("dumpsys power | grep -e mScreenOn -e mInteractive"); 146 retries++; 147 if (retries > MAX_SCREEN_OFF_RETRY) { 148 CLog.w(String.format("screen still on after %d retries", retries)); 149 break; 150 } 151 } 152 } 153 } 154