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