OLD | NEW |
1 # Copyright 2015 The Chromium Authors. All rights reserved. | 1 # Copyright 2015 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides a variety of device interactions with power. | 5 """Provides a variety of device interactions with power. |
6 """ | 6 """ |
7 # pylint: disable=unused-argument | 7 # pylint: disable=unused-argument |
8 | 8 |
9 import collections | 9 import collections |
10 import contextlib | 10 import contextlib |
11 import csv | 11 import csv |
12 import logging | 12 import logging |
13 | 13 |
14 from pylib import constants | 14 from pylib import constants |
15 from pylib.device import decorators | 15 from pylib.device import decorators |
16 from pylib.device import device_errors | 16 from pylib.device import device_errors |
17 from pylib.device import device_utils | 17 from pylib.device import device_utils |
18 from pylib.utils import timeout_retry | 18 from pylib.utils import timeout_retry |
19 | 19 |
20 _DEFAULT_TIMEOUT = 30 | 20 _DEFAULT_TIMEOUT = 30 |
21 _DEFAULT_RETRIES = 3 | 21 _DEFAULT_RETRIES = 3 |
22 | 22 |
23 _CONTROL_CHARGING_COMMANDS = [ | 23 |
| 24 _DEVICE_PROFILES = [ |
24 { | 25 { |
25 # Nexus 4 | 26 'name': 'Nexus 4', |
26 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', | 27 'witness_file': '/sys/module/pm8921_charger/parameters/disabled', |
27 'enable_command': 'echo 0 > /sys/module/pm8921_charger/parameters/disabled', | 28 'enable_command': ( |
28 'disable_command': | 29 'echo 0 > /sys/module/pm8921_charger/parameters/disabled && ' |
29 'echo 1 > /sys/module/pm8921_charger/parameters/disabled', | 30 'dumpsys battery reset'), |
| 31 'disable_command': ( |
| 32 'echo 1 > /sys/module/pm8921_charger/parameters/disabled && ' |
| 33 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), |
| 34 'charge_counter': None, |
| 35 'voltage': None, |
| 36 'current': None, |
30 }, | 37 }, |
31 { | 38 { |
| 39 'name': 'Nexus 5', |
32 # Nexus 5 | 40 # Nexus 5 |
33 # Setting the HIZ bit of the bq24192 causes the charger to actually ignore | 41 # Setting the HIZ bit of the bq24192 causes the charger to actually ignore |
34 # energy coming from USB. Setting the power_supply offline just updates the | 42 # energy coming from USB. Setting the power_supply offline just updates the |
35 # Android system to reflect that. | 43 # Android system to reflect that. |
36 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT', | 44 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT', |
37 'enable_command': ( | 45 'enable_command': ( |
38 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' | 46 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' |
39 'echo 1 > /sys/class/power_supply/usb/online'), | 47 'echo 1 > /sys/class/power_supply/usb/online &&' |
| 48 'dumpsys battery reset'), |
40 'disable_command': ( | 49 'disable_command': ( |
41 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' | 50 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' |
42 'chmod 644 /sys/class/power_supply/usb/online && ' | 51 'chmod 644 /sys/class/power_supply/usb/online && ' |
43 'echo 0 > /sys/class/power_supply/usb/online'), | 52 'echo 0 > /sys/class/power_supply/usb/online && ' |
| 53 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), |
| 54 'charge_counter': None, |
| 55 'voltage': None, |
| 56 'current': None, |
| 57 }, |
| 58 { |
| 59 'name': 'Nexus 6', |
| 60 'witness_file': None, |
| 61 'enable_command': ( |
| 62 'echo 1 > /sys/class/power_supply/battery/charging_enabled && ' |
| 63 'dumpsys battery reset'), |
| 64 'disable_command': ( |
| 65 'echo 0 > /sys/class/power_supply/battery/charging_enabled && ' |
| 66 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), |
| 67 'charge_counter': ( |
| 68 '/sys/class/power_supply/max170xx_battery/charge_counter_ext'), |
| 69 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now', |
| 70 'current': '/sys/class/power_supply/max170xx_battery/current_now', |
| 71 }, |
| 72 { |
| 73 'name': 'Nexus 9', |
| 74 'witness_file': None, |
| 75 'enable_command': ( |
| 76 'echo Disconnected > ' |
| 77 '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && ' |
| 78 'dumpsys battery reset'), |
| 79 'disable_command': ( |
| 80 'echo Connected > ' |
| 81 '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && ' |
| 82 'dumpsys battery set ac 0 && dumpsys battery set usb 0'), |
| 83 'charge_counter': ( |
| 84 '/sys/class/power_supply/max170xx_battery/charge_counter_ext'), |
| 85 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now', |
| 86 'current': '/sys/class/power_supply/max170xx_battery/current_now', |
| 87 }, |
| 88 { |
| 89 'name': 'Nexus 10', |
| 90 'witness_file': None, |
| 91 'enable_command': None, |
| 92 'disable_command': None, |
| 93 'charge_counter': ( |
| 94 '/sys/class/power_supply/ds2784-fuelgauge/charge_counter_ext'), |
| 95 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now', |
| 96 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now', |
| 97 |
44 }, | 98 }, |
45 ] | 99 ] |
46 | 100 |
47 # The list of useful dumpsys columns. | 101 # The list of useful dumpsys columns. |
48 # Index of the column containing the format version. | 102 # Index of the column containing the format version. |
49 _DUMP_VERSION_INDEX = 0 | 103 _DUMP_VERSION_INDEX = 0 |
50 # Index of the column containing the type of the row. | 104 # Index of the column containing the type of the row. |
51 _ROW_TYPE_INDEX = 3 | 105 _ROW_TYPE_INDEX = 3 |
52 # Index of the column containing the uid. | 106 # Index of the column containing the uid. |
53 _PACKAGE_UID_INDEX = 4 | 107 _PACKAGE_UID_INDEX = 4 |
(...skipping 27 matching lines...) Expand all Loading... |
81 TypeError: If it is not passed a DeviceUtils instance. | 135 TypeError: If it is not passed a DeviceUtils instance. |
82 """ | 136 """ |
83 if not isinstance(device, device_utils.DeviceUtils): | 137 if not isinstance(device, device_utils.DeviceUtils): |
84 raise TypeError('Must be initialized with DeviceUtils object.') | 138 raise TypeError('Must be initialized with DeviceUtils object.') |
85 self._device = device | 139 self._device = device |
86 self._cache = device.GetClientCache(self.__class__.__name__) | 140 self._cache = device.GetClientCache(self.__class__.__name__) |
87 self._default_timeout = default_timeout | 141 self._default_timeout = default_timeout |
88 self._default_retries = default_retries | 142 self._default_retries = default_retries |
89 | 143 |
90 @decorators.WithTimeoutAndRetriesFromInstance() | 144 @decorators.WithTimeoutAndRetriesFromInstance() |
| 145 def SupportsFuelGauge(self, timeout=None, retries=None): |
| 146 """Detect if fuel gauge chip is present. |
| 147 |
| 148 Args: |
| 149 timeout: timeout in seconds |
| 150 retries: number of retries |
| 151 |
| 152 Returns: |
| 153 True if known fuel gauge files are present. |
| 154 False otherwise. |
| 155 """ |
| 156 self._DiscoverDeviceProfile() |
| 157 return (self._cache['profile']['enable_command'] != None |
| 158 and self._cache['profile']['charge_counter'] != None) |
| 159 |
| 160 @decorators.WithTimeoutAndRetriesFromInstance() |
| 161 def GetFuelGaugeChargeCounter(self, timeout=None, retries=None): |
| 162 """Get value of charge_counter on fuel gauge chip. |
| 163 |
| 164 Device must have charging disabled for this, not just battery updates |
| 165 disabled. The only device that this currently works with is the nexus 5. |
| 166 |
| 167 Args: |
| 168 timeout: timeout in seconds |
| 169 retries: number of retries |
| 170 |
| 171 Returns: |
| 172 value of charge_counter for fuel gauge chip in units of nAh. |
| 173 |
| 174 Raises: |
| 175 device_errors.CommandFailedError: If fuel gauge chip not found. |
| 176 """ |
| 177 if self.SupportsFuelGauge(): |
| 178 return int(self._device.ReadFile( |
| 179 self._cache['profile']['charge_counter'])) |
| 180 raise device_errors.CommandFailedError( |
| 181 'Unable to find fuel gauge.') |
| 182 |
| 183 @decorators.WithTimeoutAndRetriesFromInstance() |
91 def GetNetworkData(self, package, timeout=None, retries=None): | 184 def GetNetworkData(self, package, timeout=None, retries=None): |
92 """ Get network data for specific package. | 185 """Get network data for specific package. |
93 | 186 |
94 Args: | 187 Args: |
95 package: package name you want network data for. | 188 package: package name you want network data for. |
96 timeout: timeout in seconds | 189 timeout: timeout in seconds |
97 retries: number of retries | 190 retries: number of retries |
98 | 191 |
99 Returns: | 192 Returns: |
100 Tuple of (sent_data, recieved_data) | 193 Tuple of (sent_data, recieved_data) |
101 None if no network data found | 194 None if no network data found |
102 """ | 195 """ |
(...skipping 17 matching lines...) Expand all Loading... |
120 send_data = 0 | 213 send_data = 0 |
121 try: | 214 try: |
122 recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv')) | 215 recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv')) |
123 except device_errors.AdbShellCommandFailedError: | 216 except device_errors.AdbShellCommandFailedError: |
124 logging.warning('No received data found for package %s', package) | 217 logging.warning('No received data found for package %s', package) |
125 recv_data = 0 | 218 recv_data = 0 |
126 return (send_data, recv_data) | 219 return (send_data, recv_data) |
127 | 220 |
128 @decorators.WithTimeoutAndRetriesFromInstance() | 221 @decorators.WithTimeoutAndRetriesFromInstance() |
129 def GetPowerData(self, timeout=None, retries=None): | 222 def GetPowerData(self, timeout=None, retries=None): |
130 """ Get power data for device. | 223 """Get power data for device. |
| 224 |
131 Args: | 225 Args: |
132 timeout: timeout in seconds | 226 timeout: timeout in seconds |
133 retries: number of retries | 227 retries: number of retries |
134 | 228 |
135 Returns: | 229 Returns: |
136 Dict of power data, keyed on package names. | 230 Dict of power data, keyed on package names. |
137 { | 231 { |
138 package_name: { | 232 package_name: { |
139 'uid': uid, | 233 'uid': uid, |
140 'data': [1,2,3] | 234 'data': [1,2,3] |
(...skipping 26 matching lines...) Expand all Loading... |
167 and entry[_ROW_TYPE_INDEX] == 'pwi' | 261 and entry[_ROW_TYPE_INDEX] == 'pwi' |
168 and entry[_PWI_AGGREGATION_INDEX] == 'l'): | 262 and entry[_PWI_AGGREGATION_INDEX] == 'l'): |
169 pwi_entries[entry[_PWI_UID_INDEX]].append( | 263 pwi_entries[entry[_PWI_UID_INDEX]].append( |
170 float(entry[_PWI_POWER_CONSUMPTION_INDEX])) | 264 float(entry[_PWI_POWER_CONSUMPTION_INDEX])) |
171 | 265 |
172 return {p: {'uid': uid, 'data': pwi_entries[uid]} | 266 return {p: {'uid': uid, 'data': pwi_entries[uid]} |
173 for p, uid in self._cache['uids'].iteritems()} | 267 for p, uid in self._cache['uids'].iteritems()} |
174 | 268 |
175 @decorators.WithTimeoutAndRetriesFromInstance() | 269 @decorators.WithTimeoutAndRetriesFromInstance() |
176 def GetPackagePowerData(self, package, timeout=None, retries=None): | 270 def GetPackagePowerData(self, package, timeout=None, retries=None): |
177 """ Get power data for particular package. | 271 """Get power data for particular package. |
178 | 272 |
179 Args: | 273 Args: |
180 package: Package to get power data on. | 274 package: Package to get power data on. |
181 | 275 |
182 returns: | 276 returns: |
183 Dict of UID and power data. | 277 Dict of UID and power data. |
184 { | 278 { |
185 'uid': uid, | 279 'uid': uid, |
186 'data': [1,2,3] | 280 'data': [1,2,3] |
187 } | 281 } |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
239 Args: | 333 Args: |
240 enabled: A boolean indicating whether charging should be enabled or | 334 enabled: A boolean indicating whether charging should be enabled or |
241 disabled. | 335 disabled. |
242 timeout: timeout in seconds | 336 timeout: timeout in seconds |
243 retries: number of retries | 337 retries: number of retries |
244 | 338 |
245 Raises: | 339 Raises: |
246 device_errors.CommandFailedError: If method of disabling charging cannot | 340 device_errors.CommandFailedError: If method of disabling charging cannot |
247 be determined. | 341 be determined. |
248 """ | 342 """ |
249 if 'charging_config' not in self._cache: | 343 self._DiscoverDeviceProfile() |
250 for c in _CONTROL_CHARGING_COMMANDS: | 344 if not self._cache['profile']['enable_command']: |
251 if self._device.FileExists(c['witness_file']): | 345 raise device_errors.CommandFailedError( |
252 self._cache['charging_config'] = c | 346 'Unable to find charging commands.') |
253 break | |
254 else: | |
255 raise device_errors.CommandFailedError( | |
256 'Unable to find charging commands.') | |
257 | 347 |
258 if enabled: | 348 if enabled: |
259 command = self._cache['charging_config']['enable_command'] | 349 command = self._cache['profile']['enable_command'] |
260 else: | 350 else: |
261 command = self._cache['charging_config']['disable_command'] | 351 command = self._cache['profile']['disable_command'] |
262 | 352 |
263 def set_and_verify_charging(): | 353 def set_and_verify_charging(): |
264 self._device.RunShellCommand(command, check_return=True) | 354 self._device.RunShellCommand(command, check_return=True) |
265 return self.GetCharging() == enabled | 355 return self.GetCharging() == enabled |
266 | 356 |
267 timeout_retry.WaitFor(set_and_verify_charging, wait_period=1) | 357 timeout_retry.WaitFor(set_and_verify_charging, wait_period=1) |
268 | 358 |
269 # TODO(rnephew): Make private when all use cases can use the context manager. | 359 # TODO(rnephew): Make private when all use cases can use the context manager. |
270 @decorators.WithTimeoutAndRetriesFromInstance() | 360 @decorators.WithTimeoutAndRetriesFromInstance() |
271 def DisableBatteryUpdates(self, timeout=None, retries=None): | 361 def DisableBatteryUpdates(self, timeout=None, retries=None): |
272 """ Resets battery data and makes device appear like it is not | 362 """Resets battery data and makes device appear like it is not |
273 charging so that it will collect power data since last charge. | 363 charging so that it will collect power data since last charge. |
274 | 364 |
275 Args: | 365 Args: |
276 timeout: timeout in seconds | 366 timeout: timeout in seconds |
277 retries: number of retries | 367 retries: number of retries |
278 | 368 |
279 Raises: | 369 Raises: |
280 device_errors.CommandFailedError: When resetting batterystats fails to | 370 device_errors.CommandFailedError: When resetting batterystats fails to |
281 reset power values. | 371 reset power values. |
282 device_errors.DeviceVersionError: If device is not L or higher. | 372 device_errors.DeviceVersionError: If device is not L or higher. |
283 """ | 373 """ |
284 def battery_updates_disabled(): | 374 def battery_updates_disabled(): |
285 return self.GetCharging() is False | 375 return self.GetCharging() is False |
286 | 376 |
287 if (self._device.build_version_sdk < | 377 self._ClearPowerData() |
288 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): | |
289 raise device_errors.DeviceVersionError('Device must be L or higher.') | |
290 | |
291 self._device.RunShellCommand( | |
292 ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True) | |
293 self._device.RunShellCommand( | |
294 ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True) | |
295 self._device.RunShellCommand( | |
296 ['dumpsys', 'batterystats', '--reset'], check_return=True) | |
297 battery_data = self._device.RunShellCommand( | |
298 ['dumpsys', 'batterystats', '--charged', '--checkin'], | |
299 check_return=True, large_output=True) | |
300 ROW_TYPE_INDEX = 3 | |
301 PWI_POWER_INDEX = 5 | |
302 for line in battery_data: | |
303 l = line.split(',') | |
304 if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi' | |
305 and l[PWI_POWER_INDEX] != 0): | |
306 raise device_errors.CommandFailedError( | |
307 'Non-zero pmi value found after reset.') | |
308 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'], | 378 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'], |
309 check_return=True) | 379 check_return=True) |
310 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'], | 380 self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'], |
311 check_return=True) | 381 check_return=True) |
312 timeout_retry.WaitFor(battery_updates_disabled, wait_period=1) | 382 timeout_retry.WaitFor(battery_updates_disabled, wait_period=1) |
313 | 383 |
314 # TODO(rnephew): Make private when all use cases can use the context manager. | 384 # TODO(rnephew): Make private when all use cases can use the context manager. |
315 @decorators.WithTimeoutAndRetriesFromInstance() | 385 @decorators.WithTimeoutAndRetriesFromInstance() |
316 def EnableBatteryUpdates(self, timeout=None, retries=None): | 386 def EnableBatteryUpdates(self, timeout=None, retries=None): |
317 """ Restarts device charging so that dumpsys no longer collects power data. | 387 """Restarts device charging so that dumpsys no longer collects power data. |
318 | 388 |
319 Args: | 389 Args: |
320 timeout: timeout in seconds | 390 timeout: timeout in seconds |
321 retries: number of retries | 391 retries: number of retries |
322 | 392 |
323 Raises: | 393 Raises: |
324 device_errors.DeviceVersionError: If device is not L or higher. | 394 device_errors.DeviceVersionError: If device is not L or higher. |
325 """ | 395 """ |
326 def battery_updates_enabled(): | 396 def battery_updates_enabled(): |
327 return self.GetCharging() is True | 397 return (self.GetCharging() |
328 | 398 or not bool('UPDATES STOPPED' in self._device.RunShellCommand( |
329 if (self._device.build_version_sdk < | 399 ['dumpsys', 'battery'], check_return=True))) |
330 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): | |
331 raise device_errors.DeviceVersionError('Device must be L or higher.') | |
332 | 400 |
333 self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], | 401 self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], |
334 check_return=True) | 402 check_return=True) |
335 timeout_retry.WaitFor(battery_updates_enabled, wait_period=1) | 403 timeout_retry.WaitFor(battery_updates_enabled, wait_period=1) |
336 | 404 |
337 @contextlib.contextmanager | 405 @contextlib.contextmanager |
338 def BatteryMeasurement(self, timeout=None, retries=None): | 406 def BatteryMeasurement(self, timeout=None, retries=None): |
339 """Context manager that enables battery data collection. It makes | 407 """Context manager that enables battery data collection. It makes |
340 the device appear to stop charging so that dumpsys will start collecting | 408 the device appear to stop charging so that dumpsys will start collecting |
341 power data since last charge. Once the with block is exited, charging is | 409 power data since last charge. Once the with block is exited, charging is |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
394 wait_period: time in seconds to wait between checking. | 462 wait_period: time in seconds to wait between checking. |
395 """ | 463 """ |
396 def cool_device(): | 464 def cool_device(): |
397 temp = self.GetBatteryInfo().get('temperature') | 465 temp = self.GetBatteryInfo().get('temperature') |
398 if temp is None: | 466 if temp is None: |
399 logging.warning('Unable to find current battery temperature.') | 467 logging.warning('Unable to find current battery temperature.') |
400 temp = 0 | 468 temp = 0 |
401 else: | 469 else: |
402 logging.info('Current battery temperature: %s', temp) | 470 logging.info('Current battery temperature: %s', temp) |
403 return int(temp) <= target_temp | 471 return int(temp) <= target_temp |
404 | 472 self.EnableBatteryUpdates() |
405 logging.info('Waiting for the device to cool down to %s degrees.', | 473 logging.info('Waiting for the device to cool down to %s (0.1 C)', |
406 target_temp) | 474 target_temp) |
407 timeout_retry.WaitFor(cool_device, wait_period=wait_period) | 475 timeout_retry.WaitFor(cool_device, wait_period=wait_period) |
| 476 |
| 477 @decorators.WithTimeoutAndRetriesFromInstance() |
| 478 def TieredSetCharging(self, enabled, timeout=None, retries=None): |
| 479 """Enables or disables charging on the device. |
| 480 |
| 481 Args: |
| 482 enabled: A boolean indicating whether charging should be enabled or |
| 483 disabled. |
| 484 timeout: timeout in seconds |
| 485 retries: number of retries |
| 486 """ |
| 487 if self.GetCharging() == enabled: |
| 488 logging.warning('Device charging already in expected state: %s', enabled) |
| 489 return |
| 490 |
| 491 if enabled: |
| 492 try: |
| 493 self.SetCharging(enabled) |
| 494 except device_errors.CommandFailedError: |
| 495 logging.info('Unable to enable charging via hardware.' |
| 496 ' Falling back to software enabling.') |
| 497 self.EnableBatteryUpdates() |
| 498 else: |
| 499 try: |
| 500 self._ClearPowerData() |
| 501 self.SetCharging(enabled) |
| 502 except device_errors.CommandFailedError: |
| 503 logging.info('Unable to disable charging via hardware.' |
| 504 ' Falling back to software disabling.') |
| 505 self.DisableBatteryUpdates() |
| 506 |
| 507 @contextlib.contextmanager |
| 508 def PowerMeasurement(self, timeout=None, retries=None): |
| 509 """Context manager that enables battery power collection. |
| 510 |
| 511 Once the with block is exited, charging is resumed. Will attempt to disable |
| 512 charging at the hardware level, and if that fails will fall back to software |
| 513 disabling of battery updates. |
| 514 |
| 515 Only for devices L and higher. |
| 516 |
| 517 Example usage: |
| 518 with PowerMeasurement(): |
| 519 browser_actions() |
| 520 get_power_data() # report usage within this block |
| 521 after_measurements() # Anything that runs after power |
| 522 # measurements are collected |
| 523 |
| 524 Args: |
| 525 timeout: timeout in seconds |
| 526 retries: number of retries |
| 527 """ |
| 528 try: |
| 529 self.TieredSetCharging(False, timeout=timeout, retries=retries) |
| 530 yield |
| 531 finally: |
| 532 self.TieredSetCharging(True, timeout=timeout, retries=retries) |
| 533 |
| 534 def _ClearPowerData(self): |
| 535 """Resets battery data and makes device appear like it is not |
| 536 charging so that it will collect power data since last charge. |
| 537 |
| 538 Returns: |
| 539 True if power data cleared. |
| 540 False if power data clearing is not supported (pre-L) |
| 541 |
| 542 Raises: |
| 543 device_errors.DeviceVersionError: If power clearing is supported, |
| 544 but fails. |
| 545 """ |
| 546 if (self._device.build_version_sdk < |
| 547 constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): |
| 548 logging.warning('Dumpsys power data only available on 5.0 and above. ' |
| 549 'Cannot clear power data.') |
| 550 return False |
| 551 |
| 552 self._device.RunShellCommand( |
| 553 ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True) |
| 554 self._device.RunShellCommand( |
| 555 ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True) |
| 556 self._device.RunShellCommand( |
| 557 ['dumpsys', 'batterystats', '--reset'], check_return=True) |
| 558 battery_data = self._device.RunShellCommand( |
| 559 ['dumpsys', 'batterystats', '--charged', '--checkin'], |
| 560 check_return=True, large_output=True) |
| 561 for line in battery_data: |
| 562 l = line.split(',') |
| 563 if (len(l) > _PWI_POWER_CONSUMPTION_INDEX and l[_ROW_TYPE_INDEX] == 'pwi' |
| 564 and l[_PWI_POWER_CONSUMPTION_INDEX] != 0): |
| 565 self._device.RunShellCommand( |
| 566 ['dumpsys', 'battery', 'reset'], check_return=True) |
| 567 raise device_errors.CommandFailedError( |
| 568 'Non-zero pmi value found after reset.') |
| 569 self._device.RunShellCommand( |
| 570 ['dumpsys', 'battery', 'reset'], check_return=True) |
| 571 return True |
| 572 |
| 573 def _DiscoverDeviceProfile(self): |
| 574 """Checks and caches device information. |
| 575 |
| 576 Returns: |
| 577 True if profile is found, false otherwise. |
| 578 """ |
| 579 |
| 580 if 'profile' in self._cache: |
| 581 return True |
| 582 for profile in _DEVICE_PROFILES: |
| 583 if self._device.product_model == profile['name']: |
| 584 self._cache['profile'] = profile |
| 585 return True |
| 586 self._cache['profile'] = { |
| 587 'name': None, |
| 588 'witness_file': None, |
| 589 'enable_command': None, |
| 590 'disable_command': None, |
| 591 'charge_counter': None, |
| 592 'voltage': None, |
| 593 'current': None, |
| 594 } |
| 595 return False |
OLD | NEW |