adb_list_devices.py revision dcdd57faf02fb4fd23bb8265392b9c22e068907e
151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger#!/usr/bin/python 251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# 351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# Copyright (c) 2012 The Chromium Authors. All rights reserved. 451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# Use of this source code is governed by a BSD-style license that can be 551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# found in the LICENSE file. 651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger""" adb_list_devices: list information about attached Android devices. """ 851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 9ac8a0ea174c9a9197c1ab8b5d57fcc0e5e0505b1Android Chromium Automerger 10ac8a0ea174c9a9197c1ab8b5d57fcc0e5e0505b1Android Chromium Automergerimport os 11ac8a0ea174c9a9197c1ab8b5d57fcc0e5e0505b1Android Chromium Automergerimport re 1251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerimport shlex 1351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerimport subprocess 1451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerimport sys 1551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 1651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# This file, which resides on every Android device, contains a great deal of 1751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# information about the device. 1851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium AutomergerINFO_FILE = '/system/build.prop' 1951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 2051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger# Default set of properties to query about a device. 2151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium AutomergerDEFAULT_PROPS_TO_GET = ['ro.product.device', 'ro.build.version.release', 2251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 'ro.build.type'] 2351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 2451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 2551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerdef GetDeviceInfo(adb, serial, props_to_get): 2651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ Return a list of values (or "<Unknown>" if no value can be found) for the 2751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger given set of properties for the device with the given serial number. 2851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 2951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger adb: path to the ADB program. 3051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger serial: serial number of the target device. 3151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger props_to_get: list of strings indicating which properties to determine. 3251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ 3351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger device_proc = subprocess.Popen([adb, '-s', serial, 'shell', 'cat', 3451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger INFO_FILE], stdout=subprocess.PIPE) 3551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger code = device_proc.wait() 3651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if code != 0: 3751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger raise Exception('Could not query device with serial number %s.' % serial) 3851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger output = device_proc.stdout.read() 3951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger device_info = [] 40b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger for prop in props_to_get: 4151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger # Find the property in the outputs 4251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger search_str = r'%s=(\S+)' % prop 43b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger match = re.search(search_str, output) 44b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger if not match: 45b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger value = '<Unknown>' 46b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger else: 47b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger value = match.group(1) 48b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger device_info.append(value) 4951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger return device_info 5051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 5151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 5251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerdef PrintPrettyTable(data, file=None): 5351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ Print out the given data in a nicely-spaced format. This function scans 5451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger the list multiple times and uses extra memory, so don't use it for big data 5551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger sets. 5651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 5751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger data: list of lists of strings, where each list represents a row of data. 5851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger This table is assumed to be rectangular; if the length of any list differs 5951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger some of the output may not get printed. 6051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger file: file-like object into which the table should be written. If none is 6151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger provided, the table is written to stdout. 6251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ 6351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if not file: 6451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger file = sys.stdout 6551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger column_widths = [0 for length in data[0]] 6651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger for line in data: 6751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger column_widths = [max(longest_len, len(prop)) for \ 6851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger longest_len, prop in zip(column_widths, line)] 6951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger for line in data: 7051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger for prop, width in zip(line, column_widths): 7151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger file.write(prop.ljust(width + 1)) 7251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger file.write('\n') 7351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 7451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 7551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerdef FindADB(hint=None): 7651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ Attempt to find the ADB program using the following sequence of steps. 7751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger Returns the path to ADB if it can be found, or None otherwise. 7851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 1. If a hint was provided, is it a valid path to ADB? 7951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 2. Is ADB in PATH? 8051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 3. Is there an environment variable for ADB? 8151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 4. If the ANDROID_SDK_ROOT variable is set, try to find ADB in the SDK 8251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger directory. 83f1a314b2eb3a83facfd86d292b05f37d77381cacAndroid Chromium Automerger 8451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger hint: string indicating a possible path to ADB. 8551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ 8651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger # 1. If a hint was provided, does it point to ADB? 8751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if hint: 8851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if os.path.basename(hint) == 'adb': 8951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger adb = hint 9051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger else: 91deafe80bd7094c268e81edcea7015bc08535b5deTorne (Richard Coles) adb = os.path.join(hint, 'adb') 92deafe80bd7094c268e81edcea7015bc08535b5deTorne (Richard Coles) if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 93deafe80bd7094c268e81edcea7015bc08535b5deTorne (Richard Coles) return adb 94deafe80bd7094c268e81edcea7015bc08535b5deTorne (Richard Coles) 9580bc6f5eb8065006f1997be0fbf429efbb748df8Torne (Richard Coles) # 2. Is 'adb' in our PATH? 9651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger adb = 'adb' 9751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 9851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger return adb 9951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 10051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger # 3. Is there an environment variable for ADB? 10151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger try: 10251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger adb = os.environ.get('ADB') 10351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 10451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger return adb 10551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger except: 10651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger pass 10751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 10851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger # 4. If ANDROID_SDK_ROOT is set, try to find ADB in the SDK directory. 10951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger try: 110b68b69450259b5e317e989b0331c1ac97af9bb9cAndroid Chromium Automerger sdk_dir = os.environ.get('ANDROID_SDK_ROOT') 11151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger adb = os.path.join(sdk_dir, 'platform-tools', 'adb') 11251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: 11351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger return adb 11451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger except: 11551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger pass 11651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger return None 11751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 11851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 11951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerdef main(argv): 12051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ Print out information about connected Android devices. By default, print 12151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger the serial number, status, device name, OS version, and build type of each 12251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger device. If any arguments are supplied on the command line, print the serial 12351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger number and status for each device along with values for those arguments 12451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger interpreted as properties. 12551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger """ 12651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if len(argv) > 1: 12751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger props_to_get = argv[1:] 12851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger else: 12951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger props_to_get = DEFAULT_PROPS_TO_GET 13051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger adb = FindADB() 13151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if not adb: 13251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger raise Exception('Could not find ADB!') 13351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger proc = subprocess.Popen([adb, 'devices'], stdout=subprocess.PIPE) 13451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger code = proc.wait() 13551219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger if code != 0: 13651219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger raise Exception('Failure in ADB: could not find attached devices.') 13751219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger header = ['Serial', 'Status'] 13851219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger header.extend(props_to_get) 13951219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger output_lines = [header] 14051219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger for line in proc.stdout: 14151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger line = line.rstrip() 142b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger if line != 'List of devices attached' and line != '': 14351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger line_list = shlex.split(line) 14451219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger serial = line_list[0] 145b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger status = line_list[1] 146b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger device_info = [serial, status] 147b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger device_info.extend(GetDeviceInfo(adb, serial, props_to_get)) 148b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger output_lines.append(device_info) 149b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger PrintPrettyTable(output_lines) 150b43e9a6c0ced53d64d0de10dc608d8ea5fba5acaAndroid Chromium Automerger 15151219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger 15251219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automergerif __name__ == '__main__': 15351219f8e546520a70f8f21a73e631c9bf0ac738dAndroid Chromium Automerger sys.exit(main(sys.argv))