OLD | NEW |
---|---|
1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 # Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 """Provides an interface to communicate with the device via the adb command. | 5 """Provides an interface to communicate with the device via the adb command. |
6 | 6 |
7 Assumes adb binary is currently on system path. | 7 Assumes adb binary is currently on system path. |
8 """ | 8 """ |
9 | 9 |
10 import collections | 10 import collections |
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
731 self.RunShellCommand('pm clear ' + package) | 731 self.RunShellCommand('pm clear ' + package) |
732 | 732 |
733 def SendKeyEvent(self, keycode): | 733 def SendKeyEvent(self, keycode): |
734 """Sends keycode to the device. | 734 """Sends keycode to the device. |
735 | 735 |
736 Args: | 736 Args: |
737 keycode: Numeric keycode to send (see "enum" at top of file). | 737 keycode: Numeric keycode to send (see "enum" at top of file). |
738 """ | 738 """ |
739 self.RunShellCommand('input keyevent %d' % keycode) | 739 self.RunShellCommand('input keyevent %d' % keycode) |
740 | 740 |
741 def CheckMd5Sum(self, local_path, device_path): | 741 def _RunMd5Sum(self, local_path, device_path): |
742 """Compares the md5sum of a local path against a device path. | 742 """Gets the md5sum of a local path and device path. |
743 | 743 |
744 Args: | 744 Args: |
745 local_path: Path (file or directory) on the host. | 745 local_path: Path (file or directory) on the host. |
746 device_path: Path on the device. | 746 device_path: Path on the device. |
747 | 747 |
748 Returns: | 748 Returns: |
749 True if the md5sums match. | 749 A tuple containing lists of the local and device md5sum results. |
frankf
2013/07/31 22:58:19
Define exactly what tuple is.
craigdh
2013/08/05 23:55:43
Done.
| |
750 """ | 750 """ |
751 if not self._md5sum_build_dir: | 751 if not self._md5sum_build_dir: |
752 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') | 752 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') |
753 build_dir = '%s/%s/' % ( | 753 build_dir = '%s/%s/' % ( |
754 cmd_helper.OutDirectory().get(), default_build_type) | 754 cmd_helper.OutDirectory().get(), default_build_type) |
755 md5sum_dist_path = '%s/md5sum_dist' % build_dir | 755 md5sum_dist_path = '%s/md5sum_dist' % build_dir |
756 if not os.path.exists(md5sum_dist_path): | 756 if not os.path.exists(md5sum_dist_path): |
757 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() | 757 build_dir = '%s/Release/' % cmd_helper.OutDirectory().get() |
758 md5sum_dist_path = '%s/md5sum_dist' % build_dir | 758 md5sum_dist_path = '%s/md5sum_dist' % build_dir |
759 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' | 759 assert os.path.exists(md5sum_dist_path), 'Please build md5sum.' |
760 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) | 760 command = 'push %s %s' % (md5sum_dist_path, MD5SUM_DEVICE_FOLDER) |
761 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) | 761 assert _HasAdbPushSucceeded(self._adb.SendCommand(command)) |
762 self._md5sum_build_dir = build_dir | 762 self._md5sum_build_dir = build_dir |
763 | 763 |
764 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + | 764 cmd = (MD5SUM_LD_LIBRARY_PATH + ' ' + self._util_wrapper + ' ' + |
765 MD5SUM_DEVICE_PATH + ' ' + device_path) | 765 MD5SUM_DEVICE_PATH + ' ' + device_path) |
766 device_hash_tuples = _ComputeFileListHash( | 766 device_hash_tuples = _ComputeFileListHash( |
767 self.RunShellCommand(cmd, timeout_time=2 * 60)) | 767 self.RunShellCommand(cmd, timeout_time=2 * 60)) |
768 assert os.path.exists(local_path), 'Local path not found %s' % local_path | 768 assert os.path.exists(local_path), 'Local path not found %s' % local_path |
769 md5sum_output = cmd_helper.GetCmdOutput( | 769 md5sum_output = cmd_helper.GetCmdOutput( |
770 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) | 770 ['%s/md5sum_bin_host' % self._md5sum_build_dir, local_path]) |
771 host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines()) | 771 host_hash_tuples = _ComputeFileListHash(md5sum_output.splitlines()) |
772 return (host_hash_tuples, device_hash_tuples) | |
773 | |
774 def GetFileDiff(self, local_path, device_path): | |
frankf
2013/07/31 22:58:19
GetFileDiff -> GetFilesChanged
craigdh
2013/08/05 23:55:43
Done.
| |
775 """Compares the md5sum of a local path against a device path. | |
776 | |
777 Note: Ignores extra files on the device. | |
778 | |
779 Args: | |
780 local_path: Path (file or directory) on the host. | |
781 device_path: Path on the device. | |
782 | |
783 Returns: | |
784 A list of files whose md5sums do not match. | |
785 """ | |
786 host_hash_tuples, device_hash_tuples = self._RunMd5Sum( | |
787 local_path, device_path) | |
772 | 788 |
773 # Ignore extra files on the device. | 789 # Ignore extra files on the device. |
774 if len(device_hash_tuples) > len(host_hash_tuples): | 790 if len(device_hash_tuples) > len(host_hash_tuples): |
775 host_files = [os.path.relpath(os.path.normpath(p.path), | 791 host_files = [os.path.relpath(os.path.normpath(p.path), |
776 os.path.normpath(local_path)) for p in host_hash_tuples] | 792 os.path.normpath(local_path)) for p in host_hash_tuples] |
777 | 793 |
778 def _host_has(fname): | 794 def _host_has(fname): |
frankf
2013/07/31 22:58:19
naming issue
craigdh
2013/08/05 23:55:43
Done.
| |
779 return any(path in fname for path in host_files) | 795 return any(path in fname for path in host_files) |
780 | 796 |
781 hashes_on_device = [h.hash for h in device_hash_tuples if | 797 device_hash_tuples = [h for h in device_hash_tuples if _host_has(h.path)] |
782 _host_has(h.path)] | |
783 else: | |
784 hashes_on_device = [h.hash for h in device_hash_tuples] | |
785 | 798 |
786 # Compare md5sums between host and device files. | 799 # Constructs the target device path from a given host path. Don't use when |
787 hashes_on_host = [h.hash for h in host_hash_tuples] | 800 # only a single file is given as the device_path may specify a rename. |
frankf
2013/07/31 22:58:19
What rename?
craigdh
2013/08/05 23:55:43
If the local_path and device_path refer to a file
| |
788 hashes_on_device.sort() | 801 def _h2d_path(host_path): |
frankf
2013/07/31 22:58:19
Use our naming convention
craigdh
2013/08/05 23:55:43
Done.
| |
789 hashes_on_host.sort() | 802 return os.path.join(os.path.dirname(device_path), os.path.relpath( |
790 return hashes_on_device == hashes_on_host | 803 host_path, os.path.dirname(os.path.normpath(local_path)))) |
804 | |
805 device_hashes = [h.hash for h in device_hash_tuples] | |
806 return [(t.path, | |
807 _h2d_path(t.path) if os.path.isdir(local_path) else device_path) | |
frankf
2013/07/31 22:58:19
You're returning a list of tuples, this doesn't ma
craigdh
2013/08/05 23:55:43
Done.
| |
808 for t in host_hash_tuples if t.hash not in device_hashes] | |
809 | |
810 def CheckMd5Sum(self, local_path, device_path): | |
811 """Compares the md5sum of a local path against a device path. | |
812 | |
813 Args: | |
814 local_path: Path (file or directory) on the host. | |
815 device_path: Path on the device. | |
816 | |
817 Returns: | |
818 True if the md5sums match. | |
819 """ | |
820 return not self.GetFileDiff(local_path, device_path) | |
791 | 821 |
792 def PushIfNeeded(self, local_path, device_path): | 822 def PushIfNeeded(self, local_path, device_path): |
793 """Pushes |local_path| to |device_path|. | 823 """Pushes |local_path| to |device_path|. |
frankf
2013/07/31 22:58:19
rename local to host everywhere
craigdh
2013/08/05 23:55:43
Done.
| |
794 | 824 |
795 Works for files and directories. This method skips copying any paths in | 825 Works for files and directories. This method skips copying any paths in |
796 |test_data_paths| that already exist on the device with the same hash. | 826 |test_data_paths| that already exist on the device with the same hash. |
797 | 827 |
798 All pushed files can be removed by calling RemovePushedFiles(). | 828 All pushed files can be removed by calling RemovePushedFiles(). |
799 """ | 829 """ |
800 assert os.path.exists(local_path), 'Local path not found %s' % local_path | 830 assert os.path.exists(local_path), 'Local path not found %s' % local_path |
801 size = int(cmd_helper.GetCmdOutput(['du', '-sb', local_path]).split()[0]) | 831 |
832 def _get_local_size(path): | |
833 return int(cmd_helper.GetCmdOutput(['du', '-sb', path]).split()[0]) | |
834 | |
835 size = _get_local_size(local_path) | |
802 self._pushed_files.append(device_path) | 836 self._pushed_files.append(device_path) |
803 self._potential_push_size += size | 837 self._potential_push_size += size |
804 | 838 |
805 if self.CheckMd5Sum(local_path, device_path): | 839 missing_files = self.GetFileDiff(local_path, device_path) |
840 if not missing_files: | |
806 return | 841 return |
807 | 842 |
808 self._actual_push_size += size | 843 def _push(local, device): |
frankf
2013/07/31 22:58:19
Naming
craigdh
2013/08/05 23:55:43
Done.
| |
809 # They don't match, so remove everything first and then create it. | 844 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout |
810 if os.path.isdir(local_path): | 845 # of 60 seconds which isn't sufficient for a lot of users of this method. |
811 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) | 846 push_command = 'push %s %s' % (local, device) |
812 self.RunShellCommand('mkdir -p %s' % device_path) | 847 self._LogShell(push_command) |
813 | 848 |
814 # NOTE: We can't use adb_interface.Push() because it hardcodes a timeout of | 849 # Retry push with increasing backoff if the device is busy. |
815 # 60 seconds which isn't sufficient for a lot of users of this method. | 850 retry = 0 |
816 push_command = 'push %s %s' % (local_path, device_path) | 851 while True: |
817 self._LogShell(push_command) | 852 output = self._adb.SendCommand(push_command, timeout_time=30 * 60) |
853 if _HasAdbPushSucceeded(output): | |
854 return | |
855 if 'resource busy' in output and retry < 3: | |
856 retry += 1 | |
857 wait_time = 5 * retry | |
858 logging.error('Push failed, retrying in %d seconds: %s' % | |
859 (wait_time, output)) | |
860 time.sleep(wait_time) | |
861 else: | |
862 raise Exception('Push failed: %s' % output) | |
818 | 863 |
819 # Retry push with increasing backoff if the device is busy. | 864 # Above a small number of files it's likely faster to push everything. |
820 retry = 0 | 865 if len(missing_files) > 20: |
frankf
2013/07/31 22:58:19
This is very arbitrary. Why number of files instea
craigdh
2013/08/05 23:55:43
Based on size for now with a cutoff and added a TO
| |
821 while True: | 866 # We're pushing everything, remove everything first and then create it. |
822 output = self._adb.SendCommand(push_command, timeout_time=30 * 60) | 867 self._actual_push_size += size |
823 if _HasAdbPushSucceeded(output): | 868 if os.path.isdir(local_path): |
824 return | 869 self.RunShellCommand('rm -r %s' % device_path, timeout_time=2 * 60) |
825 if 'resource busy' in output and retry < 3: | 870 self.RunShellCommand('mkdir -p %s' % device_path) |
826 retry += 1 | 871 _push(local_path, device_path) |
827 wait_time = 5 * retry | 872 else: |
828 logging.error('Push failed, retrying in %d seconds: %s' % | 873 for f in missing_files: |
829 (wait_time, output)) | 874 self._actual_push_size += _get_local_size(f[0]) |
830 time.sleep(wait_time) | 875 _push(f[0], f[1]) |
831 else: | |
832 raise Exception('Push failed: %s' % output) | |
833 | 876 |
834 def GetPushSizeInfo(self): | 877 def GetPushSizeInfo(self): |
835 """Get total size of pushes to the device done via PushIfNeeded() | 878 """Get total size of pushes to the device done via PushIfNeeded() |
836 | 879 |
837 Returns: | 880 Returns: |
838 A tuple: | 881 A tuple: |
839 1. Total size of push requests to PushIfNeeded (MB) | 882 1. Total size of push requests to PushIfNeeded (MB) |
840 2. Total size that was actually pushed (MB) | 883 2. Total size that was actually pushed (MB) |
841 """ | 884 """ |
842 return (self._potential_push_size, self._actual_push_size) | 885 return (self._potential_push_size, self._actual_push_size) |
(...skipping 629 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1472 """ | 1515 """ |
1473 def __init__(self, output): | 1516 def __init__(self, output): |
1474 self._output = output | 1517 self._output = output |
1475 | 1518 |
1476 def write(self, data): | 1519 def write(self, data): |
1477 data = data.replace('\r\r\n', '\n') | 1520 data = data.replace('\r\r\n', '\n') |
1478 self._output.write(data) | 1521 self._output.write(data) |
1479 | 1522 |
1480 def flush(self): | 1523 def flush(self): |
1481 self._output.flush() | 1524 self._output.flush() |
OLD | NEW |