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