| Index: build/android/devil/android/battery_utils.py
|
| diff --git a/build/android/devil/android/battery_utils.py b/build/android/devil/android/battery_utils.py
|
| deleted file mode 100644
|
| index f499720a8092828fd9f4003b77ce566c05ec776a..0000000000000000000000000000000000000000
|
| --- a/build/android/devil/android/battery_utils.py
|
| +++ /dev/null
|
| @@ -1,649 +0,0 @@
|
| -# Copyright 2015 The Chromium Authors. All rights reserved.
|
| -# Use of this source code is governed by a BSD-style license that can be
|
| -# found in the LICENSE file.
|
| -
|
| -"""Provides a variety of device interactions with power.
|
| -"""
|
| -# pylint: disable=unused-argument
|
| -
|
| -import collections
|
| -import contextlib
|
| -import csv
|
| -import logging
|
| -
|
| -from devil.android import decorators
|
| -from devil.android import device_errors
|
| -from devil.android import device_utils
|
| -from devil.android.sdk import version_codes
|
| -from devil.utils import timeout_retry
|
| -
|
| -_DEFAULT_TIMEOUT = 30
|
| -_DEFAULT_RETRIES = 3
|
| -
|
| -
|
| -_DEVICE_PROFILES = [
|
| - {
|
| - 'name': 'Nexus 4',
|
| - 'witness_file': '/sys/module/pm8921_charger/parameters/disabled',
|
| - 'enable_command': (
|
| - 'echo 0 > /sys/module/pm8921_charger/parameters/disabled && '
|
| - 'dumpsys battery reset'),
|
| - 'disable_command': (
|
| - 'echo 1 > /sys/module/pm8921_charger/parameters/disabled && '
|
| - 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
|
| - 'charge_counter': None,
|
| - 'voltage': None,
|
| - 'current': None,
|
| - },
|
| - {
|
| - 'name': 'Nexus 5',
|
| - # Nexus 5
|
| - # Setting the HIZ bit of the bq24192 causes the charger to actually ignore
|
| - # energy coming from USB. Setting the power_supply offline just updates the
|
| - # Android system to reflect that.
|
| - 'witness_file': '/sys/kernel/debug/bq24192/INPUT_SRC_CONT',
|
| - 'enable_command': (
|
| - 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
|
| - 'chmod 644 /sys/class/power_supply/usb/online && '
|
| - 'echo 1 > /sys/class/power_supply/usb/online && '
|
| - 'dumpsys battery reset'),
|
| - 'disable_command': (
|
| - 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
|
| - 'chmod 644 /sys/class/power_supply/usb/online && '
|
| - 'echo 0 > /sys/class/power_supply/usb/online && '
|
| - 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
|
| - 'charge_counter': None,
|
| - 'voltage': None,
|
| - 'current': None,
|
| - },
|
| - {
|
| - 'name': 'Nexus 6',
|
| - 'witness_file': None,
|
| - 'enable_command': (
|
| - 'echo 1 > /sys/class/power_supply/battery/charging_enabled && '
|
| - 'dumpsys battery reset'),
|
| - 'disable_command': (
|
| - 'echo 0 > /sys/class/power_supply/battery/charging_enabled && '
|
| - 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
|
| - 'charge_counter': (
|
| - '/sys/class/power_supply/max170xx_battery/charge_counter_ext'),
|
| - 'voltage': '/sys/class/power_supply/max170xx_battery/voltage_now',
|
| - 'current': '/sys/class/power_supply/max170xx_battery/current_now',
|
| - },
|
| - {
|
| - 'name': 'Nexus 9',
|
| - 'witness_file': None,
|
| - 'enable_command': (
|
| - 'echo Disconnected > '
|
| - '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
|
| - 'dumpsys battery reset'),
|
| - 'disable_command': (
|
| - 'echo Connected > '
|
| - '/sys/bus/i2c/drivers/bq2419x/0-006b/input_cable_state && '
|
| - 'dumpsys battery set ac 0 && dumpsys battery set usb 0'),
|
| - 'charge_counter': '/sys/class/power_supply/battery/charge_counter_ext',
|
| - 'voltage': '/sys/class/power_supply/battery/voltage_now',
|
| - 'current': '/sys/class/power_supply/battery/current_now',
|
| - },
|
| - {
|
| - 'name': 'Nexus 10',
|
| - 'witness_file': None,
|
| - 'enable_command': None,
|
| - 'disable_command': None,
|
| - 'charge_counter': None,
|
| - 'voltage': '/sys/class/power_supply/ds2784-fuelgauge/voltage_now',
|
| - 'current': '/sys/class/power_supply/ds2784-fuelgauge/current_now',
|
| -
|
| - },
|
| -]
|
| -
|
| -# The list of useful dumpsys columns.
|
| -# Index of the column containing the format version.
|
| -_DUMP_VERSION_INDEX = 0
|
| -# Index of the column containing the type of the row.
|
| -_ROW_TYPE_INDEX = 3
|
| -# Index of the column containing the uid.
|
| -_PACKAGE_UID_INDEX = 4
|
| -# Index of the column containing the application package.
|
| -_PACKAGE_NAME_INDEX = 5
|
| -# The column containing the uid of the power data.
|
| -_PWI_UID_INDEX = 1
|
| -# The column containing the type of consumption. Only consumption since last
|
| -# charge are of interest here.
|
| -_PWI_AGGREGATION_INDEX = 2
|
| -_PWS_AGGREGATION_INDEX = _PWI_AGGREGATION_INDEX
|
| -# The column containing the amount of power used, in mah.
|
| -_PWI_POWER_CONSUMPTION_INDEX = 5
|
| -_PWS_POWER_CONSUMPTION_INDEX = _PWI_POWER_CONSUMPTION_INDEX
|
| -
|
| -_MAX_CHARGE_ERROR = 20
|
| -
|
| -
|
| -class BatteryUtils(object):
|
| -
|
| - def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT,
|
| - default_retries=_DEFAULT_RETRIES):
|
| - """BatteryUtils constructor.
|
| -
|
| - Args:
|
| - device: A DeviceUtils instance.
|
| - default_timeout: An integer containing the default number of seconds to
|
| - wait for an operation to complete if no explicit value
|
| - is provided.
|
| - default_retries: An integer containing the default number or times an
|
| - operation should be retried on failure if no explicit
|
| - value is provided.
|
| - Raises:
|
| - TypeError: If it is not passed a DeviceUtils instance.
|
| - """
|
| - if not isinstance(device, device_utils.DeviceUtils):
|
| - raise TypeError('Must be initialized with DeviceUtils object.')
|
| - self._device = device
|
| - self._cache = device.GetClientCache(self.__class__.__name__)
|
| - self._default_timeout = default_timeout
|
| - self._default_retries = default_retries
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def SupportsFuelGauge(self, timeout=None, retries=None):
|
| - """Detect if fuel gauge chip is present.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Returns:
|
| - True if known fuel gauge files are present.
|
| - False otherwise.
|
| - """
|
| - self._DiscoverDeviceProfile()
|
| - return (self._cache['profile']['enable_command'] != None
|
| - and self._cache['profile']['charge_counter'] != None)
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def GetFuelGaugeChargeCounter(self, timeout=None, retries=None):
|
| - """Get value of charge_counter on fuel gauge chip.
|
| -
|
| - Device must have charging disabled for this, not just battery updates
|
| - disabled. The only device that this currently works with is the nexus 5.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Returns:
|
| - value of charge_counter for fuel gauge chip in units of nAh.
|
| -
|
| - Raises:
|
| - device_errors.CommandFailedError: If fuel gauge chip not found.
|
| - """
|
| - if self.SupportsFuelGauge():
|
| - return int(self._device.ReadFile(
|
| - self._cache['profile']['charge_counter']))
|
| - raise device_errors.CommandFailedError(
|
| - 'Unable to find fuel gauge.')
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def GetNetworkData(self, package, timeout=None, retries=None):
|
| - """Get network data for specific package.
|
| -
|
| - Args:
|
| - package: package name you want network data for.
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Returns:
|
| - Tuple of (sent_data, recieved_data)
|
| - None if no network data found
|
| - """
|
| - # If device_utils clears cache, cache['uids'] doesn't exist
|
| - if 'uids' not in self._cache:
|
| - self._cache['uids'] = {}
|
| - if package not in self._cache['uids']:
|
| - self.GetPowerData()
|
| - if package not in self._cache['uids']:
|
| - logging.warning('No UID found for %s. Can\'t get network data.',
|
| - package)
|
| - return None
|
| -
|
| - network_data_path = '/proc/uid_stat/%s/' % self._cache['uids'][package]
|
| - try:
|
| - send_data = int(self._device.ReadFile(network_data_path + 'tcp_snd'))
|
| - # If ReadFile throws exception, it means no network data usage file for
|
| - # package has been recorded. Return 0 sent and 0 received.
|
| - except device_errors.AdbShellCommandFailedError:
|
| - logging.warning('No sent data found for package %s', package)
|
| - send_data = 0
|
| - try:
|
| - recv_data = int(self._device.ReadFile(network_data_path + 'tcp_rcv'))
|
| - except device_errors.AdbShellCommandFailedError:
|
| - logging.warning('No received data found for package %s', package)
|
| - recv_data = 0
|
| - return (send_data, recv_data)
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def GetPowerData(self, timeout=None, retries=None):
|
| - """Get power data for device.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Returns:
|
| - Dict containing system power, and a per-package power dict keyed on
|
| - package names.
|
| - {
|
| - 'system_total': 23.1,
|
| - 'per_package' : {
|
| - package_name: {
|
| - 'uid': uid,
|
| - 'data': [1,2,3]
|
| - },
|
| - }
|
| - }
|
| - """
|
| - if 'uids' not in self._cache:
|
| - self._cache['uids'] = {}
|
| - dumpsys_output = self._device.RunShellCommand(
|
| - ['dumpsys', 'batterystats', '-c'],
|
| - check_return=True, large_output=True)
|
| - csvreader = csv.reader(dumpsys_output)
|
| - pwi_entries = collections.defaultdict(list)
|
| - system_total = None
|
| - for entry in csvreader:
|
| - if entry[_DUMP_VERSION_INDEX] not in ['8', '9']:
|
| - # Wrong dumpsys version.
|
| - raise device_errors.DeviceVersionError(
|
| - 'Dumpsys version must be 8 or 9. %s found.'
|
| - % entry[_DUMP_VERSION_INDEX])
|
| - if _ROW_TYPE_INDEX < len(entry) and entry[_ROW_TYPE_INDEX] == 'uid':
|
| - current_package = entry[_PACKAGE_NAME_INDEX]
|
| - if (self._cache['uids'].get(current_package)
|
| - and self._cache['uids'].get(current_package)
|
| - != entry[_PACKAGE_UID_INDEX]):
|
| - raise device_errors.CommandFailedError(
|
| - 'Package %s found multiple times with different UIDs %s and %s'
|
| - % (current_package, self._cache['uids'][current_package],
|
| - entry[_PACKAGE_UID_INDEX]))
|
| - self._cache['uids'][current_package] = entry[_PACKAGE_UID_INDEX]
|
| - elif (_PWI_POWER_CONSUMPTION_INDEX < len(entry)
|
| - and entry[_ROW_TYPE_INDEX] == 'pwi'
|
| - and entry[_PWI_AGGREGATION_INDEX] == 'l'):
|
| - pwi_entries[entry[_PWI_UID_INDEX]].append(
|
| - float(entry[_PWI_POWER_CONSUMPTION_INDEX]))
|
| - elif (_PWS_POWER_CONSUMPTION_INDEX < len(entry)
|
| - and entry[_ROW_TYPE_INDEX] == 'pws'
|
| - and entry[_PWS_AGGREGATION_INDEX] == 'l'):
|
| - # This entry should only appear once.
|
| - assert system_total is None
|
| - system_total = float(entry[_PWS_POWER_CONSUMPTION_INDEX])
|
| -
|
| - per_package = {p: {'uid': uid, 'data': pwi_entries[uid]}
|
| - for p, uid in self._cache['uids'].iteritems()}
|
| - return {'system_total': system_total, 'per_package': per_package}
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def GetBatteryInfo(self, timeout=None, retries=None):
|
| - """Gets battery info for the device.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| - Returns:
|
| - A dict containing various battery information as reported by dumpsys
|
| - battery.
|
| - """
|
| - result = {}
|
| - # Skip the first line, which is just a header.
|
| - for line in self._device.RunShellCommand(
|
| - ['dumpsys', 'battery'], check_return=True)[1:]:
|
| - # If usb charging has been disabled, an extra line of header exists.
|
| - if 'UPDATES STOPPED' in line:
|
| - logging.warning('Dumpsys battery not receiving updates. '
|
| - 'Run dumpsys battery reset if this is in error.')
|
| - elif ':' not in line:
|
| - logging.warning('Unknown line found in dumpsys battery: "%s"', line)
|
| - else:
|
| - k, v = line.split(':', 1)
|
| - result[k.strip()] = v.strip()
|
| - return result
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def GetCharging(self, timeout=None, retries=None):
|
| - """Gets the charging state of the device.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| - Returns:
|
| - True if the device is charging, false otherwise.
|
| - """
|
| - battery_info = self.GetBatteryInfo()
|
| - for k in ('AC powered', 'USB powered', 'Wireless powered'):
|
| - if (k in battery_info and
|
| - battery_info[k].lower() in ('true', '1', 'yes')):
|
| - return True
|
| - return False
|
| -
|
| - # TODO(rnephew): Make private when all use cases can use the context manager.
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def DisableBatteryUpdates(self, timeout=None, retries=None):
|
| - """Resets battery data and makes device appear like it is not
|
| - charging so that it will collect power data since last charge.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Raises:
|
| - device_errors.CommandFailedError: When resetting batterystats fails to
|
| - reset power values.
|
| - device_errors.DeviceVersionError: If device is not L or higher.
|
| - """
|
| - def battery_updates_disabled():
|
| - return self.GetCharging() is False
|
| -
|
| - self._ClearPowerData()
|
| - self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'ac', '0'],
|
| - check_return=True)
|
| - self._device.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'],
|
| - check_return=True)
|
| - timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
|
| -
|
| - # TODO(rnephew): Make private when all use cases can use the context manager.
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def EnableBatteryUpdates(self, timeout=None, retries=None):
|
| - """Restarts device charging so that dumpsys no longer collects power data.
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Raises:
|
| - device_errors.DeviceVersionError: If device is not L or higher.
|
| - """
|
| - def battery_updates_enabled():
|
| - return (self.GetCharging()
|
| - or not bool('UPDATES STOPPED' in self._device.RunShellCommand(
|
| - ['dumpsys', 'battery'], check_return=True)))
|
| -
|
| - self._device.RunShellCommand(['dumpsys', 'battery', 'reset'],
|
| - check_return=True)
|
| - timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
|
| -
|
| - @contextlib.contextmanager
|
| - def BatteryMeasurement(self, timeout=None, retries=None):
|
| - """Context manager that enables battery data collection. It makes
|
| - the device appear to stop charging so that dumpsys will start collecting
|
| - power data since last charge. Once the with block is exited, charging is
|
| - resumed and power data since last charge is no longer collected.
|
| -
|
| - Only for devices L and higher.
|
| -
|
| - Example usage:
|
| - with BatteryMeasurement():
|
| - browser_actions()
|
| - get_power_data() # report usage within this block
|
| - after_measurements() # Anything that runs after power
|
| - # measurements are collected
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Raises:
|
| - device_errors.DeviceVersionError: If device is not L or higher.
|
| - """
|
| - if self._device.build_version_sdk < version_codes.LOLLIPOP:
|
| - raise device_errors.DeviceVersionError('Device must be L or higher.')
|
| - try:
|
| - self.DisableBatteryUpdates(timeout=timeout, retries=retries)
|
| - yield
|
| - finally:
|
| - self.EnableBatteryUpdates(timeout=timeout, retries=retries)
|
| -
|
| - def _DischargeDevice(self, percent, wait_period=120):
|
| - """Disables charging and waits for device to discharge given amount
|
| -
|
| - Args:
|
| - percent: level of charge to discharge.
|
| -
|
| - Raises:
|
| - ValueError: If percent is not between 1 and 99.
|
| - """
|
| - battery_level = int(self.GetBatteryInfo().get('level'))
|
| - if not 0 < percent < 100:
|
| - raise ValueError('Discharge amount(%s) must be between 1 and 99'
|
| - % percent)
|
| - if battery_level is None:
|
| - logging.warning('Unable to find current battery level. Cannot discharge.')
|
| - return
|
| - # Do not discharge if it would make battery level too low.
|
| - if percent >= battery_level - 10:
|
| - logging.warning('Battery is too low or discharge amount requested is too '
|
| - 'high. Cannot discharge phone %s percent.', percent)
|
| - return
|
| -
|
| - self._HardwareSetCharging(False)
|
| - def device_discharged():
|
| - self._HardwareSetCharging(True)
|
| - current_level = int(self.GetBatteryInfo().get('level'))
|
| - logging.info('current battery level: %s', current_level)
|
| - if battery_level - current_level >= percent:
|
| - return True
|
| - self._HardwareSetCharging(False)
|
| - return False
|
| -
|
| - timeout_retry.WaitFor(device_discharged, wait_period=wait_period)
|
| -
|
| - def ChargeDeviceToLevel(self, level, wait_period=60):
|
| - """Enables charging and waits for device to be charged to given level.
|
| -
|
| - Args:
|
| - level: level of charge to wait for.
|
| - wait_period: time in seconds to wait between checking.
|
| - Raises:
|
| - device_errors.DeviceChargingError: If error while charging is detected.
|
| - """
|
| - self.SetCharging(True)
|
| - charge_status = {
|
| - 'charge_failure_count': 0,
|
| - 'last_charge_value': 0
|
| - }
|
| - def device_charged():
|
| - battery_level = self.GetBatteryInfo().get('level')
|
| - if battery_level is None:
|
| - logging.warning('Unable to find current battery level.')
|
| - battery_level = 100
|
| - else:
|
| - logging.info('current battery level: %s', battery_level)
|
| - battery_level = int(battery_level)
|
| -
|
| - # Use > so that it will not reset if charge is going down.
|
| - if battery_level > charge_status['last_charge_value']:
|
| - charge_status['last_charge_value'] = battery_level
|
| - charge_status['charge_failure_count'] = 0
|
| - else:
|
| - charge_status['charge_failure_count'] += 1
|
| -
|
| - if (not battery_level >= level
|
| - and charge_status['charge_failure_count'] >= _MAX_CHARGE_ERROR):
|
| - raise device_errors.DeviceChargingError(
|
| - 'Device not charging properly. Current level:%s Previous level:%s'
|
| - % (battery_level, charge_status['last_charge_value']))
|
| - return battery_level >= level
|
| -
|
| - timeout_retry.WaitFor(device_charged, wait_period=wait_period)
|
| -
|
| - def LetBatteryCoolToTemperature(self, target_temp, wait_period=180):
|
| - """Lets device sit to give battery time to cool down
|
| - Args:
|
| - temp: maximum temperature to allow in tenths of degrees c.
|
| - wait_period: time in seconds to wait between checking.
|
| - """
|
| - def cool_device():
|
| - temp = self.GetBatteryInfo().get('temperature')
|
| - if temp is None:
|
| - logging.warning('Unable to find current battery temperature.')
|
| - temp = 0
|
| - else:
|
| - logging.info('Current battery temperature: %s', temp)
|
| - if int(temp) <= target_temp:
|
| - return True
|
| - else:
|
| - if self._cache['profile']['name'] == 'Nexus 5':
|
| - self._DischargeDevice(1)
|
| - return False
|
| -
|
| - self._DiscoverDeviceProfile()
|
| - self.EnableBatteryUpdates()
|
| - logging.info('Waiting for the device to cool down to %s (0.1 C)',
|
| - target_temp)
|
| - timeout_retry.WaitFor(cool_device, wait_period=wait_period)
|
| -
|
| - @decorators.WithTimeoutAndRetriesFromInstance()
|
| - def SetCharging(self, enabled, timeout=None, retries=None):
|
| - """Enables or disables charging on the device.
|
| -
|
| - Args:
|
| - enabled: A boolean indicating whether charging should be enabled or
|
| - disabled.
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| - """
|
| - if self.GetCharging() == enabled:
|
| - logging.warning('Device charging already in expected state: %s', enabled)
|
| - return
|
| -
|
| - self._DiscoverDeviceProfile()
|
| - if enabled:
|
| - if self._cache['profile']['enable_command']:
|
| - self._HardwareSetCharging(enabled)
|
| - else:
|
| - logging.info('Unable to enable charging via hardware. '
|
| - 'Falling back to software enabling.')
|
| - self.EnableBatteryUpdates()
|
| - else:
|
| - if self._cache['profile']['enable_command']:
|
| - self._ClearPowerData()
|
| - self._HardwareSetCharging(enabled)
|
| - else:
|
| - logging.info('Unable to disable charging via hardware. '
|
| - 'Falling back to software disabling.')
|
| - self.DisableBatteryUpdates()
|
| -
|
| - def _HardwareSetCharging(self, enabled, timeout=None, retries=None):
|
| - """Enables or disables charging on the device.
|
| -
|
| - Args:
|
| - enabled: A boolean indicating whether charging should be enabled or
|
| - disabled.
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| -
|
| - Raises:
|
| - device_errors.CommandFailedError: If method of disabling charging cannot
|
| - be determined.
|
| - """
|
| - self._DiscoverDeviceProfile()
|
| - if not self._cache['profile']['enable_command']:
|
| - raise device_errors.CommandFailedError(
|
| - 'Unable to find charging commands.')
|
| -
|
| - command = (self._cache['profile']['enable_command'] if enabled
|
| - else self._cache['profile']['disable_command'])
|
| -
|
| - def verify_charging():
|
| - return self.GetCharging() == enabled
|
| -
|
| - self._device.RunShellCommand(
|
| - command, check_return=True, as_root=True, large_output=True)
|
| - timeout_retry.WaitFor(verify_charging, wait_period=1)
|
| -
|
| - @contextlib.contextmanager
|
| - def PowerMeasurement(self, timeout=None, retries=None):
|
| - """Context manager that enables battery power collection.
|
| -
|
| - Once the with block is exited, charging is resumed. Will attempt to disable
|
| - charging at the hardware level, and if that fails will fall back to software
|
| - disabling of battery updates.
|
| -
|
| - Only for devices L and higher.
|
| -
|
| - Example usage:
|
| - with PowerMeasurement():
|
| - browser_actions()
|
| - get_power_data() # report usage within this block
|
| - after_measurements() # Anything that runs after power
|
| - # measurements are collected
|
| -
|
| - Args:
|
| - timeout: timeout in seconds
|
| - retries: number of retries
|
| - """
|
| - try:
|
| - self.SetCharging(False, timeout=timeout, retries=retries)
|
| - yield
|
| - finally:
|
| - self.SetCharging(True, timeout=timeout, retries=retries)
|
| -
|
| - def _ClearPowerData(self):
|
| - """Resets battery data and makes device appear like it is not
|
| - charging so that it will collect power data since last charge.
|
| -
|
| - Returns:
|
| - True if power data cleared.
|
| - False if power data clearing is not supported (pre-L)
|
| -
|
| - Raises:
|
| - device_errors.DeviceVersionError: If power clearing is supported,
|
| - but fails.
|
| - """
|
| - if self._device.build_version_sdk < version_codes.LOLLIPOP:
|
| - logging.warning('Dumpsys power data only available on 5.0 and above. '
|
| - 'Cannot clear power data.')
|
| - return False
|
| -
|
| - self._device.RunShellCommand(
|
| - ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True)
|
| - self._device.RunShellCommand(
|
| - ['dumpsys', 'battery', 'set', 'ac', '1'], check_return=True)
|
| - self._device.RunShellCommand(
|
| - ['dumpsys', 'batterystats', '--reset'], check_return=True)
|
| - battery_data = self._device.RunShellCommand(
|
| - ['dumpsys', 'batterystats', '--charged', '-c'],
|
| - check_return=True, large_output=True)
|
| - for line in battery_data:
|
| - l = line.split(',')
|
| - if (len(l) > _PWI_POWER_CONSUMPTION_INDEX and l[_ROW_TYPE_INDEX] == 'pwi'
|
| - and l[_PWI_POWER_CONSUMPTION_INDEX] != 0):
|
| - self._device.RunShellCommand(
|
| - ['dumpsys', 'battery', 'reset'], check_return=True)
|
| - raise device_errors.CommandFailedError(
|
| - 'Non-zero pmi value found after reset.')
|
| - self._device.RunShellCommand(
|
| - ['dumpsys', 'battery', 'reset'], check_return=True)
|
| - return True
|
| -
|
| - def _DiscoverDeviceProfile(self):
|
| - """Checks and caches device information.
|
| -
|
| - Returns:
|
| - True if profile is found, false otherwise.
|
| - """
|
| -
|
| - if 'profile' in self._cache:
|
| - return True
|
| - for profile in _DEVICE_PROFILES:
|
| - if self._device.product_model == profile['name']:
|
| - self._cache['profile'] = profile
|
| - return True
|
| - self._cache['profile'] = {
|
| - 'name': None,
|
| - 'witness_file': None,
|
| - 'enable_command': None,
|
| - 'disable_command': None,
|
| - 'charge_counter': None,
|
| - 'voltage': None,
|
| - 'current': None,
|
| - }
|
| - return False
|
|
|