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.config.Option; 20 import com.android.tradefed.config.OptionClass; 21 import com.android.tradefed.device.DeviceNotAvailableException; 22 import com.android.tradefed.device.DeviceUnresponsiveException; 23 import com.android.tradefed.device.ITestDevice; 24 import com.android.tradefed.device.TestDeviceState; 25 import com.android.tradefed.invoker.TestInformation; 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 { 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(TestInformation testInfo)74 public void setUp(TestInformation testInfo) 75 throws TargetSetupError, BuildError, DeviceNotAvailableException { 76 // no op since this is a target cleaner 77 } 78 79 @Override tearDown(TestInformation testInfo, Throwable e)80 public void tearDown(TestInformation testInfo, Throwable e) throws DeviceNotAvailableException { 81 if (e instanceof DeviceFailedToBootError) { 82 CLog.w("boot failure: attempting to stop runtime instead of cleanup"); 83 try { 84 testInfo.getDevice().executeShellCommand("stop"); 85 } catch (DeviceUnresponsiveException due) { 86 CLog.w("boot failure: ignored DeviceUnresponsiveException during forced cleanup"); 87 } 88 } else { 89 clean(testInfo.getDevice()); 90 } 91 } 92 93 /** 94 * Execute cleanup action followed by post cleanup action 95 */ clean(ITestDevice device)96 protected void clean(ITestDevice device) throws DeviceNotAvailableException { 97 if (TestDeviceState.ONLINE.equals(device.getDeviceState())) { 98 switch (mCleanupAction) { 99 case NONE: 100 // do nothing here 101 break; 102 case REBOOT: 103 device.reboot(); 104 break; 105 case FORMAT: 106 device.rebootIntoBootloader(); 107 device.executeLongFastbootCommand("-w"); 108 device.executeFastbootCommand("reboot"); 109 device.waitForDeviceAvailable(); 110 break; 111 } 112 if (mScreenOff && mPostCleanupAction == PostCleanupAction.NONE) { 113 mPostCleanupAction = PostCleanupAction.SCREEN_OFF; 114 } 115 // perform post cleanup action 116 switch (mPostCleanupAction) { 117 case NONE: 118 // do nothing here 119 break; 120 case SCREEN_OFF: 121 turnScreenOff(device); 122 break; 123 case SCREEN_OFF_AND_STOP: 124 turnScreenOff(device); 125 device.executeShellCommand("stop"); 126 break; 127 } 128 } 129 } 130 turnScreenOff(ITestDevice device)131 private void turnScreenOff(ITestDevice device) throws DeviceNotAvailableException { 132 String output = 133 device.executeShellCommand("dumpsys power | grep -e mScreenOn -e mInteractive"); 134 int retries = 1; 135 // screen on semantics have changed in newest API platform, checking for both signatures 136 // to detect screen on state 137 while (output.contains("mScreenOn=true") || output.contains("mInteractive=true")) { 138 // KEYCODE_POWER = 26 139 device.executeShellCommand("input keyevent 26"); 140 // due to framework initialization, device may not actually turn off screen 141 // after boot, recheck screen status with linear backoff 142 RunUtil.getDefault().sleep(SCREEN_OFF_RETRY_DELAY_MS * retries); 143 output = 144 device.executeShellCommand("dumpsys power | grep -e mScreenOn -e mInteractive"); 145 retries++; 146 if (retries > MAX_SCREEN_OFF_RETRY) { 147 CLog.w(String.format("screen still on after %d retries", retries)); 148 break; 149 } 150 } 151 } 152 } 153