blob: dcd2d299a415275ec52023344d95b160abc7aa1e [file] [log] [blame]
# Copyright 2014 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.
import atexit
import logging
from telemetry.internal.platform.power_monitor import android_power_monitor_base
def _ReenableChargingIfNeeded(battery):
if not battery.GetCharging():
battery.SetCharging(True)
class AndroidPowerMonitorController(
android_power_monitor_base.AndroidPowerMonitorBase):
"""
PowerMonitor that acts as facade for a list of PowerMonitor objects and uses
the first available one.
"""
def __init__(self, power_monitors, battery):
super(AndroidPowerMonitorController, self).__init__()
self._candidate_power_monitors = power_monitors
self._active_monitors = []
self._battery = battery
atexit.register(_ReenableChargingIfNeeded, self._battery)
def CanMonitorPower(self):
return any(m.CanMonitorPower() for m in self._candidate_power_monitors)
def StartMonitoringPower(self, browser):
# TODO(rnephew): re-add assert when crbug.com/553601 is solved and
# StopMonitoringPower is called in the correct place.
if self._active_monitors:
logging.warning('StopMonitoringPower() not called when expected. Last '
'results are likely not reported.')
self.StopMonitoringPower()
self._CheckStart()
self._ChargingOff(self._battery)
self._active_monitors = (
[m for m in self._candidate_power_monitors if m.CanMonitorPower()])
assert self._active_monitors, 'No available monitor.'
for monitor in self._active_monitors:
monitor.StartMonitoringPower(browser)
@staticmethod
def _MergePowerResults(combined_results, monitor_results):
"""
Merges monitor_results into combined_results and leaves monitor_results
values if there are merge conflicts.
"""
def _CheckDuplicateKeys(dict_one, dict_two, ignore_list=None):
for key in dict_one:
if key in dict_two and key not in ignore_list:
logging.warning('Found multiple instances of %s in power monitor '
'entries. Using newest one.', key)
# Sub level power entries.
for part in ['platform_info', 'component_utilization']:
if part in monitor_results:
_CheckDuplicateKeys(combined_results[part], monitor_results[part])
combined_results[part].update(monitor_results[part])
# Top level power entries.
platform_info = combined_results['platform_info'].copy()
comp_utilization = combined_results['component_utilization'].copy()
_CheckDuplicateKeys(
combined_results, monitor_results,
['identifier', 'platform_info', 'component_utilization'])
combined_results.update(monitor_results)
combined_results['platform_info'] = platform_info
combined_results['component_utilization'] = comp_utilization
def StopMonitoringPower(self):
self._CheckStop()
self._ChargingOn(self._battery)
try:
results = {'platform_info': {}, 'component_utilization': {}}
for monitor in self._active_monitors:
self._MergePowerResults(results, monitor.StopMonitoringPower())
return results
finally:
self._active_monitors = []
def _ChargingOff(self, battery):
battery.SetCharging(False)
def _ChargingOn(self, battery):
if battery.GetCharging():
logging.warning('Charging re-enabled during test.'
'Results may be inaccurate.')
battery.SetCharging(True)