| OLD | NEW |
| (Empty) |
| 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 continue | |
| 43 | |
| 44 indent_match = _INDENTATION_RE.match(line) | |
| 45 if not indent_match: | |
| 46 continue | |
| 47 | |
| 48 depth = 1 + len(indent_match.group(1)) / 2 | |
| 49 if depth > len(depth_stack): | |
| 50 logging.error( | |
| 51 'lsusb parsing error: unexpected indentation: "%s"', line) | |
| 52 continue | |
| 53 | |
| 54 while depth < len(depth_stack): | |
| 55 depth_stack.pop() | |
| 56 | |
| 57 cur = depth_stack[-1] | |
| 58 | |
| 59 m = _LSUSB_GROUP_RE.match(line) | |
| 60 if m: | |
| 61 new_group = {} | |
| 62 cur[m.group(1)] = new_group | |
| 63 depth_stack.append(new_group) | |
| 64 continue | |
| 65 | |
| 66 m = _LSUSB_ENTRY_RE.match(line) | |
| 67 if m: | |
| 68 new_entry = { | |
| 69 '_value': m.group(2), | |
| 70 '_desc': m.group(3), | |
| 71 } | |
| 72 cur[m.group(1)] = new_entry | |
| 73 depth_stack.append(new_entry) | |
| 74 continue | |
| 75 | |
| 76 logging.error('lsusb parsing error: unrecognized line: "%s"', line) | |
| 77 | |
| 78 return device | |
| 79 | |
| 80 def lsusb(): | |
| 81 """Call lsusb and return the parsed output.""" | |
| 82 _, lsusb_list_output = cmd_helper.GetCmdStatusAndOutputWithTimeout( | |
| 83 ['lsusb'], timeout=10) | |
| 84 devices = [] | |
| 85 for line in lsusb_list_output.splitlines(): | |
| 86 m = _LSUSB_BUS_DEVICE_RE.match(line) | |
| 87 if m: | |
| 88 bus_num = m.group(1) | |
| 89 dev_num = m.group(2) | |
| 90 try: | |
| 91 devices.append(_lsusbv_on_device(bus_num, dev_num)) | |
| 92 except cmd_helper.TimeoutError: | |
| 93 # Will be blacklisted if it is in expected device file, but times out. | |
| 94 logging.info('lsusb -v %s:%s timed out.', bus_num, dev_num) | |
| 95 | |
| 96 return devices | |
| 97 | |
| 98 def get_lsusb_serial(device): | |
| 99 try: | |
| 100 return device['Device Descriptor']['iSerial']['_desc'] | |
| 101 except KeyError: | |
| 102 return None | |
| 103 | |
| 104 def get_android_devices(): | |
| 105 return [serial for serial in (get_lsusb_serial(d) for d in lsusb()) | |
| 106 if serial] | |
| OLD | NEW |