1 /* 2 * Copyright (C) 2011 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.testtype; 18 19 import com.android.annotations.VisibleForTesting; 20 import com.android.ddmlib.IDevice; 21 import com.android.tradefed.config.Option; 22 import com.android.tradefed.config.OptionClass; 23 import com.android.tradefed.device.DeviceNotAvailableException; 24 import com.android.tradefed.device.DeviceSelectionOptions; 25 import com.android.tradefed.device.ITestDevice; 26 import com.android.tradefed.log.LogUtil.CLog; 27 import com.android.tradefed.result.ITestInvocationListener; 28 import com.android.tradefed.targetprep.ITargetPreparer; 29 import com.android.tradefed.util.IRunUtil; 30 import com.android.tradefed.util.RunUtil; 31 import com.android.tradefed.util.TimeUtil; 32 33 import org.junit.Assert; 34 35 import java.util.concurrent.ExecutionException; 36 import java.util.concurrent.TimeUnit; 37 38 /** 39 * An {@link ITargetPreparer} that checks for a minimum battery charge, and waits for the battery 40 * to reach a second charging threshold if the minimum charge isn't present. 41 */ 42 @OptionClass(alias = "battery-checker") 43 public class DeviceBatteryLevelChecker implements IDeviceTest, IRemoteTest { 44 45 private ITestDevice mTestDevice = null; 46 47 /** 48 * We use max-battery here to coincide with a {@link DeviceSelectionOptions} option of the same 49 * name. Thus, DeviceBatteryLevelChecker 50 */ 51 @Option(name = "max-battery", description = "Charge level below which we force the device to " + 52 "sit and charge. Range: 0-100.") 53 private Integer mMaxBattery = 20; 54 55 @Option(name = "resume-level", description = "Charge level at which we release the device to " + 56 "begin testing again. Range: 0-100.") 57 private int mResumeLevel = 80; 58 59 /** 60 * This is decoupled from the log poll time below specifically to allow this invocation to be 61 * killed without having to wait for the full log period to lapse. 62 */ 63 @Option(name = "poll-time", description = "Time in minutes to wait between battery level " + 64 "polls. Decimal times accepted.") 65 private double mChargingPollTime = 1.0; 66 67 @Option(name = "batt-log-period", description = "Min time in minutes to wait between " + 68 "printing current battery level to log. Decimal times accepted.") 69 private double mLoggingPollTime = 10.0; 70 71 @Option(name = "reboot-charging-devices", description = "Whether to reboot a device when we " + 72 "detect that it should be held for charging. This would hopefully kill any battery-" + 73 "draining processes and allow the device to charge at its fastest rate.") 74 private boolean mRebootChargeDevices = false; 75 76 @Option(name = "stop-runtime", description = "Whether to stop runtime.") 77 private boolean mStopRuntime = false; 78 79 @Option(name = "stop-logcat", description = "Whether to stop logcat during the recharge. " 80 + "this option is enabled by default.") 81 private boolean mStopLogcat = true; 82 83 @Option( 84 name = "max-run-time", 85 description = "The max run time the battery level checker can run before stopping.", 86 isTimeVal = true 87 ) 88 private long mMaxRunTime = 30 * 60 * 1000L; 89 checkBatteryLevel(ITestDevice device)90 Integer checkBatteryLevel(ITestDevice device) { 91 try { 92 IDevice idevice = device.getIDevice(); 93 // Force a synchronous check, which will also tell us if the device is still alive 94 return idevice.getBattery(500, TimeUnit.MILLISECONDS).get(); 95 } catch (InterruptedException | ExecutionException e) { 96 return null; 97 } 98 } 99 stopDeviceRuntime()100 private void stopDeviceRuntime() throws DeviceNotAvailableException { 101 getDevice().executeShellCommand("stop"); 102 } 103 104 /** 105 * {@inheritDoc} 106 */ 107 @Override run(ITestInvocationListener listener)108 public void run(ITestInvocationListener listener) throws DeviceNotAvailableException { 109 Assert.assertNotNull(mTestDevice); 110 111 Integer batteryLevel = checkBatteryLevel(mTestDevice); 112 113 if (batteryLevel == null) { 114 CLog.w("Failed to determine battery level for device %s.", 115 mTestDevice.getSerialNumber()); 116 return; 117 } else if (batteryLevel < mMaxBattery) { 118 // Time-out. Send the device to the corner 119 CLog.w("Battery level %d is below the min level %d; holding for device %s to charge " + 120 "to level %d", batteryLevel, mMaxBattery, mTestDevice.getSerialNumber(), 121 mResumeLevel); 122 } else { 123 // Good to go 124 CLog.d("Battery level %d is above the minimum of %d; %s is good to go.", batteryLevel, 125 mMaxBattery, mTestDevice.getSerialNumber()); 126 return; 127 } 128 129 if (mRebootChargeDevices) { 130 // reboot the device, in an attempt to kill any battery-draining processes 131 CLog.d("Rebooting device %s prior to holding", mTestDevice.getSerialNumber()); 132 mTestDevice.reboot(); 133 } 134 135 // turn screen off 136 turnScreenOff(mTestDevice); 137 138 if (mStopRuntime) { 139 stopDeviceRuntime(); 140 } 141 // Stop our logcat receiver 142 if (mStopLogcat) { 143 getDevice().stopLogcat(); 144 } 145 146 // If we're down here, it's time to hold the device until it reaches mResumeLevel 147 Long lastReportTime = System.currentTimeMillis(); 148 Integer newLevel = checkBatteryLevel(mTestDevice); 149 150 long startTime = System.currentTimeMillis(); 151 while (batteryLevel != null && batteryLevel < mResumeLevel) { 152 if (System.currentTimeMillis() - lastReportTime > mLoggingPollTime * 60 * 1000) { 153 // Log the battery level status every mLoggingPollTime minutes 154 CLog.w("Battery level for device %s is currently %d", mTestDevice.getSerialNumber(), 155 newLevel); 156 lastReportTime = System.currentTimeMillis(); 157 } 158 if (System.currentTimeMillis() - startTime > mMaxRunTime) { 159 CLog.w( 160 "DeviceBatteryLevelChecker has been running for %s. terminating.", 161 TimeUtil.formatElapsedTime(mMaxRunTime)); 162 break; 163 } 164 165 getRunUtil().sleep((long) (mChargingPollTime * 60 * 1000)); 166 newLevel = checkBatteryLevel(mTestDevice); 167 if (newLevel == null) { 168 // weird 169 CLog.w("Breaking out of wait loop because battery level read failed for device %s", 170 mTestDevice.getSerialNumber()); 171 break; 172 } else if (newLevel < batteryLevel) { 173 // also weird 174 CLog.w("Warning: battery discharged from %d to %d on device %s during the last " + 175 "%.02f minutes.", batteryLevel, newLevel, mTestDevice.getSerialNumber(), 176 mChargingPollTime); 177 } else { 178 CLog.v("Battery level for device %s is currently %d", mTestDevice.getSerialNumber(), 179 newLevel); 180 } 181 batteryLevel = newLevel; 182 } 183 CLog.w("Device %s is now charged to battery level %d; releasing.", 184 mTestDevice.getSerialNumber(), batteryLevel); 185 } 186 turnScreenOff(ITestDevice device)187 private void turnScreenOff(ITestDevice device) throws DeviceNotAvailableException { 188 // disable always on 189 device.executeShellCommand("svc power stayon false"); 190 // set screen timeout to 1s 191 device.executeShellCommand("settings put system screen_off_timeout 1000"); 192 // pause for 5s to ensure that screen would be off 193 getRunUtil().sleep(5000); 194 } 195 196 /** 197 * Get a RunUtil instance 198 * 199 * <p>Exposed for unit testing 200 */ 201 @VisibleForTesting getRunUtil()202 IRunUtil getRunUtil() { 203 return RunUtil.getDefault(); 204 } 205 206 @Override setDevice(ITestDevice device)207 public void setDevice(ITestDevice device) { 208 mTestDevice = device; 209 } 210 211 @Override getDevice()212 public ITestDevice getDevice() { 213 return mTestDevice; 214 } 215 setResumeLevel(int level)216 protected void setResumeLevel(int level) { 217 mResumeLevel = level; 218 } 219 } 220 221