| # 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 |