1#!/usr/bin/python 2# 3# Copyright (c) 2012 The Chromium Authors. All rights reserved. 4# Use of this source code is governed by a BSD-style license that can be 5# found in the LICENSE file. 6 7""" adb_list_devices: list information about attached Android devices. """ 8 9 10import os 11import re 12import shlex 13import subprocess 14import sys 15 16# This file, which resides on every Android device, contains a great deal of 17# information about the device. 18INFO_FILE = '/system/build.prop' 19 20# Default set of properties to query about a device. 21DEFAULT_PROPS_TO_GET = ['ro.product.device', 'ro.build.version.release', 22 'ro.build.type'] 23 24 25def GetDeviceInfo(adb, serial, props_to_get): 26 """ Return a list of values (or "<Unknown>" if no value can be found) for the 27 given set of properties for the device with the given serial number. 28 29 adb: path to the ADB program. 30 serial: serial number of the target device. 31 props_to_get: list of strings indicating which properties to determine. 32 """ 33 device_proc = subprocess.Popen([adb, '-s', serial, 'shell', 'cat', 34 INFO_FILE], stdout=subprocess.PIPE) 35 code = device_proc.wait() 36 if code != 0: 37 raise Exception('Could not query device with serial number %s.' % serial) 38 output = device_proc.stdout.read() 39 device_info = [] 40 for prop in props_to_get: 41 # Find the property in the outputs 42 search_str = r'%s=(\S+)' % prop 43 match = re.search(search_str, output) 44 if not match: 45 value = '<Unknown>' 46 else: 47 value = match.group(1) 48 device_info.append(value) 49 return device_info 50 51 52def PrintPrettyTable(data, file=None): 53 """ Print out the given data in a nicely-spaced format. This function scans 54 the list multiple times and uses extra memory, so don't use it for big data 55 sets. 56 57 data: list of lists of strings, where each list represents a row of data. 58 This table is assumed to be rectangular; if the length of any list differs 59 some of the output may not get printed. 60 file: file-like object into which the table should be written. If none is 61 provided, the table is written to stdout. 62 """ 63 if not file: 64 file = sys.stdout 65 column_widths = [0 for length in data[0]] 66 for line in data: 67 column_widths = [max(longest_len, len(prop)) for \ 68 longest_len, prop in zip(column_widths, line)] 69 for line in data: 70 for prop, width in zip(line, column_widths): 71 file.write(prop.ljust(width + 1)) 72 file.write('\n') 73 74 75def FindADB(hint=None): 76 """ Attempt to find the ADB program using the following sequence of steps. 77 Returns the path to ADB if it can be found, or None otherwise. 78 1. If a hint was provided, is it a valid path to ADB? 79 2. Is ADB in PATH? 80 3. Is there an environment variable for ADB? 81 4. If the ANDROID_SDK_ROOT variable is set, try to find ADB in the SDK 82 directory. 83 84 hint: string indicating a possible path to ADB. 85 """ 86 # 1. If a hint was provided, does it point to ADB? 87 if hint: 88 if os.path.basename(hint) == 'adb': 89 adb = hint 90 else: 91 adb = os.path.join(hint, 'adb') 92 if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 93 return adb 94 95 # 2. Is 'adb' in our PATH? 96 adb = 'adb' 97 if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 98 return adb 99 100 # 3. Is there an environment variable for ADB? 101 try: 102 adb = os.environ.get('ADB') 103 if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 104 return adb 105 except: 106 pass 107 108 # 4. If ANDROID_SDK_ROOT is set, try to find ADB in the SDK directory. 109 try: 110 sdk_dir = os.environ.get('ANDROID_SDK_ROOT') 111 adb = os.path.join(sdk_dir, 'platform-tools', 'adb') 112 if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 113 return adb 114 except: 115 pass 116 return None 117 118 119def main(argv): 120 """ Print out information about connected Android devices. By default, print 121 the serial number, status, device name, OS version, and build type of each 122 device. If any arguments are supplied on the command line, print the serial 123 number and status for each device along with values for those arguments 124 interpreted as properties. 125 """ 126 if len(argv) > 1: 127 props_to_get = argv[1:] 128 else: 129 props_to_get = DEFAULT_PROPS_TO_GET 130 adb = FindADB() 131 if not adb: 132 raise Exception('Could not find ADB!') 133 proc = subprocess.Popen([adb, 'devices'], stdout=subprocess.PIPE) 134 code = proc.wait() 135 if code != 0: 136 raise Exception('Failure in ADB: could not find attached devices.') 137 header = ['Serial', 'Status'] 138 header.extend(props_to_get) 139 output_lines = [header] 140 for line in proc.stdout: 141 line = line.rstrip() 142 if line != 'List of devices attached' and line != '': 143 line_list = shlex.split(line) 144 serial = line_list[0] 145 status = line_list[1] 146 device_info = [serial, status] 147 device_info.extend(GetDeviceInfo(adb, serial, props_to_get)) 148 output_lines.append(device_info) 149 PrintPrettyTable(output_lines) 150 151 152if __name__ == '__main__': 153 sys.exit(main(sys.argv))