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 |