| OLD | NEW |
| 1 # Copyright 2014 The Chromium Authors. All rights reserved. | 1 # Copyright 2014 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 a variety of device interactions based on adb. | 5 """Provides a variety of device interactions based on adb. |
| 6 | 6 |
| 7 Eventually, this will be based on adb_wrapper. | 7 Eventually, this will be based on adb_wrapper. |
| 8 """ | 8 """ |
| 9 # pylint: disable=W0613 | 9 # pylint: disable=W0613 |
| 10 | 10 |
| 11 import multiprocessing | |
| 12 import os | |
| 13 import pipes | 11 import pipes |
| 14 import sys | 12 import sys |
| 15 import tempfile | |
| 16 import time | 13 import time |
| 17 import zipfile | |
| 18 | 14 |
| 19 import pylib.android_commands | 15 import pylib.android_commands |
| 20 from pylib.device import adb_wrapper | 16 from pylib.device import adb_wrapper |
| 21 from pylib.device import decorators | 17 from pylib.device import decorators |
| 22 from pylib.device import device_errors | 18 from pylib.device import device_errors |
| 23 from pylib.device.commands import install_commands | |
| 24 from pylib.utils import apk_helper | 19 from pylib.utils import apk_helper |
| 25 from pylib.utils import host_utils | |
| 26 from pylib.utils import parallelizer | 20 from pylib.utils import parallelizer |
| 27 | 21 |
| 28 _DEFAULT_TIMEOUT = 30 | 22 _DEFAULT_TIMEOUT = 30 |
| 29 _DEFAULT_RETRIES = 3 | 23 _DEFAULT_RETRIES = 3 |
| 30 | 24 |
| 31 | 25 |
| 32 @decorators.WithExplicitTimeoutAndRetries( | 26 @decorators.WithExplicitTimeoutAndRetries( |
| 33 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) | 27 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
| 34 def GetAVDs(): | 28 def GetAVDs(): |
| 35 """Returns a list of Android Virtual Devices. | 29 """Returns a list of Android Virtual Devices. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 60 Args: | 54 Args: |
| 61 device: Either a device serial, an existing AdbWrapper instance, an | 55 device: Either a device serial, an existing AdbWrapper instance, an |
| 62 an existing AndroidCommands instance, or nothing. | 56 an existing AndroidCommands instance, or nothing. |
| 63 default_timeout: An integer containing the default number of seconds to | 57 default_timeout: An integer containing the default number of seconds to |
| 64 wait for an operation to complete if no explicit value | 58 wait for an operation to complete if no explicit value |
| 65 is provided. | 59 is provided. |
| 66 default_retries: An integer containing the default number or times an | 60 default_retries: An integer containing the default number or times an |
| 67 operation should be retried on failure if no explicit | 61 operation should be retried on failure if no explicit |
| 68 value is provided. | 62 value is provided. |
| 69 """ | 63 """ |
| 70 self.adb = None | |
| 71 self.old_interface = None | 64 self.old_interface = None |
| 72 if isinstance(device, basestring): | 65 if isinstance(device, basestring): |
| 73 self.adb = adb_wrapper.AdbWrapper(device) | |
| 74 self.old_interface = pylib.android_commands.AndroidCommands(device) | 66 self.old_interface = pylib.android_commands.AndroidCommands(device) |
| 75 elif isinstance(device, adb_wrapper.AdbWrapper): | 67 elif isinstance(device, adb_wrapper.AdbWrapper): |
| 76 self.adb = device | |
| 77 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) | 68 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) |
| 78 elif isinstance(device, pylib.android_commands.AndroidCommands): | 69 elif isinstance(device, pylib.android_commands.AndroidCommands): |
| 79 self.adb = adb_wrapper.AdbWrapper(device.GetDevice()) | |
| 80 self.old_interface = device | 70 self.old_interface = device |
| 81 elif not device: | 71 elif not device: |
| 82 self.adb = adb_wrapper.AdbWrapper('') | |
| 83 self.old_interface = pylib.android_commands.AndroidCommands() | 72 self.old_interface = pylib.android_commands.AndroidCommands() |
| 84 else: | 73 else: |
| 85 raise ValueError('Unsupported type passed for argument "device"') | 74 raise ValueError('Unsupported type passed for argument "device"') |
| 86 self._commands_installed = False | |
| 87 self._default_timeout = default_timeout | 75 self._default_timeout = default_timeout |
| 88 self._default_retries = default_retries | 76 self._default_retries = default_retries |
| 89 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) | 77 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) |
| 90 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) | 78 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) |
| 91 | 79 |
| 92 @decorators.WithTimeoutAndRetriesFromInstance() | 80 @decorators.WithTimeoutAndRetriesFromInstance() |
| 93 def IsOnline(self, timeout=None, retries=None): | 81 def IsOnline(self, timeout=None, retries=None): |
| 94 """Checks whether the device is online. | 82 """Checks whether the device is online. |
| 95 | 83 |
| 96 Args: | 84 Args: |
| 97 timeout: timeout in seconds | 85 timeout: timeout in seconds |
| 98 retries: number of retries | 86 retries: number of retries |
| 99 | 87 |
| 100 Returns: | 88 Returns: |
| 101 True if the device is online, False otherwise. | 89 True if the device is online, False otherwise. |
| 102 | 90 |
| 103 Raises: | 91 Raises: |
| 104 CommandTimeoutError on timeout. | 92 CommandTimeoutError on timeout. |
| 105 """ | 93 """ |
| 106 return self._IsOnlineImpl() | |
| 107 | |
| 108 def _IsOnlineImpl(self): | |
| 109 return self.old_interface.IsOnline() | 94 return self.old_interface.IsOnline() |
| 110 | 95 |
| 111 @decorators.WithTimeoutAndRetriesFromInstance() | 96 @decorators.WithTimeoutAndRetriesFromInstance() |
| 112 def HasRoot(self, timeout=None, retries=None): | 97 def HasRoot(self, timeout=None, retries=None): |
| 113 """Checks whether or not adbd has root privileges. | 98 """Checks whether or not adbd has root privileges. |
| 114 | 99 |
| 115 Args: | 100 Args: |
| 116 timeout: timeout in seconds | 101 timeout: timeout in seconds |
| 117 retries: number of retries | 102 retries: number of retries |
| 118 | 103 |
| 119 Returns: | 104 Returns: |
| 120 True if adbd has root privileges, False otherwise. | 105 True if adbd has root privileges, False otherwise. |
| 121 | 106 |
| 122 Raises: | 107 Raises: |
| 123 CommandTimeoutError on timeout. | 108 CommandTimeoutError on timeout. |
| 124 DeviceUnreachableError on missing device. | 109 DeviceUnreachableError on missing device. |
| 125 """ | 110 """ |
| 126 return self._HasRootImpl() | 111 return self._HasRootImpl() |
| 127 | 112 |
| 128 def _HasRootImpl(self): | 113 def _HasRootImpl(self): |
| 114 """Implementation of HasRoot. |
| 115 |
| 116 This is split from HasRoot to allow other DeviceUtils methods to call |
| 117 HasRoot without spawning a new timeout thread. |
| 118 |
| 119 Returns: |
| 120 Same as for |HasRoot|. |
| 121 |
| 122 Raises: |
| 123 Same as for |HasRoot|. |
| 124 """ |
| 129 return self.old_interface.IsRootEnabled() | 125 return self.old_interface.IsRootEnabled() |
| 130 | 126 |
| 131 @decorators.WithTimeoutAndRetriesFromInstance() | 127 @decorators.WithTimeoutAndRetriesFromInstance() |
| 132 def EnableRoot(self, timeout=None, retries=None): | 128 def EnableRoot(self, timeout=None, retries=None): |
| 133 """Restarts adbd with root privileges. | 129 """Restarts adbd with root privileges. |
| 134 | 130 |
| 135 Args: | 131 Args: |
| 136 timeout: timeout in seconds | 132 timeout: timeout in seconds |
| 137 retries: number of retries | 133 retries: number of retries |
| 138 | 134 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 153 retries: number of retries | 149 retries: number of retries |
| 154 | 150 |
| 155 Returns: | 151 Returns: |
| 156 The device's path to its SD card. | 152 The device's path to its SD card. |
| 157 | 153 |
| 158 Raises: | 154 Raises: |
| 159 CommandFailedError if the external storage path could not be determined. | 155 CommandFailedError if the external storage path could not be determined. |
| 160 CommandTimeoutError on timeout. | 156 CommandTimeoutError on timeout. |
| 161 DeviceUnreachableError on missing device. | 157 DeviceUnreachableError on missing device. |
| 162 """ | 158 """ |
| 163 return self._GetExternalStoragePathImpl() | |
| 164 | |
| 165 def _GetExternalStoragePathImpl(self): | |
| 166 try: | 159 try: |
| 167 return self.old_interface.GetExternalStorage() | 160 return self.old_interface.GetExternalStorage() |
| 168 except AssertionError as e: | 161 except AssertionError as e: |
| 169 raise device_errors.CommandFailedError( | 162 raise device_errors.CommandFailedError( |
| 170 str(e), device=str(self)), None, sys.exc_info()[2] | 163 str(e), device=str(self)), None, sys.exc_info()[2] |
| 171 | 164 |
| 172 @decorators.WithTimeoutAndRetriesFromInstance() | 165 @decorators.WithTimeoutAndRetriesFromInstance() |
| 173 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): | 166 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
| 174 """Wait for the device to fully boot. | 167 """Wait for the device to fully boot. |
| 175 | 168 |
| 176 This means waiting for the device to boot, the package manager to be | 169 This means waiting for the device to boot, the package manager to be |
| 177 available, and the SD card to be ready. It can optionally mean waiting | 170 available, and the SD card to be ready. It can optionally mean waiting |
| 178 for wifi to come up, too. | 171 for wifi to come up, too. |
| 179 | 172 |
| 180 Args: | 173 Args: |
| 181 wifi: A boolean indicating if we should wait for wifi to come up or not. | 174 wifi: A boolean indicating if we should wait for wifi to come up or not. |
| 182 timeout: timeout in seconds | 175 timeout: timeout in seconds |
| 183 retries: number of retries | 176 retries: number of retries |
| 184 | 177 |
| 185 Raises: | 178 Raises: |
| 186 CommandFailedError on failure. | 179 CommandFailedError on failure. |
| 187 CommandTimeoutError if one of the component waits times out. | 180 CommandTimeoutError if one of the component waits times out. |
| 188 DeviceUnreachableError if the device becomes unresponsive. | 181 DeviceUnreachableError if the device becomes unresponsive. |
| 189 """ | 182 """ |
| 190 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) | 183 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) |
| 191 | 184 |
| 192 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): | 185 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): |
| 186 """Implementation of WaitUntilFullyBooted. |
| 187 |
| 188 This is split from WaitUntilFullyBooted to allow other DeviceUtils methods |
| 189 to call WaitUntilFullyBooted without spawning a new timeout thread. |
| 190 |
| 191 TODO(jbudorick) Remove the timeout parameter once this is no longer |
| 192 implemented via AndroidCommands. |
| 193 |
| 194 Args: |
| 195 wifi: Same as for |WaitUntilFullyBooted|. |
| 196 timeout: timeout in seconds |
| 197 |
| 198 Raises: |
| 199 Same as for |WaitUntilFullyBooted|. |
| 200 """ |
| 193 if timeout is None: | 201 if timeout is None: |
| 194 timeout = self._default_timeout | 202 timeout = self._default_timeout |
| 195 self.old_interface.WaitForSystemBootCompleted(timeout) | 203 self.old_interface.WaitForSystemBootCompleted(timeout) |
| 196 self.old_interface.WaitForDevicePm() | 204 self.old_interface.WaitForDevicePm() |
| 197 self.old_interface.WaitForSdCardReady(timeout) | 205 self.old_interface.WaitForSdCardReady(timeout) |
| 198 if wifi: | 206 if wifi: |
| 199 while not 'Wi-Fi is enabled' in ( | 207 while not 'Wi-Fi is enabled' in ( |
| 200 self._RunShellCommandImpl('dumpsys wifi')): | 208 self._RunShellCommandImpl('dumpsys wifi')): |
| 201 time.sleep(1) | 209 time.sleep(1) |
| 202 | 210 |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 266 out = self.old_interface.Install(apk_path, reinstall=reinstall) | 274 out = self.old_interface.Install(apk_path, reinstall=reinstall) |
| 267 for line in out.splitlines(): | 275 for line in out.splitlines(): |
| 268 if 'Failure' in line: | 276 if 'Failure' in line: |
| 269 raise device_errors.CommandFailedError( | 277 raise device_errors.CommandFailedError( |
| 270 line.strip(), device=str(self)) | 278 line.strip(), device=str(self)) |
| 271 except AssertionError as e: | 279 except AssertionError as e: |
| 272 raise device_errors.CommandFailedError( | 280 raise device_errors.CommandFailedError( |
| 273 str(e), device=str(self)), None, sys.exc_info()[2] | 281 str(e), device=str(self)), None, sys.exc_info()[2] |
| 274 | 282 |
| 275 @decorators.WithTimeoutAndRetriesFromInstance() | 283 @decorators.WithTimeoutAndRetriesFromInstance() |
| 276 def RunShellCommand(self, cmd, check_return=False, as_root=False, cwd=None, | 284 def RunShellCommand(self, cmd, check_return=False, as_root=False, |
| 277 env=None, timeout=None, retries=None): | 285 timeout=None, retries=None): |
| 278 """Run an ADB shell command. | 286 """Run an ADB shell command. |
| 279 | 287 |
| 280 TODO(jbudorick) Switch the default value of check_return to True after | 288 TODO(jbudorick) Switch the default value of check_return to True after |
| 281 AndroidCommands is gone. | 289 AndroidCommands is gone. |
| 282 | 290 |
| 283 Args: | 291 Args: |
| 284 cmd: A list containing the command to run on the device and any arguments. | 292 cmd: A list containing the command to run on the device and any arguments. |
| 285 check_return: A boolean indicating whether or not the return code should | 293 check_return: A boolean indicating whether or not the return code should |
| 286 be checked. | 294 be checked. |
| 287 as_root: A boolean indicating whether the shell command should be run | 295 as_root: A boolean indicating whether the shell command should be run |
| 288 with root privileges. | 296 with root privileges. |
| 289 cwd: The device directory in which the command should be run. | |
| 290 env: The environment variables with which the command should be run. | |
| 291 timeout: timeout in seconds | 297 timeout: timeout in seconds |
| 292 retries: number of retries | 298 retries: number of retries |
| 293 | 299 |
| 294 Returns: | 300 Returns: |
| 295 The output of the command. | 301 The output of the command. |
| 296 | 302 |
| 297 Raises: | 303 Raises: |
| 298 CommandFailedError if check_return is True and the return code is nozero. | 304 CommandFailedError if check_return is True and the return code is nozero. |
| 299 CommandTimeoutError on timeout. | 305 CommandTimeoutError on timeout. |
| 300 DeviceUnreachableError on missing device. | 306 DeviceUnreachableError on missing device. |
| 301 """ | 307 """ |
| 302 return self._RunShellCommandImpl( | 308 return self._RunShellCommandImpl(cmd, check_return=check_return, |
| 303 cmd, check_return=check_return, as_root=as_root, cwd=cwd, env=env, | 309 as_root=as_root, timeout=timeout) |
| 304 timeout=timeout) | |
| 305 | 310 |
| 306 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, | 311 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, |
| 307 cwd=None, env=None, timeout=None): | 312 timeout=None): |
| 308 # TODO(jbudorick): Remove the timeout parameter once this is no longer | 313 """Implementation of RunShellCommand. |
| 309 # backed by AndroidCommands. | 314 |
| 315 This is split from RunShellCommand to allow other DeviceUtils methods to |
| 316 call RunShellCommand without spawning a new timeout thread. |
| 317 |
| 318 TODO(jbudorick) Remove the timeout parameter once this is no longer |
| 319 implemented via AndroidCommands. |
| 320 |
| 321 Args: |
| 322 cmd: Same as for |RunShellCommand|. |
| 323 check_return: Same as for |RunShellCommand|. |
| 324 as_root: Same as for |RunShellCommand|. |
| 325 timeout: timeout in seconds |
| 326 |
| 327 Raises: |
| 328 Same as for |RunShellCommand|. |
| 329 |
| 330 Returns: |
| 331 Same as for |RunShellCommand|. |
| 332 """ |
| 310 if isinstance(cmd, list): | 333 if isinstance(cmd, list): |
| 311 cmd = ' '.join(cmd) | 334 cmd = ' '.join(cmd) |
| 312 if as_root and not self._HasRootImpl(): | 335 if as_root and not self.HasRoot(): |
| 313 cmd = 'su -c %s' % cmd | 336 cmd = 'su -c %s' % cmd |
| 314 if env: | |
| 315 cmd = '%s %s' % ( | |
| 316 ' '.join('%s=%s' % (k, v) for k, v in env.iteritems()), cmd) | |
| 317 if cwd: | |
| 318 cmd = 'cd %s && %s' % (cwd, cmd) | |
| 319 if check_return: | 337 if check_return: |
| 320 code, output = self.old_interface.GetShellCommandStatusAndOutput( | 338 code, output = self.old_interface.GetShellCommandStatusAndOutput( |
| 321 cmd, timeout_time=timeout) | 339 cmd, timeout_time=timeout) |
| 322 if int(code) != 0: | 340 if int(code) != 0: |
| 323 raise device_errors.AdbCommandFailedError( | 341 raise device_errors.AdbCommandFailedError( |
| 324 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) | 342 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) |
| 325 else: | 343 else: |
| 326 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) | 344 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) |
| 327 return output | 345 return output |
| 328 | 346 |
| (...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 DeviceUnreachableError on missing device. | 494 DeviceUnreachableError on missing device. |
| 477 """ | 495 """ |
| 478 self.old_interface.SendKeyEvent(keycode) | 496 self.old_interface.SendKeyEvent(keycode) |
| 479 | 497 |
| 480 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT | 498 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT |
| 481 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES | 499 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES |
| 482 | 500 |
| 483 @decorators.WithTimeoutAndRetriesDefaults( | 501 @decorators.WithTimeoutAndRetriesDefaults( |
| 484 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, | 502 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, |
| 485 PUSH_CHANGED_FILES_DEFAULT_RETRIES) | 503 PUSH_CHANGED_FILES_DEFAULT_RETRIES) |
| 486 def PushChangedFiles(self, host_device_tuples, timeout=None, | 504 def PushChangedFiles(self, host_path, device_path, timeout=None, |
| 487 retries=None): | 505 retries=None): |
| 488 """Push files to the device, skipping files that don't need updating. | 506 """Push files to the device, skipping files that don't need updating. |
| 489 | 507 |
| 490 Args: | 508 Args: |
| 491 host_device_tuples: A list of (host_path, device_path) tuples, where | 509 host_path: A string containing the absolute path to the file or directory |
| 492 |host_path| is an absolute path of a file or directory on the host | 510 on the host that should be minimally pushed to the device. |
| 493 that should be minimially pushed to the device, and |device_path| is | 511 device_path: A string containing the absolute path of the destination on |
| 494 an absolute path of the destination on the device. | 512 the device. |
| 495 timeout: timeout in seconds | 513 timeout: timeout in seconds |
| 496 retries: number of retries | 514 retries: number of retries |
| 497 | 515 |
| 498 Raises: | 516 Raises: |
| 499 CommandFailedError on failure. | 517 CommandFailedError on failure. |
| 500 CommandTimeoutError on timeout. | 518 CommandTimeoutError on timeout. |
| 501 DeviceUnreachableError on missing device. | 519 DeviceUnreachableError on missing device. |
| 502 """ | 520 """ |
| 503 | 521 self.old_interface.PushIfNeeded(host_path, device_path) |
| 504 files = [] | |
| 505 for h, d in host_device_tuples: | |
| 506 if os.path.isdir(h): | |
| 507 self._RunShellCommandImpl(['mkdir', '-p', '"%s"' % d], | |
| 508 check_return=True) | |
| 509 files += self.old_interface.GetFilesChanged(h, d) | |
| 510 | |
| 511 if not files: | |
| 512 return | |
| 513 | |
| 514 size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files) | |
| 515 file_count = len(files) | |
| 516 dir_size = sum(host_utils.GetRecursiveDiskUsage(h) | |
| 517 for h, _ in host_device_tuples) | |
| 518 dir_file_count = 0 | |
| 519 for h, _ in host_device_tuples: | |
| 520 if os.path.isdir(h): | |
| 521 dir_file_count += sum(len(f) for _r, _d, f in os.walk(h)) | |
| 522 else: | |
| 523 dir_file_count += 1 | |
| 524 | |
| 525 push_duration = self._ApproximateDuration( | |
| 526 file_count, file_count, size, False) | |
| 527 dir_push_duration = self._ApproximateDuration( | |
| 528 len(host_device_tuples), dir_file_count, dir_size, False) | |
| 529 zip_duration = self._ApproximateDuration(1, 1, size, True) | |
| 530 | |
| 531 if dir_push_duration < push_duration and dir_push_duration < zip_duration: | |
| 532 self._PushChangedFilesIndividually(host_device_tuples) | |
| 533 elif push_duration < zip_duration: | |
| 534 self._PushChangedFilesIndividually(files) | |
| 535 else: | |
| 536 self._PushChangedFilesZipped(files) | |
| 537 self._RunShellCommandImpl( | |
| 538 ['chmod', '-R', '777'] + [d for _, d in host_device_tuples], | |
| 539 as_root=True) | |
| 540 | |
| 541 @staticmethod | |
| 542 def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping): | |
| 543 # We approximate the time to push a set of files to a device as: | |
| 544 # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where | |
| 545 # t: total time (sec) | |
| 546 # c1: adb call time delay (sec) | |
| 547 # a: number of times adb is called (unitless) | |
| 548 # c2: push time delay (sec) | |
| 549 # f: number of files pushed via adb (unitless) | |
| 550 # c3: zip time delay (sec) | |
| 551 # c4: zip rate (bytes/sec) | |
| 552 # b: total number of bytes (bytes) | |
| 553 # c5: transfer rate (bytes/sec) | |
| 554 # c6: compression ratio (unitless) | |
| 555 | |
| 556 # All of these are approximations. | |
| 557 ADB_CALL_PENALTY = 0.1 # seconds | |
| 558 ADB_PUSH_PENALTY = 0.01 # seconds | |
| 559 ZIP_PENALTY = 2.0 # seconds | |
| 560 ZIP_RATE = 10000000.0 # bytes / second | |
| 561 TRANSFER_RATE = 2000000.0 # bytes / second | |
| 562 COMPRESSION_RATIO = 2.0 # unitless | |
| 563 | |
| 564 adb_call_time = ADB_CALL_PENALTY * adb_calls | |
| 565 adb_push_setup_time = ADB_PUSH_PENALTY * file_count | |
| 566 if is_zipping: | |
| 567 zip_time = ZIP_PENALTY + byte_count / ZIP_RATE | |
| 568 transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO) | |
| 569 else: | |
| 570 zip_time = 0 | |
| 571 transfer_time = byte_count / TRANSFER_RATE | |
| 572 return (adb_call_time + adb_push_setup_time + zip_time + transfer_time) | |
| 573 | |
| 574 def _PushChangedFilesIndividually(self, files): | |
| 575 for h, d in files: | |
| 576 self.adb.Push(h, d) | |
| 577 | |
| 578 def _PushChangedFilesZipped(self, files): | |
| 579 if not files: | |
| 580 return | |
| 581 | |
| 582 self._InstallCommands() | |
| 583 | |
| 584 with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file: | |
| 585 zip_proc = multiprocessing.Process( | |
| 586 target=DeviceUtils._CreateDeviceZip, | |
| 587 args=(zip_file.name, files)) | |
| 588 zip_proc.start() | |
| 589 zip_proc.join() | |
| 590 | |
| 591 zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl() | |
| 592 try: | |
| 593 self.adb.Push(zip_file.name, zip_on_device) | |
| 594 self._RunShellCommandImpl( | |
| 595 ['unzip', zip_on_device], | |
| 596 as_root=True, check_return=True, | |
| 597 env={'PATH': '$PATH:%s' % install_commands.BIN_DIR}) | |
| 598 finally: | |
| 599 if zip_proc.is_alive(): | |
| 600 zip_proc.terminate() | |
| 601 if self._IsOnlineImpl(): | |
| 602 self._RunShellCommandImpl(['rm', zip_on_device]) | |
| 603 | |
| 604 def _InstallCommands(self): | |
| 605 if not self._commands_installed and not install_commands.Installed(self): | |
| 606 install_commands.InstallCommands(self) | |
| 607 self._commands_installed = True | |
| 608 | |
| 609 @staticmethod | |
| 610 def _CreateDeviceZip(zip_path, host_device_tuples): | |
| 611 with zipfile.ZipFile(zip_path, 'w') as zip_file: | |
| 612 for host_path, device_path in host_device_tuples: | |
| 613 if os.path.isfile(host_path): | |
| 614 zip_file.write(host_path, device_path, zipfile.ZIP_DEFLATED) | |
| 615 else: | |
| 616 for hd, _, files in os.walk(host_path): | |
| 617 dd = '%s/%s' % (device_path, os.path.relpath(host_path, hd)) | |
| 618 zip_file.write(hd, dd, zipfile.ZIP_STORED) | |
| 619 for f in files: | |
| 620 zip_file.write(os.path.join(hd, f), '%s/%s' % (dd, f), | |
| 621 zipfile.ZIP_DEFLATED) | |
| 622 | 522 |
| 623 @decorators.WithTimeoutAndRetriesFromInstance() | 523 @decorators.WithTimeoutAndRetriesFromInstance() |
| 624 def FileExists(self, device_path, timeout=None, retries=None): | 524 def FileExists(self, device_path, timeout=None, retries=None): |
| 625 """Checks whether the given file exists on the device. | 525 """Checks whether the given file exists on the device. |
| 626 | 526 |
| 627 Args: | 527 Args: |
| 628 device_path: A string containing the absolute path to the file on the | 528 device_path: A string containing the absolute path to the file on the |
| 629 device. | 529 device. |
| 630 timeout: timeout in seconds | 530 timeout: timeout in seconds |
| 631 retries: number of retries | 531 retries: number of retries |
| 632 | 532 |
| 633 Returns: | 533 Returns: |
| 634 True if the file exists on the device, False otherwise. | 534 True if the file exists on the device, False otherwise. |
| 635 | 535 |
| 636 Raises: | 536 Raises: |
| 637 CommandTimeoutError on timeout. | 537 CommandTimeoutError on timeout. |
| 638 DeviceUnreachableError on missing device. | 538 DeviceUnreachableError on missing device. |
| 639 """ | 539 """ |
| 540 return self._FileExistsImpl(device_path) |
| 541 |
| 542 def _FileExistsImpl(self, device_path): |
| 543 """Implementation of FileExists. |
| 544 |
| 545 This is split from FileExists to allow other DeviceUtils methods to call |
| 546 FileExists without spawning a new timeout thread. |
| 547 |
| 548 Args: |
| 549 device_path: Same as for |FileExists|. |
| 550 |
| 551 Returns: |
| 552 True if the file exists on the device, False otherwise. |
| 553 |
| 554 Raises: |
| 555 Same as for |FileExists|. |
| 556 """ |
| 640 return self.old_interface.FileExistsOnDevice(device_path) | 557 return self.old_interface.FileExistsOnDevice(device_path) |
| 641 | 558 |
| 642 @decorators.WithTimeoutAndRetriesFromInstance() | 559 @decorators.WithTimeoutAndRetriesFromInstance() |
| 643 def PullFile(self, device_path, host_path, timeout=None, retries=None): | 560 def PullFile(self, device_path, host_path, timeout=None, retries=None): |
| 644 """Pull a file from the device. | 561 """Pull a file from the device. |
| 645 | 562 |
| 646 Args: | 563 Args: |
| 647 device_path: A string containing the absolute path of the file to pull | 564 device_path: A string containing the absolute path of the file to pull |
| 648 from the device. | 565 from the device. |
| 649 host_path: A string containing the absolute path of the destination on | 566 host_path: A string containing the absolute path of the destination on |
| (...skipping 24 matching lines...) Expand all Loading... |
| 674 retries: number of retries | 591 retries: number of retries |
| 675 | 592 |
| 676 Returns: | 593 Returns: |
| 677 The contents of the file at |device_path| as a list of lines. | 594 The contents of the file at |device_path| as a list of lines. |
| 678 | 595 |
| 679 Raises: | 596 Raises: |
| 680 CommandFailedError if the file can't be read. | 597 CommandFailedError if the file can't be read. |
| 681 CommandTimeoutError on timeout. | 598 CommandTimeoutError on timeout. |
| 682 DeviceUnreachableError on missing device. | 599 DeviceUnreachableError on missing device. |
| 683 """ | 600 """ |
| 684 # TODO(jbudorick) Evaluate whether we want to return a list of lines after | 601 # TODO(jbudorick) Evaluate whether we awant to return a list of lines after |
| 685 # the implementation switch, and if file not found should raise exception. | 602 # the implementation switch, and if file not found should raise exception. |
| 686 if as_root: | 603 if as_root: |
| 687 if not self.old_interface.CanAccessProtectedFileContents(): | 604 if not self.old_interface.CanAccessProtectedFileContents(): |
| 688 raise device_errors.CommandFailedError( | 605 raise device_errors.CommandFailedError( |
| 689 'Cannot read from %s with root privileges.' % device_path) | 606 'Cannot read from %s with root privileges.' % device_path) |
| 690 return self.old_interface.GetProtectedFileContents(device_path) | 607 return self.old_interface.GetProtectedFileContents(device_path) |
| 691 else: | 608 else: |
| 692 return self.old_interface.GetFileContents(device_path) | 609 return self.old_interface.GetFileContents(device_path) |
| 693 | 610 |
| 694 @decorators.WithTimeoutAndRetriesFromInstance() | 611 @decorators.WithTimeoutAndRetriesFromInstance() |
| (...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 831 A dict mapping process name to PID for each process that contained the | 748 A dict mapping process name to PID for each process that contained the |
| 832 provided |process_name|. | 749 provided |process_name|. |
| 833 | 750 |
| 834 Raises: | 751 Raises: |
| 835 CommandTimeoutError on timeout. | 752 CommandTimeoutError on timeout. |
| 836 DeviceUnreachableError on missing device. | 753 DeviceUnreachableError on missing device. |
| 837 """ | 754 """ |
| 838 return self._GetPidsImpl(process_name) | 755 return self._GetPidsImpl(process_name) |
| 839 | 756 |
| 840 def _GetPidsImpl(self, process_name): | 757 def _GetPidsImpl(self, process_name): |
| 758 """Implementation of GetPids. |
| 759 |
| 760 This is split from GetPids to allow other DeviceUtils methods to call |
| 761 GetPids without spawning a new timeout thread. |
| 762 |
| 763 Args: |
| 764 process_name: A string containing the process name to get the PIDs for. |
| 765 |
| 766 Returns: |
| 767 A dict mapping process name to PID for each process that contained the |
| 768 provided |process_name|. |
| 769 |
| 770 Raises: |
| 771 DeviceUnreachableError on missing device. |
| 772 """ |
| 841 procs_pids = {} | 773 procs_pids = {} |
| 842 for line in self._RunShellCommandImpl('ps'): | 774 for line in self._RunShellCommandImpl('ps'): |
| 843 try: | 775 try: |
| 844 ps_data = line.split() | 776 ps_data = line.split() |
| 845 if process_name in ps_data[-1]: | 777 if process_name in ps_data[-1]: |
| 846 procs_pids[ps_data[-1]] = ps_data[1] | 778 procs_pids[ps_data[-1]] = ps_data[1] |
| 847 except IndexError: | 779 except IndexError: |
| 848 pass | 780 pass |
| 849 return procs_pids | 781 return procs_pids |
| 850 | 782 |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 931 A Parallelizer operating over |devices|. | 863 A Parallelizer operating over |devices|. |
| 932 """ | 864 """ |
| 933 if not devices or len(devices) == 0: | 865 if not devices or len(devices) == 0: |
| 934 devices = pylib.android_commands.GetAttachedDevices() | 866 devices = pylib.android_commands.GetAttachedDevices() |
| 935 parallelizer_type = (parallelizer.Parallelizer if async | 867 parallelizer_type = (parallelizer.Parallelizer if async |
| 936 else parallelizer.SyncParallelizer) | 868 else parallelizer.SyncParallelizer) |
| 937 return parallelizer_type([ | 869 return parallelizer_type([ |
| 938 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 870 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
| 939 for d in devices]) | 871 for d in devices]) |
| 940 | 872 |
| OLD | NEW |