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 |