| #!/usr/bin/python | |
| # | |
| # Copyright (c) 2012 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. | |
| """ adb_list_devices: list information about attached Android devices. """ | |
| import os | |
| import re | |
| import shlex | |
| import subprocess | |
| import sys | |
| # This file, which resides on every Android device, contains a great deal of | |
| # information about the device. | |
| INFO_FILE = '/system/build.prop' | |
| # Default set of properties to query about a device. | |
| DEFAULT_PROPS_TO_GET = ['ro.product.device', 'ro.build.version.release', | |
| 'ro.build.type'] | |
| def GetDeviceInfo(adb, serial, props_to_get): | |
| """ Return a list of values (or "<Unknown>" if no value can be found) for the | |
| given set of properties for the device with the given serial number. | |
| adb: path to the ADB program. | |
| serial: serial number of the target device. | |
| props_to_get: list of strings indicating which properties to determine. | |
| """ | |
| device_proc = subprocess.Popen([adb, '-s', serial, 'shell', 'cat', | |
| INFO_FILE], stdout=subprocess.PIPE) | |
| code = device_proc.wait() | |
| if code != 0: | |
| raise Exception('Could not query device with serial number %s.' % serial) | |
| output = device_proc.stdout.read() | |
| device_info = [] | |
| for prop in props_to_get: | |
| # Find the property in the outputs | |
| search_str = r'%s=(\S+)' % prop | |
| match = re.search(search_str, output) | |
| if not match: | |
| value = '<Unknown>' | |
| else: | |
| value = match.group(1) | |
| device_info.append(value) | |
| return device_info | |
| def PrintPrettyTable(data, file=None): | |
| """ Print out the given data in a nicely-spaced format. This function scans | |
| the list multiple times and uses extra memory, so don't use it for big data | |
| sets. | |
| data: list of lists of strings, where each list represents a row of data. | |
| This table is assumed to be rectangular; if the length of any list differs | |
| some of the output may not get printed. | |
| file: file-like object into which the table should be written. If none is | |
| provided, the table is written to stdout. | |
| """ | |
| if not file: | |
| file = sys.stdout | |
| column_widths = [0 for length in data[0]] | |
| for line in data: | |
| column_widths = [max(longest_len, len(prop)) for \ | |
| longest_len, prop in zip(column_widths, line)] | |
| for line in data: | |
| for prop, width in zip(line, column_widths): | |
| file.write(prop.ljust(width + 1)) | |
| file.write('\n') | |
| def FindADB(hint=None): | |
| """ Attempt to find the ADB program using the following sequence of steps. | |
| Returns the path to ADB if it can be found, or None otherwise. | |
| 1. If a hint was provided, is it a valid path to ADB? | |
| 2. Is ADB in PATH? | |
| 3. Is there an environment variable for ADB? | |
| 4. If the ANDROID_SDK_ROOT variable is set, try to find ADB in the SDK | |
| directory. | |
| hint: string indicating a possible path to ADB. | |
| """ | |
| # 1. If a hint was provided, does it point to ADB? | |
| if hint: | |
| if os.path.basename(hint) == 'adb': | |
| adb = hint | |
| else: | |
| adb = os.path.join(hint, 'adb') | |
| if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: | |
| return adb | |
| # 2. Is 'adb' in our PATH? | |
| adb = 'adb' | |
| if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: | |
| return adb | |
| # 3. Is there an environment variable for ADB? | |
| try: | |
| adb = os.environ.get('ADB') | |
| if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: | |
| return adb | |
| except: | |
| pass | |
| # 4. If ANDROID_SDK_ROOT is set, try to find ADB in the SDK directory. | |
| try: | |
| sdk_dir = os.environ.get('ANDROID_SDK_ROOT') | |
| adb = os.path.join(sdk_dir, 'platform-tools', 'adb') | |
| if subprocess.Popen([adb, 'version'], stdout=subprocess.PIPE).wait() == 0: | |
| return adb | |
| except: | |
| pass | |
| return None | |
| def main(argv): | |
| """ Print out information about connected Android devices. By default, print | |
| the serial number, status, device name, OS version, and build type of each | |
| device. If any arguments are supplied on the command line, print the serial | |
| number and status for each device along with values for those arguments | |
| interpreted as properties. | |
| """ | |
| if len(argv) > 1: | |
| props_to_get = argv[1:] | |
| else: | |
| props_to_get = DEFAULT_PROPS_TO_GET | |
| adb = FindADB() | |
| if not adb: | |
| raise Exception('Could not find ADB!') | |
| proc = subprocess.Popen([adb, 'devices'], stdout=subprocess.PIPE) | |
| code = proc.wait() | |
| if code != 0: | |
| raise Exception('Failure in ADB: could not find attached devices.') | |
| header = ['Serial', 'Status'] | |
| header.extend(props_to_get) | |
| output_lines = [header] | |
| for line in proc.stdout: | |
| line = line.rstrip() | |
| if line != 'List of devices attached' and line != '': | |
| line_list = shlex.split(line) | |
| serial = line_list[0] | |
| status = line_list[1] | |
| device_info = [serial, status] | |
| device_info.extend(GetDeviceInfo(adb, serial, props_to_get)) | |
| output_lines.append(device_info) | |
| PrintPrettyTable(output_lines) | |
| if __name__ == '__main__': | |
| sys.exit(main(sys.argv)) |