aboutsummaryrefslogtreecommitdiff
path: root/src/com/android/tradefed/targetprep/DeviceCleaner.java
blob: 60024f26ad188501626d5d5966b7d4babbfca56a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
 * 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("-w");
                    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;
            }
        }
    }
}