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 < constants.ANDROID_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 GetPowerData(self, timeout=None, retries=None): """Get power data for device. Args: timeout: timeout in seconds retries: number of retries Returns: Dict of power data, keyed on package names. { 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) 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 differnt 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])) return { p: { 'uid': uid, 'data': pwi_entries[uid] } for p, uid in self._cache['uids'].iteritems() }
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 if (self._device.build_version_sdk < constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): raise device_errors.DeviceVersionError( 'Device must be L or higher.') 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', '--checkin'], check_return=True, large_output=True) ROW_TYPE_INDEX = 3 PWI_POWER_INDEX = 5 for line in battery_data: l = line.split(',') if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi' and l[PWI_POWER_INDEX] != 0): raise device_errors.CommandFailedError( 'Non-zero pmi value found after reset.') 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)
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() is True if (self._device.build_version_sdk < constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP): raise device_errors.DeviceVersionError( 'Device must be L or higher.') self._device.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True) timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)