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 390 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
401 | 401 |
402 self._LogShell(install_cmd) | 402 self._LogShell(install_cmd) |
403 return self._adb.SendCommand(install_cmd, | 403 return self._adb.SendCommand(install_cmd, |
404 timeout_time=2 * 60, | 404 timeout_time=2 * 60, |
405 retry_count=0) | 405 retry_count=0) |
406 | 406 |
407 def ManagedInstall(self, apk_path, keep_data=False, package_name=None, | 407 def ManagedInstall(self, apk_path, keep_data=False, package_name=None, |
408 reboots_on_failure=2): | 408 reboots_on_failure=2): |
409 """Installs specified package and reboots device on timeouts. | 409 """Installs specified package and reboots device on timeouts. |
410 | 410 |
| 411 If package_name is supplied, checks if the package is already installed and |
| 412 doesn't reinstall if the apk md5sums match. |
| 413 |
411 Args: | 414 Args: |
412 apk_path: Path to .apk file to install. | 415 apk_path: Path to .apk file to install. |
413 keep_data: Reinstalls instead of uninstalling first, preserving the | 416 keep_data: Reinstalls instead of uninstalling first, preserving the |
414 application data. | 417 application data. |
415 package_name: Package name (only needed if keep_data=False). | 418 package_name: Package name (only needed if keep_data=False). |
416 reboots_on_failure: number of time to reboot if package manager is frozen. | 419 reboots_on_failure: number of time to reboot if package manager is frozen. |
417 | |
418 Returns: | |
419 A status string returned by adb install | |
420 """ | 420 """ |
| 421 # Check if package is already installed and up to date. |
| 422 if package_name: |
| 423 installed_apk_path = self.GetApplicationPath(package_name) |
| 424 if installed_apk_path and self.CheckMd5Sum(apk_path, installed_apk_path): |
| 425 logging.info('Skipped install: identical %s APK already installed' % |
| 426 package_name) |
| 427 return |
| 428 # Install. |
421 reboots_left = reboots_on_failure | 429 reboots_left = reboots_on_failure |
422 while True: | 430 while True: |
423 try: | 431 try: |
424 if not keep_data: | 432 if not keep_data: |
425 assert package_name | 433 assert package_name |
426 self.Uninstall(package_name) | 434 self.Uninstall(package_name) |
427 install_status = self.Install(apk_path, reinstall=keep_data) | 435 install_status = self.Install(apk_path, reinstall=keep_data) |
428 if 'Success' in install_status: | 436 if 'Success' in install_status: |
429 return install_status | 437 return |
430 except errors.WaitForResponseTimedOutError: | 438 except errors.WaitForResponseTimedOutError: |
431 print '@@@STEP_WARNINGS@@@' | 439 print '@@@STEP_WARNINGS@@@' |
432 logging.info('Timeout on installing %s on device %s', apk_path, | 440 logging.info('Timeout on installing %s on device %s', apk_path, |
433 self._device) | 441 self._device) |
434 | 442 |
435 if reboots_left <= 0: | 443 if reboots_left <= 0: |
436 raise Exception('Install failure') | 444 raise Exception('Install failure') |
437 | 445 |
438 # Force a hard reboot on last attempt | 446 # Force a hard reboot on last attempt |
439 self.Reboot(full_reboot=(reboots_left == 1)) | 447 self.Reboot(full_reboot=(reboots_left == 1)) |
(...skipping 286 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 self.RunShellCommand('pm clear ' + package) | 734 self.RunShellCommand('pm clear ' + package) |
727 | 735 |
728 def SendKeyEvent(self, keycode): | 736 def SendKeyEvent(self, keycode): |
729 """Sends keycode to the device. | 737 """Sends keycode to the device. |
730 | 738 |
731 Args: | 739 Args: |
732 keycode: Numeric keycode to send (see "enum" at top of file). | 740 keycode: Numeric keycode to send (see "enum" at top of file). |
733 """ | 741 """ |
734 self.RunShellCommand('input keyevent %d' % keycode) | 742 self.RunShellCommand('input keyevent %d' % keycode) |
735 | 743 |
736 def CheckMd5Sum(self, local_path, device_path, ignore_paths=False): | 744 def CheckMd5Sum(self, local_path, device_path): |
737 """Compares the md5sum of a local path against a device path. | 745 """Compares the md5sum of a local path against a device path. |
738 | 746 |
739 Args: | 747 Args: |
740 local_path: Path (file or directory) on the host. | 748 local_path: Path (file or directory) on the host. |
741 device_path: Path on the device. | 749 device_path: Path on the device. |
742 ignore_paths: If False, both the md5sum and the relative paths/names of | |
743 files must match. If True, only the md5sum must match. | |
744 | 750 |
745 Returns: | 751 Returns: |
746 True if the md5sums match. | 752 True if the md5sums match. |
747 """ | 753 """ |
748 if not self._md5sum_build_dir: | 754 if not self._md5sum_build_dir: |
749 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') | 755 default_build_type = os.environ.get('BUILD_TYPE', 'Debug') |
750 build_dir = '%s/%s/' % ( | 756 build_dir = '%s/%s/' % ( |
751 cmd_helper.OutDirectory().get(), default_build_type) | 757 cmd_helper.OutDirectory().get(), default_build_type) |
752 md5sum_dist_path = '%s/md5sum_dist' % build_dir | 758 md5sum_dist_path = '%s/md5sum_dist' % build_dir |
753 if not os.path.exists(md5sum_dist_path): | 759 if not os.path.exists(md5sum_dist_path): |
(...skipping 715 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 """ | 1475 """ |
1470 def __init__(self, output): | 1476 def __init__(self, output): |
1471 self._output = output | 1477 self._output = output |
1472 | 1478 |
1473 def write(self, data): | 1479 def write(self, data): |
1474 data = data.replace('\r\r\n', '\n') | 1480 data = data.replace('\r\r\n', '\n') |
1475 self._output.write(data) | 1481 self._output.write(data) |
1476 | 1482 |
1477 def flush(self): | 1483 def flush(self): |
1478 self._output.flush() | 1484 self._output.flush() |
OLD | NEW |