OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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)') |
OLD | NEW |