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