summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xbuild/android/buildbot/bb_device_status_check.py88
-rw-r--r--build/android/devil/__init__.py3
-rw-r--r--build/android/devil/utils/__init__.py3
-rwxr-xr-xbuild/android/devil/utils/reset_usb.py163
-rw-r--r--build/android/pylib/device/adb_wrapper.py13
5 files changed, 200 insertions, 70 deletions
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index 917c51e..7098154 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -26,7 +26,8 @@ sys.path.append(os.path.join(os.path.dirname(__file__),
'common'))
import perf_tests_results_helper # pylint: disable=F0401
-sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
+from devil.utils import reset_usb
from pylib import constants
from pylib.cmd_helper import GetCmdOutput
from pylib.device import adb_wrapper
@@ -197,40 +198,6 @@ def SendEmail(from_address, to_addresses, cc_addresses, subject, msg):
logging.exception('Failed to send alert email.')
-def RestartUsb():
- if not os.path.isfile('/usr/bin/restart_usb'):
- logging.error('Could not restart usb. ''/usr/bin/restart_usb not '
- 'installed on host (see BUG=305769).')
- return False
-
- lsusb_proc = bb_utils.SpawnCmd(['lsusb'], stdout=subprocess.PIPE)
- lsusb_output, _ = lsusb_proc.communicate()
- if lsusb_proc.returncode:
- logging.error('Could not get list of USB ports (i.e. lsusb).')
- return lsusb_proc.returncode
-
- usb_devices = [re.findall(r'Bus (\d\d\d) Device (\d\d\d)', lsusb_line)[0]
- for lsusb_line in lsusb_output.strip().split('\n')]
-
- all_restarted = True
- # Walk USB devices from leaves up (i.e reverse sorted) restarting the
- # connection. If a parent node (e.g. usb hub) is restarted before the
- # devices connected to it, the (bus, dev) for the hub can change, making the
- # output we have wrong. This way we restart the devices before the hub.
- for (bus, dev) in reversed(sorted(usb_devices)):
- # Can not restart root usb connections
- if dev != '001':
- return_code = bb_utils.RunCmd(['/usr/bin/restart_usb', bus, dev])
- if return_code:
- logging.error('Error restarting USB device /dev/bus/usb/%s/%s',
- bus, dev)
- all_restarted = False
- else:
- logging.info('Restarted USB device /dev/bus/usb/%s/%s', bus, dev)
-
- return all_restarted
-
-
def KillAllAdb():
def GetAllAdb():
for p in psutil.process_iter():
@@ -266,7 +233,8 @@ def main():
parser.add_option('--device-status-dashboard', action='store_true',
help='Output device status data for dashboard.')
parser.add_option('--restart-usb', action='store_true',
- help='Restart USB ports before running device check.')
+ help='DEPRECATED. '
+ 'This script now always tries to reset USB.')
parser.add_option('--json-output',
help='Output JSON information into a specified file.')
parser.add_option('-v', '--verbose', action='count', default=1,
@@ -281,39 +249,27 @@ def main():
# Remove the last build's "bad devices" before checking device statuses.
device_blacklist.ResetBlacklist()
+ KillAllAdb()
+ reset_usb.reset_all_usb()
+
try:
- expected_devices = device_list.GetPersistentDeviceList(
- os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME))
+ expected_devices = set(device_list.GetPersistentDeviceList(
+ os.path.join(options.out_dir, device_list.LAST_DEVICES_FILENAME)))
except IOError:
- expected_devices = []
+ expected_devices = set()
devices = device_utils.DeviceUtils.HealthyDevices()
- device_serials = [d.adb.GetDeviceSerial() for d in devices]
- # Only restart usb if devices are missing.
- if set(expected_devices) != set(device_serials):
- logging.warning('expected_devices: %s', expected_devices)
- logging.warning('devices: %s', device_serials)
- KillAllAdb()
- retries = 5
- usb_restarted = True
- if options.restart_usb:
- if not RestartUsb():
- usb_restarted = False
- bb_annotations.PrintWarning()
- logging.error('USB reset stage failed, '
- 'wait for any device to come back.')
- while retries:
- logging.info('retry adb devices...')
- time.sleep(1)
- devices = device_utils.DeviceUtils.HealthyDevices()
- device_serials = [d.adb.GetDeviceSerial() for d in devices]
- if set(expected_devices) == set(device_serials):
- # All devices are online, keep going.
- break
- if not usb_restarted and devices:
- # The USB wasn't restarted, but there's at least one device online.
- # No point in trying to wait for all devices.
- break
- retries -= 1
+ device_serials = set(d.adb.GetDeviceSerial() for d in devices)
+
+ missing_devices = expected_devices.difference(device_serials)
+ new_devices = device_serials.difference(expected_devices)
+
+ if missing_devices or new_devices:
+ logging.warning('expected_devices:')
+ for d in sorted(expected_devices):
+ logging.warning(' %s', d)
+ logging.warning('devices:')
+ for d in sorted(device_serials):
+ logging.warning(' %s', d)
types, builds, batteries, errors, devices_ok, json_data = (
[], [], [], [], [], [])
diff --git a/build/android/devil/__init__.py b/build/android/devil/__init__.py
new file mode 100644
index 0000000..50b23df
--- /dev/null
+++ b/build/android/devil/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/devil/utils/__init__.py b/build/android/devil/utils/__init__.py
new file mode 100644
index 0000000..50b23df
--- /dev/null
+++ b/build/android/devil/utils/__init__.py
@@ -0,0 +1,3 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
diff --git a/build/android/devil/utils/reset_usb.py b/build/android/devil/utils/reset_usb.py
new file mode 100755
index 0000000..97facc2
--- /dev/null
+++ b/build/android/devil/utils/reset_usb.py
@@ -0,0 +1,163 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import argparse
+import fcntl
+import logging
+import re
+import sys
+
+from pylib import cmd_helper
+from pylib.device import adb_wrapper
+from pylib.device import device_errors
+from pylib.utils import run_tests_helper
+
+_INDENTATION_RE = re.compile(r'^( *)')
+_LSUSB_BUS_DEVICE_RE = re.compile(r'^Bus (\d{3}) Device (\d{3}):')
+_LSUSB_ENTRY_RE = re.compile(r'^ *([^ ]+) +([^ ]+) *([^ ].*)?$')
+_LSUSB_GROUP_RE = re.compile(r'^ *([^ ]+.*):$')
+
+_USBDEVFS_RESET = ord('U') << 8 | 20
+
+
+def reset_usb(bus, device):
+ """Reset the USB device with the given bus and device."""
+ usb_file_path = '/dev/bus/usb/%03d/%03d' % (bus, device)
+ with open(usb_file_path, 'w') as usb_file:
+ logging.debug('fcntl.ioctl(%s, %d)', usb_file_path, _USBDEVFS_RESET)
+ fcntl.ioctl(usb_file, _USBDEVFS_RESET)
+
+
+def reset_android_usb(serial):
+ """Reset the USB device for the given Android device."""
+ lsusb_info = lsusb()
+
+ bus = None
+ device = None
+ for device_info in lsusb_info:
+ device_serial = _get_lsusb_serial(device)
+ if device_serial == serial:
+ bus = int(device_info.get('bus'))
+ device = int(device_info.get('device'))
+
+ if bus and device:
+ reset_usb(bus, device)
+ else:
+ raise device_errors.DeviceUnreachableError(
+ 'Unable to determine bus or device for device %s' % serial)
+
+
+def reset_all_usb():
+ """Reset all non-root USB devices."""
+ lsusb_info = lsusb()
+ for device_info in lsusb_info:
+ if int(device_info.get('device')) != 1:
+ bus = int(device_info.get('bus'))
+ device = int(device_info.get('device'))
+ try:
+ reset_usb(bus, device)
+ serial = _get_lsusb_serial(device_info)
+ if serial:
+ logging.info('Reset USB device (bus: %03d, device: %03d, serial: %s)',
+ bus, device, serial)
+ else:
+ logging.info('Reset USB device (bus: %03d, device: %03d)',
+ bus, device)
+ except IOError:
+ logging.error(
+ 'Failed to reset USB device (bus: %03d, device: %03d)',
+ bus, device)
+
+
+def lsusb():
+ """Call lsusb and return the parsed output."""
+ lsusb_raw_output = cmd_helper.GetCmdOutput(['lsusb', '-v'])
+ device = None
+ devices = []
+ depth_stack = []
+ for line in lsusb_raw_output.splitlines():
+ if not line:
+ if device:
+ devices.append(device)
+ device = None
+ continue
+
+ if not device:
+ m = _LSUSB_BUS_DEVICE_RE.match(line)
+ if m:
+ device = {
+ 'bus': m.group(1),
+ 'device': m.group(2)
+ }
+ depth_stack = [device]
+ continue
+
+ indent_match = _INDENTATION_RE.match(line)
+ if not indent_match:
+ continue
+
+ depth = 1 + len(indent_match.group(1)) / 2
+ if depth > len(depth_stack):
+ logging.error('lsusb parsing error: unexpected indentation: "%s"', line)
+ continue
+
+ while depth < len(depth_stack):
+ depth_stack.pop()
+
+ cur = depth_stack[-1]
+
+ m = _LSUSB_GROUP_RE.match(line)
+ if m:
+ new_group = {}
+ cur[m.group(1)] = new_group
+ depth_stack.append(new_group)
+ continue
+
+ m = _LSUSB_ENTRY_RE.match(line)
+ if m:
+ new_entry = {
+ '_value': m.group(2),
+ '_desc': m.group(3),
+ }
+ cur[m.group(1)] = new_entry
+ depth_stack.append(new_entry)
+ continue
+
+ logging.error('lsusb parsing error: unrecognized line: "%s"', line)
+
+ if device:
+ devices.append(device)
+
+ return devices
+
+
+def _get_lsusb_serial(device):
+ return device.get('Device Descriptor', {}).get('iSerial', {}).get('_desc')
+
+
+def main():
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-v', '--verbose', action='count')
+ parser.add_argument('-s', '--serial')
+ parser.add_argument('--bus', type=int)
+ parser.add_argument('--device', type=int)
+ args = parser.parse_args()
+
+ run_tests_helper.SetLogLevel(args.verbose)
+
+ if args.serial:
+ reset_android_usb(args.serial)
+ elif args.bus and args.device:
+ reset_usb(args.bus, args.device)
+ else:
+ parser.error('Unable to determine target. '
+ 'Specify --serial or BOTH --bus and --device.')
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())
+
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index e897326..9ecb6bc 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -170,23 +170,28 @@ class AdbWrapper(object):
return cls.Devices(timeout=timeout, retries=retries)
@classmethod
- def Devices(cls, is_ready=True, timeout=_DEFAULT_TIMEOUT,
+ def Devices(cls, is_ready=True, long_list=False, timeout=_DEFAULT_TIMEOUT,
retries=_DEFAULT_RETRIES):
"""Get the list of active attached devices.
Args:
is_ready: Whether the devices should be limited to only those that are
ready for use.
+ long_list: Whether to use the long listing format.
timeout: (optional) Timeout per try in seconds.
retries: (optional) Number of retries to attempt.
Yields:
AdbWrapper instances.
"""
- output = cls._RunAdbCmd(['devices'], timeout=timeout, retries=retries)
- lines = (line.split() for line in output.splitlines())
+ cmd = ['devices']
+ if long_list:
+ cmd.append('-l')
+ output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries)
+ lines = (line.split() for line in output.splitlines()[1:])
return [AdbWrapper(line[0]) for line in lines
- if len(line) == 2 and (not is_ready or line[1] == _READY_STATE)]
+ if ((long_list or len(line) == 2)
+ and (not is_ready or line[1] == _READY_STATE))]
def GetDeviceSerial(self):
"""Gets the device serial number associated with this object.