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
5import csv
6import logging
7
8from telemetry.internal.platform.power_monitor import android_power_monitor_base
9
10class 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.RunCommand('dumpsys batterystats -c')
30    DUMP_VERSION_INDEX = 0
31    # Dumpsys power data is present in dumpsys versions 8 and 9
32    # which is found on L+ devices.
33    return (csv.reader(result).next()[DUMP_VERSION_INDEX] in ['8', '9'])
34
35  def StartMonitoringPower(self, browser):
36    self._CheckStart()
37    assert browser
38    self._browser = browser
39    # Disable the charging of the device over USB. This is necessary because the
40    # device only collects information about power usage when the device is not
41    # charging.
42
43  def StopMonitoringPower(self):
44    self._CheckStop()
45    assert self._browser
46    package = self._browser._browser_backend.package
47    self._browser = None
48
49    voltage = self._ParseVoltage(self._battery.GetBatteryInfo().get('voltage'))
50    power_data = self._battery.GetPowerData()
51    power_results = self.ProcessPowerData(power_data, voltage, package)
52    self._LogPowerAnomalies(power_results, package)
53    return power_results
54
55  @staticmethod
56  def ProcessPowerData(power_data, voltage, package):
57    package_power_data = power_data['per_package'].get(package)
58    if not package_power_data:
59      logging.warning('No power data for %s in dumpsys output.' % package)
60      package_power = 0
61    else:
62      package_power = sum(package_power_data['data'])
63
64    return {'identifier': 'dumpsys',
65            'power_samples_mw': [],
66            'energy_consumption_mwh': power_data['system_total'] * voltage,
67            'application_energy_consumption_mwh': package_power * voltage}
68