1 /*
2  * Copyright (C) 2015 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 package com.android.tradefed.targetprep;
17 
18 import com.android.tradefed.config.Option;
19 import com.android.tradefed.config.OptionClass;
20 import com.android.tradefed.device.DeviceNotAvailableException;
21 import com.android.tradefed.device.ITestDevice;
22 import com.android.tradefed.invoker.TestInformation;
23 import com.android.tradefed.log.LogUtil.CLog;
24 import com.android.tradefed.util.RunUtil;
25 
26 import java.util.regex.Matcher;
27 import java.util.regex.Pattern;
28 
29 /** An {@link ITargetPreparer} that waits until device's temperature gets down to target */
30 @OptionClass(alias = "temperature-throttle-waiter")
31 public class TemperatureThrottlingWaiter extends BaseTargetPreparer {
32 
33     @Option(name = "poll-interval",
34             description = "Interval in seconds, to poll for device temperature; defaults to 30s")
35     private long mPollIntervalSecs = 30;
36 
37     @Option(name = "max-wait", description = "Max wait time in seconds, for device cool down "
38             + "to target temperature; defaults to 20 minutes")
39     private long mMaxWaitSecs = 60 * 20;
40 
41     @Option(name = "abort-on-timeout", description = "If test should be aborted if device is still "
42         + " above expected temperature; defaults to false")
43     private boolean mAbortOnTimeout = false;
44 
45     @Option(name = "post-idle-wait", description = "Additional time to wait in seconds, after "
46         + "temperature has reached to target; defaults to 120s")
47     private long mPostIdleWaitSecs = 120;
48 
49     public static final String DEVICE_TEMPERATURE_FILE_PATH_NAME = "device-temperature-file-path";
50 
51     @Option(
52             name = DEVICE_TEMPERATURE_FILE_PATH_NAME,
53             description =
54                     "Name of file that contains device"
55                             + "temperature. Example: /sys/class/hwmon/hwmon1/device/msm_therm")
56     private String mDeviceTemperatureFilePath = null;
57 
58     @Option(name = "target-temperature", description = "Target Temperature that device should have;"
59         + "defaults to 30c")
60     private int mTargetTemperature = 30;
61 
62     /** {@inheritDoc} */
63     @Override
setUp(TestInformation testInfo)64     public void setUp(TestInformation testInfo)
65             throws TargetSetupError, BuildError, DeviceNotAvailableException {
66         if (mDeviceTemperatureFilePath == null) {
67             return;
68         }
69         ITestDevice device = testInfo.getDevice();
70         long start = System.currentTimeMillis();
71         long maxWaitMs = mMaxWaitSecs * 1000;
72         long intervalMs = mPollIntervalSecs * 1000;
73         int deviceTemperature = Integer.MAX_VALUE;
74         while (true) {
75             // get device temperature
76             deviceTemperature = getDeviceTemperature(device, mDeviceTemperatureFilePath);
77             if (deviceTemperature > mTargetTemperature) {
78                 CLog.d("Temperature is still high actual %d/expected %d",
79                         deviceTemperature, mTargetTemperature);
80             } else {
81                 CLog.i("Total time elapsed to get to %dc : %ds", mTargetTemperature,
82                         (System.currentTimeMillis() - start) / 1000);
83                 break; // while loop
84             }
85             if ((System.currentTimeMillis() - start) > maxWaitMs) {
86                 CLog.w("Temperature is still high, actual %d/expected %d; waiting after %ds",
87                         deviceTemperature, mTargetTemperature, maxWaitMs);
88                 if (mAbortOnTimeout) {
89                     throw new TargetSetupError(String.format("Temperature is still high after wait "
90                             + "timeout; actual %d/expected %d", deviceTemperature,
91                             mTargetTemperature), device.getDeviceDescriptor());
92                 }
93                 break; // while loop
94             }
95             RunUtil.getDefault().sleep(intervalMs);
96         }
97         // extra idle time after reaching the targetl to stable the system
98         RunUtil.getDefault().sleep(mPostIdleWaitSecs * 1000);
99         CLog.d("Done waiting, total time elapsed: %ds",
100                 (System.currentTimeMillis() - start) / 1000);
101     }
102 
103     /**
104      * @param device
105      * @param fileName : filename where device temperature is stored
106      * @throws DeviceNotAvailableException
107      */
getDeviceTemperature(ITestDevice device, String fileName)108     protected int getDeviceTemperature (ITestDevice device, String fileName)
109             throws DeviceNotAvailableException, TargetSetupError {
110         int deviceTemp = Integer.MAX_VALUE;
111         String result = device.executeShellCommand(
112                 String.format("cat %s", fileName)).trim();
113         CLog.i(String.format("Temperature file output : %s", result));
114 
115         if (result == null || result.contains("No such file or directory")) {
116             throw new TargetSetupError(String.format("File %s doesn't exist", fileName),
117                     device.getDeviceDescriptor());
118         }
119 
120         // temperature raw format example output : Result:30 Raw:7f6f
121         final Pattern TEMPERATURE_RAW_FORMAT_REGEX = Pattern.compile("Result:(\\d+)\\sRaw:(\\w+)");
122         // temperature format example output : 30
123         final Pattern TEMPERATURE_FORMAT_REGEX = Pattern.compile("\\d+");
124         Matcher matcher = TEMPERATURE_RAW_FORMAT_REGEX.matcher(result);
125         if (matcher.find()) {
126             deviceTemp = Integer.parseInt(matcher.group(1));
127         } else {
128             matcher = TEMPERATURE_FORMAT_REGEX.matcher(result);
129             if (matcher.find()) {
130                 deviceTemp = Integer.parseInt(matcher.group());
131             } else {
132                 throw new TargetSetupError(
133                         String.format("file content is not as expected. Content : %s", result),
134                         device.getDeviceDescriptor());
135             }
136         }
137 
138         return deviceTemp;
139     }
140 }
141