• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
5from telemetry.internal.util import atexit_with_log
6import logging
7
8from telemetry.internal.platform.power_monitor import android_power_monitor_base
9
10def _ReenableChargingIfNeeded(battery):
11  if not battery.GetCharging():
12    battery.SetCharging(True)
13  logging.info('Charging status checked at exit.')
14
15class AndroidPowerMonitorController(
16    android_power_monitor_base.AndroidPowerMonitorBase):
17  """
18  PowerMonitor that acts as facade for a list of PowerMonitor objects and uses
19  the first available one.
20  """
21  def __init__(self, power_monitors, battery):
22    super(AndroidPowerMonitorController, self).__init__()
23    self._candidate_power_monitors = power_monitors
24    self._active_monitors = []
25    self._battery = battery
26    atexit_with_log.Register(_ReenableChargingIfNeeded, self._battery)
27
28  def CanMonitorPower(self):
29    return any(m.CanMonitorPower() for m in self._candidate_power_monitors)
30
31  def StartMonitoringPower(self, browser):
32    # TODO(rnephew): re-add assert when crbug.com/553601 is solved and
33    # StopMonitoringPower is called in the correct place.
34    if self._active_monitors:
35      logging.warning('StopMonitoringPower() not called when expected. Last '
36                      'results are likely not reported.')
37      self.StopMonitoringPower()
38    self._CheckStart()
39    self._ChargingOff(self._battery)
40    self._active_monitors = (
41        [m for m in self._candidate_power_monitors if m.CanMonitorPower()])
42    assert self._active_monitors, 'No available monitor.'
43    for monitor in self._active_monitors:
44      monitor.StartMonitoringPower(browser)
45
46  @staticmethod
47  def _MergePowerResults(combined_results, monitor_results):
48    """
49    Merges monitor_results into combined_results and leaves monitor_results
50    values if there are merge conflicts.
51    """
52    def _CheckDuplicateKeys(dict_one, dict_two, ignore_list=None):
53      for key in dict_one:
54        if key in dict_two and key not in ignore_list:
55          logging.warning('Found multiple instances of %s in power monitor '
56                          'entries. Using newest one.', key)
57    # Sub level power entries.
58    for part in ['platform_info', 'component_utilization']:
59      if part in monitor_results:
60        _CheckDuplicateKeys(combined_results[part], monitor_results[part])
61        combined_results[part].update(monitor_results[part])
62
63    # Top level power entries.
64    platform_info = combined_results['platform_info'].copy()
65    comp_utilization = combined_results['component_utilization'].copy()
66    _CheckDuplicateKeys(
67        combined_results, monitor_results,
68        ['identifier', 'platform_info', 'component_utilization'])
69    combined_results.update(monitor_results)
70    combined_results['platform_info'] = platform_info
71    combined_results['component_utilization'] = comp_utilization
72
73  def StopMonitoringPower(self):
74    self._CheckStop()
75    self._ChargingOn(self._battery)
76    try:
77      results = {'platform_info': {}, 'component_utilization': {}}
78      for monitor in self._active_monitors:
79        self._MergePowerResults(results, monitor.StopMonitoringPower())
80      return results
81    finally:
82      self._active_monitors = []
83
84  def _ChargingOff(self, battery):
85    battery.SetCharging(False)
86
87  def _ChargingOn(self, battery):
88    if battery.GetCharging():
89      logging.warning('Charging re-enabled during test.'
90                      'Results may be inaccurate.')
91    battery.SetCharging(True)
92