Home | History | Annotate | Download | only in utils
      1 # Copyright 2015 The Chromium Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 
      5 import logging
      6 import re
      7 
      8 from devil.utils import cmd_helper
      9 
     10 _COULDNT_OPEN_ERROR_RE = re.compile(r'Couldn\'t open device.*')
     11 _INDENTATION_RE = re.compile(r'^( *)')
     12 _LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}): (.*)')
     13 _LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
     14 _LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
     15 
     16 
     17 def _lsusbv_on_device(bus_id, dev_id):
     18   """Calls lsusb -v on device."""
     19   _, raw_output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
     20       ['lsusb', '-v', '-s', '%s:%s' % (bus_id, dev_id)], timeout=10)
     21 
     22   device = {'bus': bus_id, 'device': dev_id}
     23   depth_stack = [device]
     24 
     25   # TODO(jbudorick): Add documentation for parsing.
     26   for line in raw_output.splitlines():
     27     # Ignore blank lines.
     28     if not line:
     29       continue
     30     # Filter out error mesage about opening device.
     31     if _COULDNT_OPEN_ERROR_RE.match(line):
     32       continue
     33     # Find start of device information.
     34     m = _LSUSB_BUS_DEVICE_RE.match(line)
     35     if m:
     36       if m.group(1) != bus_id:
     37         logging.warning(
     38             'Expected bus_id value: %r, seen %r', bus_id, m.group(1))
     39       if m.group(2) != dev_id:
     40         logging.warning(
     41             'Expected dev_id value: %r, seen %r', dev_id, m.group(2))
     42       device['desc'] = m.group(3)
     43       continue
     44 
     45     indent_match = _INDENTATION_RE.match(line)
     46     if not indent_match:
     47       continue
     48 
     49     depth = 1 + len(indent_match.group(1)) / 2
     50     if depth > len(depth_stack):
     51       logging.error(
     52           'lsusb parsing error: unexpected indentation: "%s"', line)
     53       continue
     54 
     55     while depth < len(depth_stack):
     56       depth_stack.pop()
     57 
     58     cur = depth_stack[-1]
     59 
     60     m = _LSUSB_GROUP_RE.match(line)
     61     if m:
     62       new_group = {}
     63       cur[m.group(1)] = new_group
     64       depth_stack.append(new_group)
     65       continue
     66 
     67     m = _LSUSB_ENTRY_RE.match(line)
     68     if m:
     69       new_entry = {
     70         '_value': m.group(2),
     71         '_desc': m.group(3),
     72       }
     73       cur[m.group(1)] = new_entry
     74       depth_stack.append(new_entry)
     75       continue
     76 
     77     logging.error('lsusb parsing error: unrecognized line: "%s"', line)
     78 
     79   return device
     80 
     81 def lsusb():
     82   """Call lsusb and return the parsed output."""
     83   _, lsusb_list_output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
     84       ['lsusb'], timeout=10)
     85   devices = []
     86   for line in lsusb_list_output.splitlines():
     87     m = _LSUSB_BUS_DEVICE_RE.match(line)
     88     if m:
     89       bus_num = m.group(1)
     90       dev_num = m.group(2)
     91       try:
     92         devices.append(_lsusbv_on_device(bus_num, dev_num))
     93       except cmd_helper.TimeoutError:
     94         # Will be blacklisted if it is in expected device file, but times out.
     95         logging.info('lsusb -v %s:%s timed out.', bus_num, dev_num)
     96   return devices
     97 
     98 def raw_lsusb():
     99   return cmd_helper.GetCmdOutput(['lsusb'])
    100 
    101 def get_lsusb_serial(device):
    102   try:
    103     return device['Device Descriptor']['iSerial']['_desc']
    104   except KeyError:
    105     return None
    106 
    107 def get_android_devices():
    108   return [serial for serial in (get_lsusb_serial(d) for d in lsusb())
    109           if serial]
    110