Home | History | Annotate | Download | only in systrace
      1 # Copyright 2015 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 optparse
      6 import os
      7 import random
      8 import string
      9 import subprocess
     10 import sys
     11 
     12 from devil.android.constants import chrome
     13 
     14 class OptionParserIgnoreErrors(optparse.OptionParser):
     15   """Wrapper for OptionParser that ignores errors and produces no output."""
     16 
     17   def error(self, msg):
     18     pass
     19 
     20   def exit(self, status=0, msg=None):
     21     pass
     22 
     23   def print_usage(self, out_file=None):
     24     pass
     25 
     26   def print_help(self, out_file=None):
     27     pass
     28 
     29   def print_version(self, out_file=None):
     30     pass
     31 
     32 
     33 def add_adb_serial(adb_command, device_serial):
     34   """Add serial number to ADB shell command.
     35 
     36   ADB shell command is given as list, e.g.
     37   ['adb','shell','some_command','some_args'].
     38   This replaces it with:
     39   ['adb','shell',-s',device_serial,'some_command','some_args']
     40 
     41   Args:
     42      adb_command: ADB command list.
     43      device_serial: Device serial number.
     44 
     45   Returns:
     46      ADB command list with serial number added.
     47   """
     48   if device_serial is not None:
     49     adb_command.insert(1, device_serial)
     50     adb_command.insert(1, '-s')
     51 
     52 
     53 def construct_adb_shell_command(shell_args, device_serial):
     54   """Construct an ADB shell command with given device serial and arguments.
     55 
     56   Args:
     57      shell_args: array of arguments to pass to adb shell.
     58      device_serial: if not empty, will add the appropriate command-line
     59         parameters so that adb targets the given device.
     60   """
     61   adb_command = ['adb', 'shell', ' '.join(shell_args)]
     62   add_adb_serial(adb_command, device_serial)
     63   return adb_command
     64 
     65 
     66 def run_adb_command(adb_command):
     67   adb_output = []
     68   adb_return_code = 0
     69   try:
     70     adb_output = subprocess.check_output(adb_command, stderr=subprocess.STDOUT,
     71                                          shell=False, universal_newlines=True)
     72   except OSError as error:
     73     # This usually means that the adb executable was not found in the path.
     74     print >> sys.stderr, ('\nThe command "%s" failed with the following error:'
     75                           % ' '.join(adb_command))
     76     print >> sys.stderr, '    %s' % str(error)
     77     print >> sys.stderr, 'Is adb in your path?'
     78     adb_return_code = error.errno
     79     adb_output = error
     80   except subprocess.CalledProcessError as error:
     81     # The process exited with an error.
     82     adb_return_code = error.returncode
     83     adb_output = error.output
     84 
     85   return (adb_output, adb_return_code)
     86 
     87 
     88 def run_adb_shell(shell_args, device_serial):
     89   """Runs "adb shell" with the given arguments.
     90 
     91   Args:
     92     shell_args: array of arguments to pass to adb shell.
     93     device_serial: if not empty, will add the appropriate command-line
     94         parameters so that adb targets the given device.
     95   Returns:
     96     A tuple containing the adb output (stdout & stderr) and the return code
     97     from adb.  Will exit if adb fails to start.
     98   """
     99   adb_command = construct_adb_shell_command(shell_args, device_serial)
    100   return run_adb_command(adb_command)
    101 
    102 
    103 def get_device_sdk_version():
    104   """Uses adb to attempt to determine the SDK version of a running device."""
    105 
    106   getprop_args = ['getprop', 'ro.build.version.sdk']
    107 
    108   # get_device_sdk_version() is called before we even parse our command-line
    109   # args.  Therefore, parse just the device serial number part of the
    110   # command-line so we can send the adb command to the correct device.
    111   parser = OptionParserIgnoreErrors()
    112   parser.add_option('-e', '--serial', dest='device_serial', type='string')
    113   options, unused_args = parser.parse_args()  # pylint: disable=unused-variable
    114 
    115   success = False
    116 
    117   adb_output, adb_return_code = run_adb_shell(getprop_args,
    118                                               options.device_serial)
    119 
    120   if adb_return_code == 0:
    121     # ADB may print output other than the version number (e.g. it chould
    122     # print a message about starting the ADB server).
    123     # Break the ADB output into white-space delimited segments.
    124     parsed_output = str.split(adb_output)
    125     if parsed_output:
    126       # Assume that the version number is the last thing printed by ADB.
    127       version_string = parsed_output[-1]
    128       if version_string:
    129         try:
    130           # Try to convert the text into an integer.
    131           version = int(version_string)
    132         except ValueError:
    133           version = -1
    134         else:
    135           success = True
    136 
    137   if not success:
    138     sys.exit(1)
    139 
    140   return version
    141 
    142 
    143 def generate_random_filename_for_test():
    144   """Used for temporary files used in tests.
    145 
    146   Files created from 'NamedTemporaryFile' have inconsistent reuse support across
    147   platforms, so it's not guaranteed that they can be reopened. Since many tests
    148   communicate files via path, we typically use this method, as well as
    149   manual file removal."""
    150   name = ''.join(random.choice(string.ascii_uppercase +
    151               string.digits) for _ in range(10))
    152   return os.path.abspath(name)
    153 
    154 
    155 def get_supported_browsers():
    156   """Returns the package names of all supported browsers."""
    157   # Add aliases for backwards compatibility.
    158   supported_browsers = {
    159     'stable': chrome.PACKAGE_INFO['chrome_stable'],
    160     'beta': chrome.PACKAGE_INFO['chrome_beta'],
    161     'dev': chrome.PACKAGE_INFO['chrome_dev'],
    162     'build': chrome.PACKAGE_INFO['chrome'],
    163   }
    164   supported_browsers.update(chrome.PACKAGE_INFO)
    165   return supported_browsers
    166 
    167 
    168 def get_default_serial():
    169   if 'ANDROID_SERIAL' in os.environ:
    170     return os.environ['ANDROID_SERIAL']
    171   return None
    172 
    173 
    174 def get_main_options(parser):
    175   parser.add_option('-o', dest='output_file', help='write trace output to FILE',
    176                     default=None, metavar='FILE')
    177   parser.add_option('-t', '--time', dest='trace_time', type='int',
    178                     help='trace for N seconds', metavar='N')
    179   parser.add_option('-j', '--json', dest='write_json',
    180                     default=False, action='store_true',
    181                     help='write a JSON file')
    182   parser.add_option('--link-assets', dest='link_assets', default=False,
    183                     action='store_true',
    184                     help='(deprecated)')
    185   parser.add_option('--from-file', dest='from_file', action='store',
    186                     help='read the trace from a file (compressed) rather than'
    187                     'running a live trace')
    188   parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
    189                     type='string', help='(deprecated)')
    190   parser.add_option('-e', '--serial', dest='device_serial_number',
    191                     default=get_default_serial(),
    192                     type='string', help='adb device serial number')
    193   parser.add_option('--target', dest='target', default='android', type='string',
    194                     help='choose tracing target (android or linux)')
    195   parser.add_option('--timeout', dest='timeout', type='int',
    196                     help='timeout for start and stop tracing (seconds)')
    197   parser.add_option('--collection-timeout', dest='collection_timeout',
    198                     type='int', help='timeout for data collection (seconds)')
    199   parser.add_option('-a', '--app', dest='app_name', default=None,
    200                     type='string', action='store',
    201                     help='enable application-level tracing for '
    202                     'comma-separated list of app cmdlines')
    203   parser.add_option('-t', '--time', dest='trace_time', type='int',
    204                     help='trace for N seconds', metavar='N')
    205   parser.add_option('--target', dest='target', default='android',
    206                     type='string', help='choose tracing target (android or '
    207                     ' linux)')
    208   parser.add_option('-b', '--buf-size', dest='trace_buf_size',
    209                     type='int', help='use a trace buffer size '
    210                     ' of N KB', metavar='N')
    211   return parser
    212