1# Copyright (c) 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 5import optparse 6import subprocess 7import sys 8 9 10class OptionParserIgnoreErrors(optparse.OptionParser): 11 """Wrapper for OptionParser that ignores errors and produces no output.""" 12 13 def error(self, msg): 14 pass 15 16 def exit(self): 17 pass 18 19 def print_usage(self): 20 pass 21 22 def print_help(self): 23 pass 24 25 def print_version(self): 26 pass 27 28 29def add_adb_serial(adb_command, device_serial): 30 if device_serial is not None: 31 adb_command.insert(1, device_serial) 32 adb_command.insert(1, '-s') 33 34 35def construct_adb_shell_command(shell_args, device_serial): 36 adb_command = ['adb', 'shell', ' '.join(shell_args)] 37 add_adb_serial(adb_command, device_serial) 38 return adb_command 39 40 41def run_adb_shell(shell_args, device_serial): 42 """Runs "adb shell" with the given arguments. 43 44 Args: 45 shell_args: array of arguments to pass to adb shell. 46 device_serial: if not empty, will add the appropriate command-line 47 parameters so that adb targets the given device. 48 Returns: 49 A tuple containing the adb output (stdout & stderr) and the return code 50 from adb. Will exit if adb fails to start. 51 """ 52 adb_command = construct_adb_shell_command(shell_args, device_serial) 53 54 adb_output = [] 55 adb_return_code = 0 56 try: 57 adb_output = subprocess.check_output(adb_command, stderr=subprocess.STDOUT, 58 shell=False, universal_newlines=True) 59 except OSError as error: 60 # This usually means that the adb executable was not found in the path. 61 print >> sys.stderr, ('\nThe command "%s" failed with the following error:' 62 % ' '.join(adb_command)) 63 print >> sys.stderr, ' %s\n' % str(error) 64 print >> sys.stderr, 'Is adb in your path?' 65 sys.exit(1) 66 except subprocess.CalledProcessError as error: 67 # The process exited with an error. 68 adb_return_code = error.returncode 69 adb_output = error.output 70 71 return (adb_output, adb_return_code) 72 73 74def get_device_sdk_version(): 75 """Uses adb to attempt to determine the SDK version of a running device.""" 76 77 getprop_args = ['getprop', 'ro.build.version.sdk'] 78 79 # get_device_sdk_version() is called before we even parse our command-line 80 # args. Therefore, parse just the device serial number part of the 81 # command-line so we can send the adb command to the correct device. 82 parser = OptionParserIgnoreErrors() 83 parser.add_option('-e', '--serial', dest='device_serial', type='string') 84 options, unused_args = parser.parse_args() 85 86 success = False 87 88 adb_output, adb_return_code = run_adb_shell(getprop_args, 89 options.device_serial) 90 91 if adb_return_code == 0: 92 # ADB may print output other than the version number (e.g. it chould 93 # print a message about starting the ADB server). 94 # Break the ADB output into white-space delimited segments. 95 parsed_output = str.split(adb_output) 96 if parsed_output: 97 # Assume that the version number is the last thing printed by ADB. 98 version_string = parsed_output[-1] 99 if version_string: 100 try: 101 # Try to convert the text into an integer. 102 version = int(version_string) 103 except ValueError: 104 version = -1 105 else: 106 success = True 107 108 if not success: 109 print >> sys.stderr, ( 110 '\nThe command "%s" failed with the following message:' 111 % ' '.join(getprop_args)) 112 print >> sys.stderr, adb_output 113 sys.exit(1) 114 115 return version 116