1 # Copyright 2014 The Chromium Authors. All rights reserved. 2 # Use of this source code is governed by a BSD-style license that can be 3 # found in the LICENSE file. 4 5 import csv 6 import logging 7 8 from telemetry.internal.platform.power_monitor import android_power_monitor_base 9 10 class DumpsysPowerMonitor(android_power_monitor_base.AndroidPowerMonitorBase): 11 """PowerMonitor that relies on the dumpsys batterystats to monitor the power 12 consumption of a single android application. This measure uses a heuristic 13 and is the same information end-users see with the battery application. 14 Available on Android L and higher releases. 15 """ 16 def __init__(self, battery, platform_backend): 17 """Constructor. 18 19 Args: 20 battery: A BatteryUtil instance. 21 platform_backend: A LinuxBasedPlatformBackend instance. 22 """ 23 super(DumpsysPowerMonitor, self).__init__() 24 self._battery = battery 25 self._browser = None 26 self._platform = platform_backend 27 28 def CanMonitorPower(self): 29 result = self._platform.device.RunShellCommand( 30 ['dumpsys', 'batterystats', '-c'], check_return=True) 31 DUMP_VERSION_INDEX = 0 32 # Dumpsys power data is present in dumpsys versions 8 and 9 33 # which is found on L+ devices. 34 return (csv.reader(result).next()[DUMP_VERSION_INDEX] in ['8', '9']) 35 36 def StartMonitoringPower(self, browser): 37 self._CheckStart() 38 assert browser 39 self._browser = browser 40 # Disable the charging of the device over USB. This is necessary because the 41 # device only collects information about power usage when the device is not 42 # charging. 43 44 def StopMonitoringPower(self): 45 self._CheckStop() 46 assert self._browser 47 package = self._browser._browser_backend.package 48 self._browser = None 49 50 voltage = self._ParseVoltage(self._battery.GetBatteryInfo().get('voltage')) 51 power_data = self._battery.GetPowerData() 52 power_results = self.ProcessPowerData(power_data, voltage, package) 53 self._LogPowerAnomalies(power_results, package) 54 return power_results 55 56 @staticmethod 57 def ProcessPowerData(power_data, voltage, package): 58 package_power_data = power_data['per_package'].get(package) 59 if not package_power_data: 60 logging.warning('No power data for %s in dumpsys output.' % package) 61 package_power = 0 62 else: 63 package_power = sum(package_power_data['data']) 64 65 return {'identifier': 'dumpsys', 66 'power_samples_mw': [], 67 'energy_consumption_mwh': power_data['system_total'] * voltage, 68 'application_energy_consumption_mwh': package_power * voltage} 69