Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(649)

Side by Side Diff: appengine/third_party/python-adb/adb/adb_commands_safe.py

Issue 1424923006: Small fixes as found in staging. (Closed) Base URL: git@github.com:luci/luci-py.git@4_more_functionality
Patch Set: Include fix Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | appengine/third_party/python-adb/adb/adb_protocol.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2015 Google Inc. All rights reserved. 1 # Copyright 2015 Google Inc. All rights reserved.
2 # 2 #
3 # Licensed under the Apache License, Version 2.0 (the "License"); 3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License. 4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at 5 # You may obtain a copy of the License at
6 # 6 #
7 # http://www.apache.org/licenses/LICENSE-2.0 7 # http://www.apache.org/licenses/LICENSE-2.0
8 # 8 #
9 # Unless required by applicable law or agreed to in writing, software 9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS, 10 # distributed under the License is distributed on an "AS IS" BASIS,
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
134 def ConnectDevice(cls, port_path, **kwargs): 134 def ConnectDevice(cls, port_path, **kwargs):
135 """Return a AdbCommandsSafe for a USB device referenced by the port path. 135 """Return a AdbCommandsSafe for a USB device referenced by the port path.
136 136
137 Arguments: 137 Arguments:
138 - port_path: str in form '1/2' to refer to a connected but unopened USB 138 - port_path: str in form '1/2' to refer to a connected but unopened USB
139 device. 139 device.
140 - The rest are the same as __init__(). 140 - The rest are the same as __init__().
141 """ 141 """
142 # pylint: disable=protected-access 142 # pylint: disable=protected-access
143 obj = cls(port_path=port_path, handle=None, **kwargs) 143 obj = cls(port_path=port_path, handle=None, **kwargs)
144 obj._WaitUntilFound(use_serial=False) 144 if obj._WaitUntilFound(use_serial=False):
145 if obj._OpenHandle(): 145 if obj._OpenHandle():
146 obj._Connect(use_serial=False) 146 obj._Connect(use_serial=False)
147 return obj 147 return obj
148 148
149 @classmethod 149 @classmethod
150 def Connect(cls, handle, **kwargs): 150 def Connect(cls, handle, **kwargs):
151 """Return a AdbCommandsSafe for a USB device referenced by a handle. 151 """Return a AdbCommandsSafe for a USB device referenced by a handle.
152 152
153 Arguments: 153 Arguments:
154 - handle: an opened or unopened common.UsbHandle. 154 - handle: an opened or unopened common.UsbHandle.
155 - The rest are the same as __init__(). 155 - The rest are the same as __init__().
156 156
(...skipping 173 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 return False 330 return False
331 331
332 if not self._Reboot(): 332 if not self._Reboot():
333 return False 333 return False
334 334
335 # There's no need to loop initially too fast. Restarting the phone 335 # There's no need to loop initially too fast. Restarting the phone
336 # always take several tens of seconds at best. 336 # always take several tens of seconds at best.
337 time.sleep(5.) 337 time.sleep(5.)
338 338
339 i = 0 339 i = 0
340 for i in self._Loop(): 340 for i in self._Loop(timeout=60000):
341 if not self._Reconnect(True): 341 if not self._Reconnect(True, timeout=60000):
342 continue 342 continue
343 uptime = self.GetUptime() 343 uptime = self.GetUptime()
344 if uptime and uptime < previous_uptime: 344 if uptime and uptime < previous_uptime:
345 return True 345 return True
346 time.sleep(0.1) 346 time.sleep(0.1)
347 _LOG.error( 347 _LOG.error(
348 '%s.Reboot(): Failed to id after %d tries', self.port_path, i+1) 348 '%s.Reboot(): Failed to reboot after %d tries', self.port_path, i+1)
349 return False 349 return False
350 350
351 def Remount(self): 351 def Remount(self):
352 """Remount / as read-write.""" 352 """Remount / as read-write."""
353 if self._adb_cmd: 353 if self._adb_cmd:
354 for _ in self._Loop(): 354 for _ in self._Loop():
355 try: 355 try:
356 out = self._adb_cmd.Remount() 356 out = self._adb_cmd.Remount()
357 # TODO(maruel): Wait for the remount operation to be completed. 357 # TODO(maruel): Wait for the remount operation to be completed.
358 _LOG.info('%s.Remount(): %s', self.port_path, out) 358 _LOG.info('%s.Remount(): %s', self.port_path, out)
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after
488 return out.startswith('uid=0(root)') 488 return out.startswith('uid=0(root)')
489 489
490 # Protected methods. 490 # Protected methods.
491 491
492 def _Reboot(self): 492 def _Reboot(self):
493 """Reboots the phone.""" 493 """Reboots the phone."""
494 i = 0 494 i = 0
495 for i in self._Loop(): 495 for i in self._Loop():
496 try: 496 try:
497 out = self._adb_cmd.Reboot() 497 out = self._adb_cmd.Reboot()
498 except usb_exceptions.ReadFailedError:
499 # It looks like it's possible that adbd restarts the device so fast that
500 # it close the USB connection before adbd has the time to reply (yay for
501 # race conditions). In that case there's no way to know if the command
502 # worked too fast or something went wrong and the command didn't go
503 # through.
504 # Assume it worked, which is nasty.
505 out = ''
498 except self._ERRORS as e: 506 except self._ERRORS as e:
499 if not self._Reset('(): %s', e, use_serial=True): 507 if not self._Reset('(): %s', e, use_serial=True):
500 break 508 break
501 continue 509 continue
502 510
503 _LOG.info('%s._Reboot(): %r', self.port_path, out) 511 _LOG.info('%s._Reboot(): %s: %r', self.port_path, self.serial, out)
504 if out == '': 512 if out == '':
505 # reboot doesn't reply anything. 513 # reboot doesn't reply anything.
506 return True 514 return True
507 assert False, repr(out) 515 assert False, repr(out)
508 _LOG.error('%s._Reboot(): Failed after %d tries', self.port_path, i+1) 516 _LOG.error('%s._Reboot(): Failed after %d tries', self.port_path, i+1)
509 return False 517 return False
510 518
511 def _Root(self): 519 def _Root(self):
512 """Upgrades adbd from shell user context (uid 2000) to root.""" 520 """Upgrades adbd from shell user context (uid 2000) to root."""
513 i = 0 521 i = 0
514 for i in self._Loop(): 522 for i in self._Loop():
515 try: 523 try:
516 out = self._adb_cmd.Root() 524 out = self._adb_cmd.Root()
525 except usb_exceptions.ReadFailedError:
526 # It looks like it's possible that adbd restarts itself so fast that it
527 # close the USB connection before adbd has the time to reply (yay for
528 # race conditions). In that case there's no way to know if the command
529 # worked too fast or something went wrong and the command didn't go
530 # through.
531 # Assume it worked, which is nasty.
532 out = 'restarting adbd as root\n'
517 except self._ERRORS as e: 533 except self._ERRORS as e:
518 if not self._Reset('(): %s', e, use_serial=True): 534 if not self._Reset('(): %s', e, use_serial=True):
519 break 535 break
520 continue 536 continue
521 537
522 _LOG.info('%s._Root(): %r', self.port_path, out) 538 _LOG.info('%s._Root(): %r', self.port_path, out)
523 # Hardcoded strings in platform_system_core/adb/services.cpp 539 # Hardcoded strings in platform_system_core/adb/services.cpp
524 if out == 'adbd is already running as root\n': 540 if out == 'adbd is already running as root\n':
525 return True 541 return True
526 if out == 'adbd cannot run as root in production builds\n': 542 if out == 'adbd cannot run as root in production builds\n':
(...skipping 11 matching lines...) Expand all
538 """Reduces adbd from root to shell user context (uid 2000). 554 """Reduces adbd from root to shell user context (uid 2000).
539 555
540 Doing so has the effect of having the device switch USB port. As such, the 556 Doing so has the effect of having the device switch USB port. As such, the
541 device has to be found back by the serial number, not by self.port_path 557 device has to be found back by the serial number, not by self.port_path
542 """ 558 """
543 assert self._serial 559 assert self._serial
544 i = 0 560 i = 0
545 for i in self._Loop(): 561 for i in self._Loop():
546 try: 562 try:
547 out = self._adb_cmd.Unroot() 563 out = self._adb_cmd.Unroot()
564 except usb_exceptions.ReadFailedError:
565 # Unroot() is special (compared to Reboot and Root) as it's mostly
566 # guaranteed that the output was sent before the USB connection is torn
567 # down. But the exception still swallows the output (!)
568 # Assume it worked, which is nasty.
569 out = 'restarting adbd as non root\n'
548 except self._ERRORS as e: 570 except self._ERRORS as e:
549 if not self._Reset('(): %s', e, use_serial=True): 571 if not self._Reset('(): %s', e, use_serial=True):
550 break 572 break
551 continue 573 continue
552 574
553 _LOG.info('%s.Unroot(): %r', self.port_path, out) 575 _LOG.info('%s.Unroot(): %r', self.port_path, out)
554 # Hardcoded strings in platform_system_core/adb/services.cpp 576 # Hardcoded strings in platform_system_core/adb/services.cpp
555 if out in ('adbd not running as root\n', 'restarting adbd as non root\n'): 577 if out in ('adbd not running as root\n', 'restarting adbd as non root\n'):
556 return True 578 return True
557 assert False, repr(out) 579 assert False, repr(out)
(...skipping 19 matching lines...) Expand all
577 self._port_path = self._handle.port_path_str 599 self._port_path = self._handle.port_path_str
578 else: 600 else:
579 self._handle = common.UsbHandle.Find( 601 self._handle = common.UsbHandle.Find(
580 adb_commands.DeviceIsAvailable, port_path=self.port_path, 602 adb_commands.DeviceIsAvailable, port_path=self.port_path,
581 timeout_ms=self._default_timeout_ms) 603 timeout_ms=self._default_timeout_ms)
582 _LOG.info( 604 _LOG.info(
583 '%s._Find(%s) %s = %s', 605 '%s._Find(%s) %s = %s',
584 previous_port_path, use_serial, self._serial, 606 previous_port_path, use_serial, self._serial,
585 self.port_path if self._handle else 'None') 607 self.port_path if self._handle else 'None')
586 except (common.usb1.USBError, usb_exceptions.DeviceNotFoundError) as e: 608 except (common.usb1.USBError, usb_exceptions.DeviceNotFoundError) as e:
587 _LOG.info( 609 _LOG.debug(
588 '%s._Find(%s) %s : %s', self.port_path, use_serial, self._serial, e) 610 '%s._Find(%s) %s : %s', self.port_path, use_serial, self._serial, e)
611 return bool(self._handle)
589 612
590 def _WaitUntilFound(self, use_serial): 613 def _WaitUntilFound(self, use_serial, timeout=None):
591 """Loops until the device is found on the USB bus. 614 """Loops until the device is found on the USB bus.
592 615
593 The handle is left unopened. 616 The handle is left unopened.
594 617
595 This function should normally be called when either adbd or the phone is 618 This function should normally be called when either adbd or the phone is
596 rebooting. 619 rebooting.
597 """ 620 """
598 assert not self._handle 621 assert not self._handle
599 _LOG.debug('%s._WaitUntilFound(%s)', self.port_path, use_serial) 622 _LOG.debug(
623 '%s._WaitUntilFound(%s)',
624 self.port_path, self.serial if use_serial else use_serial)
600 i = 0 625 i = 0
601 for i in self._Loop(): 626 for i in self._Loop(timeout=timeout):
602 try: 627 if self._Find(use_serial=use_serial):
603 self._Find(use_serial=use_serial) 628 return True
604 return 629 # Enumerate the devices present to help.
605 except usb_exceptions.DeviceNotFoundError as e: 630 def fn(h):
606 _LOG.info( 631 return '%s:%s' % (h.port_path, h.serial_number)
607 '%s._WaitUntilFound(): Retrying _Find() due to %s', 632 devices = '; '.join(
608 self.port_path, e) 633 fn(h) for h in
634 common.UsbHandle.FindDevicesSafe(DeviceIsAvailable, timeout_ms=1000))
609 _LOG.warning( 635 _LOG.warning(
610 '%s._WaitUntilFound() gave up after %d tries', self.port_path, i+1) 636 '%s._WaitUntilFound(%s) gave up after %d tries; found %s.',
637 self.port_path, self.serial if use_serial else use_serial, i+1, devices)
638
639 return False
611 640
612 def _OpenHandle(self): 641 def _OpenHandle(self):
613 """Opens the unopened self._handle.""" 642 """Opens the unopened self._handle."""
614 #_LOG.debug('%s._OpenHandle()', self.port_path) 643 #_LOG.debug('%s._OpenHandle()', self.port_path)
615 if self._handle: 644 if self._handle:
616 assert not self._handle.is_open 645 assert not self._handle.is_open
617 i = 0 646 i = 0
618 for i in self._Loop(): 647 for i in self._Loop():
619 try: 648 try:
620 # If this succeeds, this initializes self._handle._handle, which is a 649 # If this succeeds, this initializes self._handle._handle, which is a
621 # usb1.USBDeviceHandle. 650 # usb1.USBDeviceHandle.
622 self._handle.Open() 651 self._handle.Open()
623 break 652 return True
624 except common.usb1.USBErrorNoDevice as e: 653 except common.usb1.USBErrorNoDevice as e:
625 _LOG.warning( 654 _LOG.warning(
626 '%s._OpenHandle(): USBErrorNoDevice: %s', self.port_path, e) 655 '%s._OpenHandle(): USBErrorNoDevice: %s', self.port_path, e)
627 # Do not kill adb, it just means the USB host is likely resetting and 656 # Do not kill adb, it just means the USB host is likely resetting and
628 # the device is temporarily unavailable. We can't use 657 # the device is temporarily unavailable. We can't use
629 # handle.serial_number since this communicates with the device. 658 # handle.serial_number since this communicates with the device.
630 except common.usb1.USBErrorBusy as e: 659 except common.usb1.USBErrorBusy as e:
631 _LOG.warning('%s._OpenHandle(): USBErrorBusy: %s', self.port_path, e) 660 _LOG.warning('%s._OpenHandle(): USBErrorBusy: %s', self.port_path, e)
632 KillADB() 661 KillADB()
633 except common.usb1.USBErrorAccess as e: 662 except common.usb1.USBErrorAccess as e:
634 # Do not try to use serial_number, since we can't even access the 663 # Do not try to use serial_number, since we can't even access the
635 # port. 664 # port.
636 _LOG.warning( 665 _LOG.error(
637 '%s._OpenHandle(): Try rebooting the host: %s', self.port_path, e) 666 '%s._OpenHandle(): No access, maybe change udev rule or add '
667 'yourself to plugdev: %s', self.port_path, e)
668 # Not worth retrying, exit early.
638 break 669 break
639 else: 670 else:
640 _LOG.error( 671 _LOG.error(
641 '%s._OpenHandle(): Failed after %d tries', self.port_path, i+1) 672 '%s._OpenHandle(): Failed after %d tries', self.port_path, i+1)
642 self.Close() 673 self.Close()
643 return bool(self._handle) 674 return False
644 675
645 def _Connect(self, use_serial): 676 def _Connect(self, use_serial):
646 """Initializes self._adb_cmd from the opened self._handle. 677 """Initializes self._adb_cmd from the opened self._handle.
647 678
648 Returns True on success. 679 Returns True on success.
649 """ 680 """
650 assert not self._adb_cmd 681 assert not self._adb_cmd
651 _LOG.debug('%s._Connect(%s)', self.port_path, use_serial) 682 _LOG.debug('%s._Connect(%s)', self.port_path, use_serial)
652 if self._handle: 683 if self._handle:
653 assert self._handle.is_open 684 assert self._handle.is_open
654 for _ in self._Loop(): 685 for _ in self._Loop():
655 # On the first access with an open handle, try to set self._serial to 686 # On the first access with an open handle, try to set self._serial to
656 # the serial number of the device. This means communicating to the USB 687 # the serial number of the device. This means communicating to the USB
657 # device, so it may throw. 688 # device, so it may throw.
658 if not self._handle: 689 if not self._handle:
659 # It may happen on a retry. 690 # It may happen on a retry.
660 self._WaitUntilFound(use_serial=use_serial) 691 if self._WaitUntilFound(use_serial=use_serial):
661 self._OpenHandle() 692 self._OpenHandle()
662 if not self._handle: 693 if not self._handle:
663 break 694 break
664 695
665 if not self._serial or use_serial: 696 if not self._serial or use_serial:
666 try: 697 try:
667 # The serial number is attached to common.UsbHandle, no 698 # The serial number is attached to common.UsbHandle, no
668 # adb_commands.AdbCommands. 699 # adb_commands.AdbCommands.
669 self._serial = self._handle.serial_number 700 self._serial = self._handle.serial_number
670 except self._ERRORS as e: 701 except self._ERRORS as e:
671 self.Close() 702 self.Close()
(...skipping 18 matching lines...) Expand all
690 finally: 721 finally:
691 # Do not leak the USB handle when we can't talk to the device. 722 # Do not leak the USB handle when we can't talk to the device.
692 if not self._adb_cmd: 723 if not self._adb_cmd:
693 self.Close() 724 self.Close()
694 725
695 if not self._adb_cmd and self._handle: 726 if not self._adb_cmd and self._handle:
696 _LOG.error('Unexpected close') 727 _LOG.error('Unexpected close')
697 self.Close() 728 self.Close()
698 return bool(self._adb_cmd) 729 return bool(self._adb_cmd)
699 730
700 def _Loop(self): 731 def _Loop(self, timeout=None):
701 """Yields a loop until it's too late.""" 732 """Yields a loop until it's too late."""
733 timeout = timeout or self._lost_timeout_ms
702 start = time.time() 734 start = time.time()
703 for i in xrange(self._tries): 735 for i in xrange(self._tries):
704 if ((time.time() - start) * 1000) >= self._lost_timeout_ms: 736 if ((time.time() - start) * 1000) >= timeout:
705 return 737 return
706 yield i 738 yield i
707 if ((time.time() - start) * 1000) >= self._lost_timeout_ms: 739 if ((time.time() - start) * 1000) >= timeout:
708 return 740 return
709 time.sleep(self._sleep) 741 time.sleep(self._sleep)
710 742
711 def _Reset(self, fmt, *args, **kwargs): 743 def _Reset(self, fmt, *args, **kwargs):
712 """When a self._ERRORS occurred, try to reset the device. 744 """When a self._ERRORS occurred, try to reset the device.
713 745
714 Returns True on success. 746 Returns True on success.
715 """ 747 """
716 items = [self.port_path, inspect.stack()[1][3]] 748 items = [self.port_path, inspect.stack()[1][3]]
717 items.extend(args) 749 items.extend(args)
718 msg = ('%s.%s' + fmt) % tuple(items) 750 msg = ('%s.%s' + fmt) % tuple(items)
719 _LOG.error(msg) 751 _LOG.error(msg)
720 if self._on_error: 752 if self._on_error:
721 self._on_error(msg) 753 self._on_error(msg)
722 754
723 # Reset the adbd and USB connections with a new connection. 755 # Reset the adbd and USB connections with a new connection.
724 return self._Reconnect(kwargs.get('use_serial', False)) 756 return self._Reconnect(kwargs.get('use_serial', False))
725 757
726 def _Reconnect(self, use_serial): 758 def _Reconnect(self, use_serial, timeout=None):
727 """Disconnects and reconnect. 759 """Disconnects and reconnect.
728 760
729 Arguments: 761 Arguments:
730 - use_serial: If True, search the device by the serial number instead of the 762 - use_serial: If True, search the device by the serial number instead of the
731 port number. This is necessary when downgrading adbd from root to user 763 port number. This is necessary when downgrading adbd from root to user
732 context. 764 context.
733 765
734 Returns True on success. 766 Returns True on success.
735 """ 767 """
736 self.Close() 768 self.Close()
737 self._WaitUntilFound(use_serial=use_serial) 769 if not self._WaitUntilFound(use_serial=use_serial, timeout=timeout):
770 return False
738 if not self._OpenHandle(): 771 if not self._OpenHandle():
739 return False 772 return False
740 return self._Connect(use_serial=use_serial) 773 return self._Connect(use_serial=use_serial)
741 774
742 def __repr__(self): 775 def __repr__(self):
743 return '<Device %s %s>' % ( 776 return '<Device %s %s>' % (
744 self.port_path, self.serial if self.is_valid else '(broken)') 777 self.port_path, self.serial if self.is_valid else '(broken)')
OLDNEW
« no previous file with comments | « no previous file | appengine/third_party/python-adb/adb/adb_protocol.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698