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 |
11 import pipes | 13 import pipes |
12 import sys | 14 import sys |
| 15 import tempfile |
13 import time | 16 import time |
| 17 import zipfile |
14 | 18 |
15 import pylib.android_commands | 19 import pylib.android_commands |
16 from pylib.device import adb_wrapper | 20 from pylib.device import adb_wrapper |
17 from pylib.device import decorators | 21 from pylib.device import decorators |
18 from pylib.device import device_errors | 22 from pylib.device import device_errors |
| 23 from pylib.device.commands import install_commands |
19 from pylib.utils import apk_helper | 24 from pylib.utils import apk_helper |
| 25 from pylib.utils import host_utils |
20 from pylib.utils import parallelizer | 26 from pylib.utils import parallelizer |
21 | 27 |
22 _DEFAULT_TIMEOUT = 30 | 28 _DEFAULT_TIMEOUT = 30 |
23 _DEFAULT_RETRIES = 3 | 29 _DEFAULT_RETRIES = 3 |
24 | 30 |
25 | 31 |
26 @decorators.WithExplicitTimeoutAndRetries( | 32 @decorators.WithExplicitTimeoutAndRetries( |
27 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) | 33 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) |
28 def GetAVDs(): | 34 def GetAVDs(): |
29 """Returns a list of Android Virtual Devices. | 35 """Returns a list of Android Virtual Devices. |
(...skipping 24 matching lines...) Expand all Loading... |
54 Args: | 60 Args: |
55 device: Either a device serial, an existing AdbWrapper instance, an | 61 device: Either a device serial, an existing AdbWrapper instance, an |
56 an existing AndroidCommands instance, or nothing. | 62 an existing AndroidCommands instance, or nothing. |
57 default_timeout: An integer containing the default number of seconds to | 63 default_timeout: An integer containing the default number of seconds to |
58 wait for an operation to complete if no explicit value | 64 wait for an operation to complete if no explicit value |
59 is provided. | 65 is provided. |
60 default_retries: An integer containing the default number or times an | 66 default_retries: An integer containing the default number or times an |
61 operation should be retried on failure if no explicit | 67 operation should be retried on failure if no explicit |
62 value is provided. | 68 value is provided. |
63 """ | 69 """ |
| 70 self.adb = None |
64 self.old_interface = None | 71 self.old_interface = None |
65 if isinstance(device, basestring): | 72 if isinstance(device, basestring): |
| 73 self.adb = adb_wrapper.AdbWrapper(device) |
66 self.old_interface = pylib.android_commands.AndroidCommands(device) | 74 self.old_interface = pylib.android_commands.AndroidCommands(device) |
67 elif isinstance(device, adb_wrapper.AdbWrapper): | 75 elif isinstance(device, adb_wrapper.AdbWrapper): |
| 76 self.adb = device |
68 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) | 77 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) |
69 elif isinstance(device, pylib.android_commands.AndroidCommands): | 78 elif isinstance(device, pylib.android_commands.AndroidCommands): |
| 79 self.adb = adb_wrapper.AdbWrapper(device.GetDevice()) |
70 self.old_interface = device | 80 self.old_interface = device |
71 elif not device: | 81 elif not device: |
| 82 self.adb = adb_wrapper.AdbWrapper('') |
72 self.old_interface = pylib.android_commands.AndroidCommands() | 83 self.old_interface = pylib.android_commands.AndroidCommands() |
73 else: | 84 else: |
74 raise ValueError('Unsupported type passed for argument "device"') | 85 raise ValueError('Unsupported type passed for argument "device"') |
| 86 self._commands_installed = False |
75 self._default_timeout = default_timeout | 87 self._default_timeout = default_timeout |
76 self._default_retries = default_retries | 88 self._default_retries = default_retries |
77 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) | 89 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) |
78 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) | 90 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) |
79 | 91 |
80 @decorators.WithTimeoutAndRetriesFromInstance() | 92 @decorators.WithTimeoutAndRetriesFromInstance() |
81 def IsOnline(self, timeout=None, retries=None): | 93 def IsOnline(self, timeout=None, retries=None): |
82 """Checks whether the device is online. | 94 """Checks whether the device is online. |
83 | 95 |
84 Args: | 96 Args: |
85 timeout: timeout in seconds | 97 timeout: timeout in seconds |
86 retries: number of retries | 98 retries: number of retries |
87 | 99 |
88 Returns: | 100 Returns: |
89 True if the device is online, False otherwise. | 101 True if the device is online, False otherwise. |
90 | 102 |
91 Raises: | 103 Raises: |
92 CommandTimeoutError on timeout. | 104 CommandTimeoutError on timeout. |
93 """ | 105 """ |
| 106 return self._IsOnlineImpl() |
| 107 |
| 108 def _IsOnlineImpl(self): |
94 return self.old_interface.IsOnline() | 109 return self.old_interface.IsOnline() |
95 | 110 |
96 @decorators.WithTimeoutAndRetriesFromInstance() | 111 @decorators.WithTimeoutAndRetriesFromInstance() |
97 def HasRoot(self, timeout=None, retries=None): | 112 def HasRoot(self, timeout=None, retries=None): |
98 """Checks whether or not adbd has root privileges. | 113 """Checks whether or not adbd has root privileges. |
99 | 114 |
100 Args: | 115 Args: |
101 timeout: timeout in seconds | 116 timeout: timeout in seconds |
102 retries: number of retries | 117 retries: number of retries |
103 | 118 |
104 Returns: | 119 Returns: |
105 True if adbd has root privileges, False otherwise. | 120 True if adbd has root privileges, False otherwise. |
106 | 121 |
107 Raises: | 122 Raises: |
108 CommandTimeoutError on timeout. | 123 CommandTimeoutError on timeout. |
109 DeviceUnreachableError on missing device. | 124 DeviceUnreachableError on missing device. |
110 """ | 125 """ |
111 return self._HasRootImpl() | 126 return self._HasRootImpl() |
112 | 127 |
113 def _HasRootImpl(self): | 128 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 """ | |
125 return self.old_interface.IsRootEnabled() | 129 return self.old_interface.IsRootEnabled() |
126 | 130 |
127 @decorators.WithTimeoutAndRetriesFromInstance() | 131 @decorators.WithTimeoutAndRetriesFromInstance() |
128 def EnableRoot(self, timeout=None, retries=None): | 132 def EnableRoot(self, timeout=None, retries=None): |
129 """Restarts adbd with root privileges. | 133 """Restarts adbd with root privileges. |
130 | 134 |
131 Args: | 135 Args: |
132 timeout: timeout in seconds | 136 timeout: timeout in seconds |
133 retries: number of retries | 137 retries: number of retries |
134 | 138 |
(...skipping 14 matching lines...) Expand all Loading... |
149 retries: number of retries | 153 retries: number of retries |
150 | 154 |
151 Returns: | 155 Returns: |
152 The device's path to its SD card. | 156 The device's path to its SD card. |
153 | 157 |
154 Raises: | 158 Raises: |
155 CommandFailedError if the external storage path could not be determined. | 159 CommandFailedError if the external storage path could not be determined. |
156 CommandTimeoutError on timeout. | 160 CommandTimeoutError on timeout. |
157 DeviceUnreachableError on missing device. | 161 DeviceUnreachableError on missing device. |
158 """ | 162 """ |
| 163 return self._GetExternalStoragePathImpl() |
| 164 |
| 165 def _GetExternalStoragePathImpl(self): |
159 try: | 166 try: |
160 return self.old_interface.GetExternalStorage() | 167 return self.old_interface.GetExternalStorage() |
161 except AssertionError as e: | 168 except AssertionError as e: |
162 raise device_errors.CommandFailedError( | 169 raise device_errors.CommandFailedError( |
163 str(e), device=str(self)), None, sys.exc_info()[2] | 170 str(e), device=str(self)), None, sys.exc_info()[2] |
164 | 171 |
165 @decorators.WithTimeoutAndRetriesFromInstance() | 172 @decorators.WithTimeoutAndRetriesFromInstance() |
166 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): | 173 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): |
167 """Wait for the device to fully boot. | 174 """Wait for the device to fully boot. |
168 | 175 |
169 This means waiting for the device to boot, the package manager to be | 176 This means waiting for the device to boot, the package manager to be |
170 available, and the SD card to be ready. It can optionally mean waiting | 177 available, and the SD card to be ready. It can optionally mean waiting |
171 for wifi to come up, too. | 178 for wifi to come up, too. |
172 | 179 |
173 Args: | 180 Args: |
174 wifi: A boolean indicating if we should wait for wifi to come up or not. | 181 wifi: A boolean indicating if we should wait for wifi to come up or not. |
175 timeout: timeout in seconds | 182 timeout: timeout in seconds |
176 retries: number of retries | 183 retries: number of retries |
177 | 184 |
178 Raises: | 185 Raises: |
179 CommandFailedError on failure. | 186 CommandFailedError on failure. |
180 CommandTimeoutError if one of the component waits times out. | 187 CommandTimeoutError if one of the component waits times out. |
181 DeviceUnreachableError if the device becomes unresponsive. | 188 DeviceUnreachableError if the device becomes unresponsive. |
182 """ | 189 """ |
183 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) | 190 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) |
184 | 191 |
185 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): | 192 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 """ | |
201 if timeout is None: | 193 if timeout is None: |
202 timeout = self._default_timeout | 194 timeout = self._default_timeout |
203 self.old_interface.WaitForSystemBootCompleted(timeout) | 195 self.old_interface.WaitForSystemBootCompleted(timeout) |
204 self.old_interface.WaitForDevicePm() | 196 self.old_interface.WaitForDevicePm() |
205 self.old_interface.WaitForSdCardReady(timeout) | 197 self.old_interface.WaitForSdCardReady(timeout) |
206 if wifi: | 198 if wifi: |
207 while not 'Wi-Fi is enabled' in ( | 199 while not 'Wi-Fi is enabled' in ( |
208 self._RunShellCommandImpl('dumpsys wifi')): | 200 self._RunShellCommandImpl('dumpsys wifi')): |
209 time.sleep(1) | 201 time.sleep(1) |
210 | 202 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 out = self.old_interface.Install(apk_path, reinstall=reinstall) | 266 out = self.old_interface.Install(apk_path, reinstall=reinstall) |
275 for line in out.splitlines(): | 267 for line in out.splitlines(): |
276 if 'Failure' in line: | 268 if 'Failure' in line: |
277 raise device_errors.CommandFailedError( | 269 raise device_errors.CommandFailedError( |
278 line.strip(), device=str(self)) | 270 line.strip(), device=str(self)) |
279 except AssertionError as e: | 271 except AssertionError as e: |
280 raise device_errors.CommandFailedError( | 272 raise device_errors.CommandFailedError( |
281 str(e), device=str(self)), None, sys.exc_info()[2] | 273 str(e), device=str(self)), None, sys.exc_info()[2] |
282 | 274 |
283 @decorators.WithTimeoutAndRetriesFromInstance() | 275 @decorators.WithTimeoutAndRetriesFromInstance() |
284 def RunShellCommand(self, cmd, check_return=False, as_root=False, | 276 def RunShellCommand(self, cmd, check_return=False, as_root=False, cwd=None, |
285 timeout=None, retries=None): | 277 env=None, timeout=None, retries=None): |
286 """Run an ADB shell command. | 278 """Run an ADB shell command. |
287 | 279 |
288 TODO(jbudorick) Switch the default value of check_return to True after | 280 TODO(jbudorick) Switch the default value of check_return to True after |
289 AndroidCommands is gone. | 281 AndroidCommands is gone. |
290 | 282 |
291 Args: | 283 Args: |
292 cmd: A list containing the command to run on the device and any arguments. | 284 cmd: A list containing the command to run on the device and any arguments. |
293 check_return: A boolean indicating whether or not the return code should | 285 check_return: A boolean indicating whether or not the return code should |
294 be checked. | 286 be checked. |
295 as_root: A boolean indicating whether the shell command should be run | 287 as_root: A boolean indicating whether the shell command should be run |
296 with root privileges. | 288 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. |
297 timeout: timeout in seconds | 291 timeout: timeout in seconds |
298 retries: number of retries | 292 retries: number of retries |
299 | 293 |
300 Returns: | 294 Returns: |
301 The output of the command. | 295 The output of the command. |
302 | 296 |
303 Raises: | 297 Raises: |
304 CommandFailedError if check_return is True and the return code is nozero. | 298 CommandFailedError if check_return is True and the return code is nozero. |
305 CommandTimeoutError on timeout. | 299 CommandTimeoutError on timeout. |
306 DeviceUnreachableError on missing device. | 300 DeviceUnreachableError on missing device. |
307 """ | 301 """ |
308 return self._RunShellCommandImpl(cmd, check_return=check_return, | 302 return self._RunShellCommandImpl( |
309 as_root=as_root, timeout=timeout) | 303 cmd, check_return=check_return, as_root=as_root, cwd=cwd, env=env, |
| 304 timeout=timeout) |
310 | 305 |
311 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, | 306 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, |
312 timeout=None): | 307 cwd=None, env=None, timeout=None): |
313 """Implementation of RunShellCommand. | 308 # TODO(jbudorick): Remove the timeout parameter once this is no longer |
314 | 309 # backed by AndroidCommands. |
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 """ | |
333 if isinstance(cmd, list): | 310 if isinstance(cmd, list): |
334 cmd = ' '.join(cmd) | 311 cmd = ' '.join(cmd) |
335 if as_root and not self.HasRoot(): | 312 if as_root and not self._HasRootImpl(): |
336 cmd = 'su -c %s' % cmd | 313 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) |
337 if check_return: | 319 if check_return: |
338 code, output = self.old_interface.GetShellCommandStatusAndOutput( | 320 code, output = self.old_interface.GetShellCommandStatusAndOutput( |
339 cmd, timeout_time=timeout) | 321 cmd, timeout_time=timeout) |
340 if int(code) != 0: | 322 if int(code) != 0: |
341 raise device_errors.AdbCommandFailedError( | 323 raise device_errors.AdbCommandFailedError( |
342 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) | 324 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) |
343 else: | 325 else: |
344 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) | 326 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) |
345 return output | 327 return output |
346 | 328 |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 DeviceUnreachableError on missing device. | 476 DeviceUnreachableError on missing device. |
495 """ | 477 """ |
496 self.old_interface.SendKeyEvent(keycode) | 478 self.old_interface.SendKeyEvent(keycode) |
497 | 479 |
498 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT | 480 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT |
499 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES | 481 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES |
500 | 482 |
501 @decorators.WithTimeoutAndRetriesDefaults( | 483 @decorators.WithTimeoutAndRetriesDefaults( |
502 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, | 484 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, |
503 PUSH_CHANGED_FILES_DEFAULT_RETRIES) | 485 PUSH_CHANGED_FILES_DEFAULT_RETRIES) |
504 def PushChangedFiles(self, host_path, device_path, timeout=None, | 486 def PushChangedFiles(self, host_device_tuples, timeout=None, |
505 retries=None): | 487 retries=None): |
506 """Push files to the device, skipping files that don't need updating. | 488 """Push files to the device, skipping files that don't need updating. |
507 | 489 |
508 Args: | 490 Args: |
509 host_path: A string containing the absolute path to the file or directory | 491 host_device_tuples: A list of (host_path, device_path) tuples, where |
510 on the host that should be minimally pushed to the device. | 492 |host_path| is an absolute path of a file or directory on the host |
511 device_path: A string containing the absolute path of the destination on | 493 that should be minimially pushed to the device, and |device_path| is |
512 the device. | 494 an absolute path of the destination on the device. |
513 timeout: timeout in seconds | 495 timeout: timeout in seconds |
514 retries: number of retries | 496 retries: number of retries |
515 | 497 |
516 Raises: | 498 Raises: |
517 CommandFailedError on failure. | 499 CommandFailedError on failure. |
518 CommandTimeoutError on timeout. | 500 CommandTimeoutError on timeout. |
519 DeviceUnreachableError on missing device. | 501 DeviceUnreachableError on missing device. |
520 """ | 502 """ |
521 self.old_interface.PushIfNeeded(host_path, device_path) | 503 |
| 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) |
522 | 622 |
523 @decorators.WithTimeoutAndRetriesFromInstance() | 623 @decorators.WithTimeoutAndRetriesFromInstance() |
524 def FileExists(self, device_path, timeout=None, retries=None): | 624 def FileExists(self, device_path, timeout=None, retries=None): |
525 """Checks whether the given file exists on the device. | 625 """Checks whether the given file exists on the device. |
526 | 626 |
527 Args: | 627 Args: |
528 device_path: A string containing the absolute path to the file on the | 628 device_path: A string containing the absolute path to the file on the |
529 device. | 629 device. |
530 timeout: timeout in seconds | 630 timeout: timeout in seconds |
531 retries: number of retries | 631 retries: number of retries |
532 | 632 |
533 Returns: | 633 Returns: |
534 True if the file exists on the device, False otherwise. | 634 True if the file exists on the device, False otherwise. |
535 | 635 |
536 Raises: | 636 Raises: |
537 CommandTimeoutError on timeout. | 637 CommandTimeoutError on timeout. |
538 DeviceUnreachableError on missing device. | 638 DeviceUnreachableError on missing device. |
539 """ | 639 """ |
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 """ | |
557 return self.old_interface.FileExistsOnDevice(device_path) | 640 return self.old_interface.FileExistsOnDevice(device_path) |
558 | 641 |
559 @decorators.WithTimeoutAndRetriesFromInstance() | 642 @decorators.WithTimeoutAndRetriesFromInstance() |
560 def PullFile(self, device_path, host_path, timeout=None, retries=None): | 643 def PullFile(self, device_path, host_path, timeout=None, retries=None): |
561 """Pull a file from the device. | 644 """Pull a file from the device. |
562 | 645 |
563 Args: | 646 Args: |
564 device_path: A string containing the absolute path of the file to pull | 647 device_path: A string containing the absolute path of the file to pull |
565 from the device. | 648 from the device. |
566 host_path: A string containing the absolute path of the destination on | 649 host_path: A string containing the absolute path of the destination on |
(...skipping 24 matching lines...) Expand all Loading... |
591 retries: number of retries | 674 retries: number of retries |
592 | 675 |
593 Returns: | 676 Returns: |
594 The contents of the file at |device_path| as a list of lines. | 677 The contents of the file at |device_path| as a list of lines. |
595 | 678 |
596 Raises: | 679 Raises: |
597 CommandFailedError if the file can't be read. | 680 CommandFailedError if the file can't be read. |
598 CommandTimeoutError on timeout. | 681 CommandTimeoutError on timeout. |
599 DeviceUnreachableError on missing device. | 682 DeviceUnreachableError on missing device. |
600 """ | 683 """ |
601 # TODO(jbudorick) Evaluate whether we awant to return a list of lines after | 684 # TODO(jbudorick) Evaluate whether we want to return a list of lines after |
602 # the implementation switch, and if file not found should raise exception. | 685 # the implementation switch, and if file not found should raise exception. |
603 if as_root: | 686 if as_root: |
604 if not self.old_interface.CanAccessProtectedFileContents(): | 687 if not self.old_interface.CanAccessProtectedFileContents(): |
605 raise device_errors.CommandFailedError( | 688 raise device_errors.CommandFailedError( |
606 'Cannot read from %s with root privileges.' % device_path) | 689 'Cannot read from %s with root privileges.' % device_path) |
607 return self.old_interface.GetProtectedFileContents(device_path) | 690 return self.old_interface.GetProtectedFileContents(device_path) |
608 else: | 691 else: |
609 return self.old_interface.GetFileContents(device_path) | 692 return self.old_interface.GetFileContents(device_path) |
610 | 693 |
611 @decorators.WithTimeoutAndRetriesFromInstance() | 694 @decorators.WithTimeoutAndRetriesFromInstance() |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
748 A dict mapping process name to PID for each process that contained the | 831 A dict mapping process name to PID for each process that contained the |
749 provided |process_name|. | 832 provided |process_name|. |
750 | 833 |
751 Raises: | 834 Raises: |
752 CommandTimeoutError on timeout. | 835 CommandTimeoutError on timeout. |
753 DeviceUnreachableError on missing device. | 836 DeviceUnreachableError on missing device. |
754 """ | 837 """ |
755 return self._GetPidsImpl(process_name) | 838 return self._GetPidsImpl(process_name) |
756 | 839 |
757 def _GetPidsImpl(self, process_name): | 840 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 """ | |
773 procs_pids = {} | 841 procs_pids = {} |
774 for line in self._RunShellCommandImpl('ps'): | 842 for line in self._RunShellCommandImpl('ps'): |
775 try: | 843 try: |
776 ps_data = line.split() | 844 ps_data = line.split() |
777 if process_name in ps_data[-1]: | 845 if process_name in ps_data[-1]: |
778 procs_pids[ps_data[-1]] = ps_data[1] | 846 procs_pids[ps_data[-1]] = ps_data[1] |
779 except IndexError: | 847 except IndexError: |
780 pass | 848 pass |
781 return procs_pids | 849 return procs_pids |
782 | 850 |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
863 A Parallelizer operating over |devices|. | 931 A Parallelizer operating over |devices|. |
864 """ | 932 """ |
865 if not devices or len(devices) == 0: | 933 if not devices or len(devices) == 0: |
866 devices = pylib.android_commands.GetAttachedDevices() | 934 devices = pylib.android_commands.GetAttachedDevices() |
867 parallelizer_type = (parallelizer.Parallelizer if async | 935 parallelizer_type = (parallelizer.Parallelizer if async |
868 else parallelizer.SyncParallelizer) | 936 else parallelizer.SyncParallelizer) |
869 return parallelizer_type([ | 937 return parallelizer_type([ |
870 d if isinstance(d, DeviceUtils) else DeviceUtils(d) | 938 d if isinstance(d, DeviceUtils) else DeviceUtils(d) |
871 for d in devices]) | 939 for d in devices]) |
872 | 940 |
OLD | NEW |