Home | History | Annotate | Download | only in tracing_agents
      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 
      5 import atexit
      6 import logging
      7 import optparse
      8 import py_utils
      9 
     10 from battor import battor_wrapper
     11 from devil.android import battery_utils
     12 from devil.android import device_utils
     13 from devil.utils import battor_device_mapping
     14 from devil.utils import find_usb_devices
     15 from py_trace_event import trace_time
     16 from systrace import trace_result
     17 from systrace import tracing_agents
     18 
     19 
     20 def try_create_agent(config):
     21   if config.from_file is not None:
     22     return None
     23   if config.battor:
     24     return BattOrTraceAgent()
     25   return None
     26 
     27 
     28 class BattOrConfig(tracing_agents.TracingConfig):
     29   def __init__(self, battor_categories, serial_map, battor_path,
     30                battor, target, from_file, device_serial_number):
     31     tracing_agents.TracingConfig.__init__(self)
     32     self.battor_categories = battor_categories
     33     self.serial_map = serial_map
     34     self.battor_path = battor_path
     35     self.battor = battor
     36     self.target = target
     37     self.from_file = from_file
     38     self.device_serial_number = device_serial_number
     39 
     40 
     41 def add_options(parser):
     42   options = optparse.OptionGroup(parser, 'BattOr trace options')
     43   options.add_option('--battor-categories', dest='battor_categories',
     44                      help='Select battor categories with a comma-delimited '
     45                      'list, e.g. --battor-categories=cat1,cat2,cat3')
     46   options.add_option('--serial-map', dest='serial_map',
     47                     default='serial_map.json',
     48                     help='File containing pregenerated map of phone serial '
     49                     'numbers to BattOr serial numbers.')
     50   options.add_option('--battor-path', dest='battor_path', default=None,
     51                     type='string', help='specify a BattOr path to use')
     52   options.add_option('--battor', dest='battor', default=False,
     53                     action='store_true', help='Use the BattOr tracing agent.')
     54   return options
     55 
     56 def get_config(options):
     57   return BattOrConfig(
     58       options.battor_categories, options.serial_map, options.battor_path,
     59       options.battor, options.target, options.from_file,
     60       options.device_serial_number)
     61 
     62 def _reenable_charging_if_needed(battery):
     63   if not battery.GetCharging():
     64     battery.SetCharging(True)
     65   logging.info('Charging status checked at exit.')
     66 
     67 
     68 class BattOrTraceAgent(tracing_agents.TracingAgent):
     69   # Class representing tracing agent that gets data from a BattOr.
     70   # BattOrs are high-frequency power monitors used for battery testing.
     71   def __init__(self):
     72     super(BattOrTraceAgent, self).__init__()
     73     self._collection_process = None
     74     self._recording_error = None
     75     self._battor_wrapper = None
     76     self._battery_utils = None
     77 
     78   @staticmethod
     79   def _FindBattOrPath(config):
     80     device_tree = find_usb_devices.GetBusNumberToDeviceTreeMap()
     81     battors = battor_device_mapping.GetBattOrList(device_tree)
     82     battor_path = config.battor_path
     83     if not config.battor_path and not config.serial_map:
     84       assert len(battors) == 1, ('Must specify BattOr path if there is not '
     85                                  'exactly one')
     86       battor_path = battors[0]
     87     return battor_path
     88 
     89   @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
     90   def StartAgentTracing(self, config, timeout=None):
     91     """Starts tracing.
     92 
     93     Args:
     94         config: Tracing config.
     95 
     96     Raises:
     97         RuntimeError: If trace already in progress.
     98         AssertionError: If There is no BattOr path given and more
     99             than one BattOr is attached.
    100     """
    101     battor_path = self._FindBattOrPath(config)
    102     self._battor_wrapper = battor_wrapper.BattOrWrapper(
    103         target_platform=config.target,
    104         android_device=config.device_serial_number,
    105         battor_path=battor_path,
    106         battor_map_file=config.serial_map)
    107 
    108     dev_utils = device_utils.DeviceUtils(config.device_serial_number)
    109     self._battery_utils = battery_utils.BatteryUtils(dev_utils)
    110     self._battery_utils.SetCharging(False)
    111     atexit.register(_reenable_charging_if_needed, self._battery_utils)
    112     self._battor_wrapper.StartShell()
    113     self._battor_wrapper.StartTracing()
    114     return True
    115 
    116   @py_utils.Timeout(tracing_agents.START_STOP_TIMEOUT)
    117   def StopAgentTracing(self, timeout=None):
    118     """Stops tracing and collects the results asynchronously.
    119 
    120     Creates a new process that stops the tracing and collects the results.
    121     Returns immediately after the process is created (does not wait for
    122     trace results to be collected).
    123     """
    124     self._battor_wrapper.StopTracing()
    125     self._battery_utils.SetCharging(True)
    126     return True
    127 
    128   def SupportsExplicitClockSync(self):
    129     """Returns whether this function supports explicit clock sync."""
    130     return self._battor_wrapper.SupportsExplicitClockSync()
    131 
    132   def RecordClockSyncMarker(self, sync_id, did_record_sync_marker_callback):
    133     """Records a clock sync marker.
    134 
    135     Args:
    136         sync_id: ID string for clock sync marker.
    137         did_record_sync_marker_callback: Callback function to call after
    138         the clock sync marker is recorded.
    139     """
    140     ts = trace_time.Now()
    141     self._battor_wrapper.RecordClockSyncMarker(sync_id)
    142     did_record_sync_marker_callback(ts, sync_id)
    143 
    144   @py_utils.Timeout(tracing_agents.GET_RESULTS_TIMEOUT)
    145   def GetResults(self, timeout=None):
    146     """Waits until data collection is completed and get the trace data.
    147 
    148     The trace data is the data that comes out of the BattOr, and is in the
    149     format with the following lines:
    150 
    151     time current voltage <sync_id>
    152 
    153     where the sync_id is only there if a clock sync marker was recorded
    154     during that sample.
    155 
    156     time = time since start of trace (ms)
    157     current = current through battery (mA) - this can be negative if the
    158         battery is charging
    159     voltage = voltage of battery (mV)
    160 
    161     Returns:
    162       The trace data.
    163     """
    164     return trace_result.TraceResult(
    165         'powerTraceAsString', self._battor_wrapper.CollectTraceData())
    166