Home | History | Annotate | Download | only in bin
      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 
     10 import os
     11 import re
     12 import shlex
     13 import subprocess
     14 import sys
     15 
     16 # This file, which resides on every Android device, contains a great deal of
     17 # information about the device.
     18 INFO_FILE = '/system/build.prop'
     19 
     20 # Default set of properties to query about a device.
     21 DEFAULT_PROPS_TO_GET = ['ro.product.device', 'ro.build.version.release',
     22                         'ro.build.type']
     23 
     24 
     25 def 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 
     52 def 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 
     75 def 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 
    119 def 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 
    152 if __name__ == '__main__':
    153   sys.exit(main(sys.argv))