• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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