# Copyright (c) 2015 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 optparse import subprocess import sys class OptionParserIgnoreErrors(optparse.OptionParser): """Wrapper for OptionParser that ignores errors and produces no output.""" def error(self, msg): pass def exit(self): pass def print_usage(self): pass def print_help(self): pass def print_version(self): pass def add_adb_serial(adb_command, device_serial): if device_serial is not None: adb_command.insert(1, device_serial) adb_command.insert(1, '-s') def construct_adb_shell_command(shell_args, device_serial): adb_command = ['adb', 'shell', ' '.join(shell_args)] add_adb_serial(adb_command, device_serial) return adb_command def run_adb_shell(shell_args, device_serial): """Runs "adb shell" with the given arguments. Args: shell_args: array of arguments to pass to adb shell. device_serial: if not empty, will add the appropriate command-line parameters so that adb targets the given device. Returns: A tuple containing the adb output (stdout & stderr) and the return code from adb. Will exit if adb fails to start. """ adb_command = construct_adb_shell_command(shell_args, device_serial) adb_output = [] adb_return_code = 0 try: adb_output = subprocess.check_output(adb_command, stderr=subprocess.STDOUT, shell=False, universal_newlines=True) except OSError as error: # This usually means that the adb executable was not found in the path. print >> sys.stderr, ('\nThe command "%s" failed with the following error:' % ' '.join(adb_command)) print >> sys.stderr, ' %s\n' % str(error) print >> sys.stderr, 'Is adb in your path?' sys.exit(1) except subprocess.CalledProcessError as error: # The process exited with an error. adb_return_code = error.returncode adb_output = error.output return (adb_output, adb_return_code) def get_device_sdk_version(): """Uses adb to attempt to determine the SDK version of a running device.""" getprop_args = ['getprop', 'ro.build.version.sdk'] # get_device_sdk_version() is called before we even parse our command-line # args. Therefore, parse just the device serial number part of the # command-line so we can send the adb command to the correct device. parser = OptionParserIgnoreErrors() parser.add_option('-e', '--serial', dest='device_serial', type='string') options, unused_args = parser.parse_args() success = False adb_output, adb_return_code = run_adb_shell(getprop_args, options.device_serial) if adb_return_code == 0: # ADB may print output other than the version number (e.g. it chould # print a message about starting the ADB server). # Break the ADB output into white-space delimited segments. parsed_output = str.split(adb_output) if parsed_output: # Assume that the version number is the last thing printed by ADB. version_string = parsed_output[-1] if version_string: try: # Try to convert the text into an integer. version = int(version_string) except ValueError: version = -1 else: success = True if not success: print >> sys.stderr, ( '\nThe command "%s" failed with the following message:' % ' '.join(getprop_args)) print >> sys.stderr, adb_output sys.exit(1) return version