| Index: appengine/third_party/python-adb/adb/adb_commands_safe.py
|
| diff --git a/appengine/third_party/python-adb/adb/adb_commands_safe.py b/appengine/third_party/python-adb/adb/adb_commands_safe.py
|
| index 4dd22ee44c76425684529b7d12403475db0b6b56..c56c27412729619f24cd4760514a4c9b84fbd639 100644
|
| --- a/appengine/third_party/python-adb/adb/adb_commands_safe.py
|
| +++ b/appengine/third_party/python-adb/adb/adb_commands_safe.py
|
| @@ -141,9 +141,9 @@ class AdbCommandsSafe(object):
|
| """
|
| # pylint: disable=protected-access
|
| obj = cls(port_path=port_path, handle=None, **kwargs)
|
| - obj._WaitUntilFound(use_serial=False)
|
| - if obj._OpenHandle():
|
| - obj._Connect(use_serial=False)
|
| + if obj._WaitUntilFound(use_serial=False):
|
| + if obj._OpenHandle():
|
| + obj._Connect(use_serial=False)
|
| return obj
|
|
|
| @classmethod
|
| @@ -337,15 +337,15 @@ class AdbCommandsSafe(object):
|
| time.sleep(5.)
|
|
|
| i = 0
|
| - for i in self._Loop():
|
| - if not self._Reconnect(True):
|
| + for i in self._Loop(timeout=60000):
|
| + if not self._Reconnect(True, timeout=60000):
|
| continue
|
| uptime = self.GetUptime()
|
| if uptime and uptime < previous_uptime:
|
| return True
|
| time.sleep(0.1)
|
| _LOG.error(
|
| - '%s.Reboot(): Failed to id after %d tries', self.port_path, i+1)
|
| + '%s.Reboot(): Failed to reboot after %d tries', self.port_path, i+1)
|
| return False
|
|
|
| def Remount(self):
|
| @@ -495,12 +495,20 @@ class AdbCommandsSafe(object):
|
| for i in self._Loop():
|
| try:
|
| out = self._adb_cmd.Reboot()
|
| + except usb_exceptions.ReadFailedError:
|
| + # It looks like it's possible that adbd restarts the device so fast that
|
| + # it close the USB connection before adbd has the time to reply (yay for
|
| + # race conditions). In that case there's no way to know if the command
|
| + # worked too fast or something went wrong and the command didn't go
|
| + # through.
|
| + # Assume it worked, which is nasty.
|
| + out = ''
|
| except self._ERRORS as e:
|
| if not self._Reset('(): %s', e, use_serial=True):
|
| break
|
| continue
|
|
|
| - _LOG.info('%s._Reboot(): %r', self.port_path, out)
|
| + _LOG.info('%s._Reboot(): %s: %r', self.port_path, self.serial, out)
|
| if out == '':
|
| # reboot doesn't reply anything.
|
| return True
|
| @@ -514,6 +522,14 @@ class AdbCommandsSafe(object):
|
| for i in self._Loop():
|
| try:
|
| out = self._adb_cmd.Root()
|
| + except usb_exceptions.ReadFailedError:
|
| + # It looks like it's possible that adbd restarts itself so fast that it
|
| + # close the USB connection before adbd has the time to reply (yay for
|
| + # race conditions). In that case there's no way to know if the command
|
| + # worked too fast or something went wrong and the command didn't go
|
| + # through.
|
| + # Assume it worked, which is nasty.
|
| + out = 'restarting adbd as root\n'
|
| except self._ERRORS as e:
|
| if not self._Reset('(): %s', e, use_serial=True):
|
| break
|
| @@ -545,6 +561,12 @@ class AdbCommandsSafe(object):
|
| for i in self._Loop():
|
| try:
|
| out = self._adb_cmd.Unroot()
|
| + except usb_exceptions.ReadFailedError:
|
| + # Unroot() is special (compared to Reboot and Root) as it's mostly
|
| + # guaranteed that the output was sent before the USB connection is torn
|
| + # down. But the exception still swallows the output (!)
|
| + # Assume it worked, which is nasty.
|
| + out = 'restarting adbd as non root\n'
|
| except self._ERRORS as e:
|
| if not self._Reset('(): %s', e, use_serial=True):
|
| break
|
| @@ -584,10 +606,11 @@ class AdbCommandsSafe(object):
|
| previous_port_path, use_serial, self._serial,
|
| self.port_path if self._handle else 'None')
|
| except (common.usb1.USBError, usb_exceptions.DeviceNotFoundError) as e:
|
| - _LOG.info(
|
| + _LOG.debug(
|
| '%s._Find(%s) %s : %s', self.port_path, use_serial, self._serial, e)
|
| + return bool(self._handle)
|
|
|
| - def _WaitUntilFound(self, use_serial):
|
| + def _WaitUntilFound(self, use_serial, timeout=None):
|
| """Loops until the device is found on the USB bus.
|
|
|
| The handle is left unopened.
|
| @@ -596,18 +619,24 @@ class AdbCommandsSafe(object):
|
| rebooting.
|
| """
|
| assert not self._handle
|
| - _LOG.debug('%s._WaitUntilFound(%s)', self.port_path, use_serial)
|
| + _LOG.debug(
|
| + '%s._WaitUntilFound(%s)',
|
| + self.port_path, self.serial if use_serial else use_serial)
|
| i = 0
|
| - for i in self._Loop():
|
| - try:
|
| - self._Find(use_serial=use_serial)
|
| - return
|
| - except usb_exceptions.DeviceNotFoundError as e:
|
| - _LOG.info(
|
| - '%s._WaitUntilFound(): Retrying _Find() due to %s',
|
| - self.port_path, e)
|
| + for i in self._Loop(timeout=timeout):
|
| + if self._Find(use_serial=use_serial):
|
| + return True
|
| + # Enumerate the devices present to help.
|
| + def fn(h):
|
| + return '%s:%s' % (h.port_path, h.serial_number)
|
| + devices = '; '.join(
|
| + fn(h) for h in
|
| + common.UsbHandle.FindDevicesSafe(DeviceIsAvailable, timeout_ms=1000))
|
| _LOG.warning(
|
| - '%s._WaitUntilFound() gave up after %d tries', self.port_path, i+1)
|
| + '%s._WaitUntilFound(%s) gave up after %d tries; found %s.',
|
| + self.port_path, self.serial if use_serial else use_serial, i+1, devices)
|
| +
|
| + return False
|
|
|
| def _OpenHandle(self):
|
| """Opens the unopened self._handle."""
|
| @@ -620,7 +649,7 @@ class AdbCommandsSafe(object):
|
| # If this succeeds, this initializes self._handle._handle, which is a
|
| # usb1.USBDeviceHandle.
|
| self._handle.Open()
|
| - break
|
| + return True
|
| except common.usb1.USBErrorNoDevice as e:
|
| _LOG.warning(
|
| '%s._OpenHandle(): USBErrorNoDevice: %s', self.port_path, e)
|
| @@ -633,14 +662,16 @@ class AdbCommandsSafe(object):
|
| except common.usb1.USBErrorAccess as e:
|
| # Do not try to use serial_number, since we can't even access the
|
| # port.
|
| - _LOG.warning(
|
| - '%s._OpenHandle(): Try rebooting the host: %s', self.port_path, e)
|
| + _LOG.error(
|
| + '%s._OpenHandle(): No access, maybe change udev rule or add '
|
| + 'yourself to plugdev: %s', self.port_path, e)
|
| + # Not worth retrying, exit early.
|
| break
|
| else:
|
| _LOG.error(
|
| '%s._OpenHandle(): Failed after %d tries', self.port_path, i+1)
|
| - self.Close()
|
| - return bool(self._handle)
|
| + self.Close()
|
| + return False
|
|
|
| def _Connect(self, use_serial):
|
| """Initializes self._adb_cmd from the opened self._handle.
|
| @@ -657,8 +688,8 @@ class AdbCommandsSafe(object):
|
| # device, so it may throw.
|
| if not self._handle:
|
| # It may happen on a retry.
|
| - self._WaitUntilFound(use_serial=use_serial)
|
| - self._OpenHandle()
|
| + if self._WaitUntilFound(use_serial=use_serial):
|
| + self._OpenHandle()
|
| if not self._handle:
|
| break
|
|
|
| @@ -697,14 +728,15 @@ class AdbCommandsSafe(object):
|
| self.Close()
|
| return bool(self._adb_cmd)
|
|
|
| - def _Loop(self):
|
| + def _Loop(self, timeout=None):
|
| """Yields a loop until it's too late."""
|
| + timeout = timeout or self._lost_timeout_ms
|
| start = time.time()
|
| for i in xrange(self._tries):
|
| - if ((time.time() - start) * 1000) >= self._lost_timeout_ms:
|
| + if ((time.time() - start) * 1000) >= timeout:
|
| return
|
| yield i
|
| - if ((time.time() - start) * 1000) >= self._lost_timeout_ms:
|
| + if ((time.time() - start) * 1000) >= timeout:
|
| return
|
| time.sleep(self._sleep)
|
|
|
| @@ -723,7 +755,7 @@ class AdbCommandsSafe(object):
|
| # Reset the adbd and USB connections with a new connection.
|
| return self._Reconnect(kwargs.get('use_serial', False))
|
|
|
| - def _Reconnect(self, use_serial):
|
| + def _Reconnect(self, use_serial, timeout=None):
|
| """Disconnects and reconnect.
|
|
|
| Arguments:
|
| @@ -734,7 +766,8 @@ class AdbCommandsSafe(object):
|
| Returns True on success.
|
| """
|
| self.Close()
|
| - self._WaitUntilFound(use_serial=use_serial)
|
| + if not self._WaitUntilFound(use_serial=use_serial, timeout=timeout):
|
| + return False
|
| if not self._OpenHandle():
|
| return False
|
| return self._Connect(use_serial=use_serial)
|
|
|