1# Copyright 2016 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 logging 6 7from battor import battor_error 8from battor import battor_wrapper 9from py_utils import cloud_storage 10from devil.android import battery_utils 11from py_trace_event import trace_time 12from telemetry.internal.platform import tracing_agent 13from telemetry.internal.util import atexit_with_log 14from tracing.trace_data import trace_data 15 16 17def _ReenableChargingIfNeeded(battery): 18 if not battery.GetCharging(): 19 battery.SetCharging(True) 20 logging.info('Charging status checked at exit.') 21 22 23class BattOrTracingAgent(tracing_agent.TracingAgent): 24 """A tracing agent for getting power data from a BattOr device. 25 26 BattOrTracingAgent allows Telemetry to issue high-level tracing commands 27 (StartTracing, StopTracing, RecordClockSyncMarker) to BattOrs, which are 28 high-frequency power monitors used for battery testing. 29 """ 30 31 def __init__(self, platform_backend): 32 super(BattOrTracingAgent, self).__init__(platform_backend) 33 self._platform_backend = platform_backend 34 android_device = ( 35 platform_backend.device if platform_backend.GetOSName() == 'android' 36 else None) 37 self._battery = ( 38 battery_utils.BatteryUtils(platform_backend.device) 39 if platform_backend.GetOSName() == 'android' else None) 40 self._battor = battor_wrapper.BattOrWrapper( 41 platform_backend.GetOSName(), android_device=android_device, 42 serial_log_bucket=cloud_storage.TELEMETRY_OUTPUT) 43 44 @classmethod 45 def IsSupported(cls, platform_backend): 46 """Returns True if BattOr tracing is available.""" 47 if platform_backend.GetOSName() == 'android': 48 # TODO(rnephew): When we pass BattOr device map into Telemetry, change 49 # this to reflect that. 50 return battor_wrapper.IsBattOrConnected( 51 'android', android_device=platform_backend.device) 52 return battor_wrapper.IsBattOrConnected(platform_backend.GetOSName()) 53 54 def StartAgentTracing(self, config, timeout): 55 """Start tracing on the BattOr. 56 57 Args: 58 config: A TracingConfig instance. 59 timeout: number of seconds that this tracing agent should try to start 60 tracing until timing out. 61 62 Returns: 63 True if the tracing agent started successfully. 64 """ 65 if not config.enable_battor_trace: 66 return False 67 try: 68 if self._battery: 69 self._battery.SetCharging(False) 70 atexit_with_log.Register(_ReenableChargingIfNeeded, self._battery) 71 72 self._battor.StartShell() 73 self._battor.StartTracing() 74 return True 75 except battor_error.BattOrError: 76 if self._battery: 77 self._battery.SetCharging(True) 78 raise 79 80 def StopAgentTracing(self): 81 """Stops tracing on the BattOr.""" 82 try: 83 self._battor.StopTracing() 84 finally: 85 if self._battery: 86 self._battery.SetCharging(True) 87 88 def SupportsExplicitClockSync(self): 89 return self._battor.SupportsExplicitClockSync() 90 91 def RecordClockSyncMarker(self, sync_id, 92 record_controller_clock_sync_marker_callback): 93 """Records a clock sync marker in the BattOr trace. 94 95 Args: 96 sync_id: Unique id for sync event. 97 record_controller_clock_sync_marker_callback: Function that takes a sync 98 ID and a timestamp as arguments. This function typically will record the 99 tracing controller clock sync marker. 100 """ 101 timestamp = trace_time.Now() 102 try: 103 self._battor.RecordClockSyncMarker(sync_id) 104 except battor_error.BattOrError: 105 logging.critical( 106 'Error while clock syncing with BattOr. Killing BattOr shell.') 107 self._battor.KillBattOrShell() 108 raise 109 record_controller_clock_sync_marker_callback(sync_id, timestamp) 110 111 def CollectAgentTraceData(self, trace_data_builder, timeout=None): 112 data = self._battor.CollectTraceData(timeout=timeout) 113 trace_data_builder.AddTraceFor(trace_data.BATTOR_TRACE_PART, data) 114