Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(49)

Side by Side Diff: build/android/pylib/device/device_utils.py

Issue 646523002: [Android] Add zip pushing and refine push mode selection. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments from craigdh Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
14 import shutil
12 import sys 15 import sys
16 import tempfile
13 import time 17 import time
18 import zipfile
14 19
15 import pylib.android_commands 20 import pylib.android_commands
16 from pylib.device import adb_wrapper 21 from pylib.device import adb_wrapper
17 from pylib.device import decorators 22 from pylib.device import decorators
18 from pylib.device import device_errors 23 from pylib.device import device_errors
24 from pylib.device.commands import install_commands
19 from pylib.utils import apk_helper 25 from pylib.utils import apk_helper
26 from pylib.utils import host_utils
20 from pylib.utils import parallelizer 27 from pylib.utils import parallelizer
21 28
22 _DEFAULT_TIMEOUT = 30 29 _DEFAULT_TIMEOUT = 30
23 _DEFAULT_RETRIES = 3 30 _DEFAULT_RETRIES = 3
24 31
25 32
26 @decorators.WithExplicitTimeoutAndRetries( 33 @decorators.WithExplicitTimeoutAndRetries(
27 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 34 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
28 def GetAVDs(): 35 def GetAVDs():
29 """Returns a list of Android Virtual Devices. 36 """Returns a list of Android Virtual Devices.
(...skipping 24 matching lines...) Expand all
54 Args: 61 Args:
55 device: Either a device serial, an existing AdbWrapper instance, an 62 device: Either a device serial, an existing AdbWrapper instance, an
56 an existing AndroidCommands instance, or nothing. 63 an existing AndroidCommands instance, or nothing.
57 default_timeout: An integer containing the default number of seconds to 64 default_timeout: An integer containing the default number of seconds to
58 wait for an operation to complete if no explicit value 65 wait for an operation to complete if no explicit value
59 is provided. 66 is provided.
60 default_retries: An integer containing the default number or times an 67 default_retries: An integer containing the default number or times an
61 operation should be retried on failure if no explicit 68 operation should be retried on failure if no explicit
62 value is provided. 69 value is provided.
63 """ 70 """
71 self.adb = None
64 self.old_interface = None 72 self.old_interface = None
65 if isinstance(device, basestring): 73 if isinstance(device, basestring):
74 self.adb = adb_wrapper.AdbWrapper(device)
66 self.old_interface = pylib.android_commands.AndroidCommands(device) 75 self.old_interface = pylib.android_commands.AndroidCommands(device)
67 elif isinstance(device, adb_wrapper.AdbWrapper): 76 elif isinstance(device, adb_wrapper.AdbWrapper):
77 self.adb = device
68 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) 78 self.old_interface = pylib.android_commands.AndroidCommands(str(device))
69 elif isinstance(device, pylib.android_commands.AndroidCommands): 79 elif isinstance(device, pylib.android_commands.AndroidCommands):
80 self.adb = adb_wrapper.AdbWrapper(device.GetDevice())
70 self.old_interface = device 81 self.old_interface = device
71 elif not device: 82 elif not device:
83 self.adb = adb_wrapper.AdbWrapper('')
72 self.old_interface = pylib.android_commands.AndroidCommands() 84 self.old_interface = pylib.android_commands.AndroidCommands()
73 else: 85 else:
74 raise ValueError('Unsupported type passed for argument "device"') 86 raise ValueError('Unsupported type passed for argument "device"')
87 self._commands_installed = False
75 self._default_timeout = default_timeout 88 self._default_timeout = default_timeout
76 self._default_retries = default_retries 89 self._default_retries = default_retries
77 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) 90 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR))
78 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) 91 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR))
79 92
80 @decorators.WithTimeoutAndRetriesFromInstance() 93 @decorators.WithTimeoutAndRetriesFromInstance()
81 def IsOnline(self, timeout=None, retries=None): 94 def IsOnline(self, timeout=None, retries=None):
82 """Checks whether the device is online. 95 """Checks whether the device is online.
83 96
84 Args: 97 Args:
85 timeout: timeout in seconds 98 timeout: timeout in seconds
86 retries: number of retries 99 retries: number of retries
87 100
88 Returns: 101 Returns:
89 True if the device is online, False otherwise. 102 True if the device is online, False otherwise.
90 103
91 Raises: 104 Raises:
92 CommandTimeoutError on timeout. 105 CommandTimeoutError on timeout.
93 """ 106 """
107 return self._IsOnlineImpl()
108
109 def _IsOnlineImpl(self):
94 return self.old_interface.IsOnline() 110 return self.old_interface.IsOnline()
95 111
96 @decorators.WithTimeoutAndRetriesFromInstance() 112 @decorators.WithTimeoutAndRetriesFromInstance()
97 def HasRoot(self, timeout=None, retries=None): 113 def HasRoot(self, timeout=None, retries=None):
98 """Checks whether or not adbd has root privileges. 114 """Checks whether or not adbd has root privileges.
99 115
100 Args: 116 Args:
101 timeout: timeout in seconds 117 timeout: timeout in seconds
102 retries: number of retries 118 retries: number of retries
103 119
104 Returns: 120 Returns:
105 True if adbd has root privileges, False otherwise. 121 True if adbd has root privileges, False otherwise.
106 122
107 Raises: 123 Raises:
108 CommandTimeoutError on timeout. 124 CommandTimeoutError on timeout.
109 DeviceUnreachableError on missing device. 125 DeviceUnreachableError on missing device.
110 """ 126 """
111 return self._HasRootImpl() 127 return self._HasRootImpl()
112 128
113 def _HasRootImpl(self): 129 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() 130 return self.old_interface.IsRootEnabled()
126 131
127 @decorators.WithTimeoutAndRetriesFromInstance() 132 @decorators.WithTimeoutAndRetriesFromInstance()
128 def EnableRoot(self, timeout=None, retries=None): 133 def EnableRoot(self, timeout=None, retries=None):
129 """Restarts adbd with root privileges. 134 """Restarts adbd with root privileges.
130 135
131 Args: 136 Args:
132 timeout: timeout in seconds 137 timeout: timeout in seconds
133 retries: number of retries 138 retries: number of retries
134 139
(...skipping 14 matching lines...) Expand all
149 retries: number of retries 154 retries: number of retries
150 155
151 Returns: 156 Returns:
152 The device's path to its SD card. 157 The device's path to its SD card.
153 158
154 Raises: 159 Raises:
155 CommandFailedError if the external storage path could not be determined. 160 CommandFailedError if the external storage path could not be determined.
156 CommandTimeoutError on timeout. 161 CommandTimeoutError on timeout.
157 DeviceUnreachableError on missing device. 162 DeviceUnreachableError on missing device.
158 """ 163 """
164 return self._GetExternalStoragePathImpl()
165
166 def _GetExternalStoragePathImpl(self):
159 try: 167 try:
160 return self.old_interface.GetExternalStorage() 168 return self.old_interface.GetExternalStorage()
161 except AssertionError as e: 169 except AssertionError as e:
162 raise device_errors.CommandFailedError( 170 raise device_errors.CommandFailedError(
163 str(e), device=str(self)), None, sys.exc_info()[2] 171 str(e), device=str(self)), None, sys.exc_info()[2]
164 172
165 @decorators.WithTimeoutAndRetriesFromInstance() 173 @decorators.WithTimeoutAndRetriesFromInstance()
166 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): 174 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
167 """Wait for the device to fully boot. 175 """Wait for the device to fully boot.
168 176
169 This means waiting for the device to boot, the package manager to be 177 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 178 available, and the SD card to be ready. It can optionally mean waiting
171 for wifi to come up, too. 179 for wifi to come up, too.
172 180
173 Args: 181 Args:
174 wifi: A boolean indicating if we should wait for wifi to come up or not. 182 wifi: A boolean indicating if we should wait for wifi to come up or not.
175 timeout: timeout in seconds 183 timeout: timeout in seconds
176 retries: number of retries 184 retries: number of retries
177 185
178 Raises: 186 Raises:
179 CommandFailedError on failure. 187 CommandFailedError on failure.
180 CommandTimeoutError if one of the component waits times out. 188 CommandTimeoutError if one of the component waits times out.
181 DeviceUnreachableError if the device becomes unresponsive. 189 DeviceUnreachableError if the device becomes unresponsive.
182 """ 190 """
183 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) 191 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout)
184 192
185 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): 193 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: 194 if timeout is None:
202 timeout = self._default_timeout 195 timeout = self._default_timeout
203 self.old_interface.WaitForSystemBootCompleted(timeout) 196 self.old_interface.WaitForSystemBootCompleted(timeout)
204 self.old_interface.WaitForDevicePm() 197 self.old_interface.WaitForDevicePm()
205 self.old_interface.WaitForSdCardReady(timeout) 198 self.old_interface.WaitForSdCardReady(timeout)
206 if wifi: 199 if wifi:
207 while not 'Wi-Fi is enabled' in ( 200 while not 'Wi-Fi is enabled' in (
208 self._RunShellCommandImpl('dumpsys wifi')): 201 self._RunShellCommandImpl('dumpsys wifi')):
209 time.sleep(1) 202 time.sleep(1)
210 203
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 out = self.old_interface.Install(apk_path, reinstall=reinstall) 267 out = self.old_interface.Install(apk_path, reinstall=reinstall)
275 for line in out.splitlines(): 268 for line in out.splitlines():
276 if 'Failure' in line: 269 if 'Failure' in line:
277 raise device_errors.CommandFailedError( 270 raise device_errors.CommandFailedError(
278 line.strip(), device=str(self)) 271 line.strip(), device=str(self))
279 except AssertionError as e: 272 except AssertionError as e:
280 raise device_errors.CommandFailedError( 273 raise device_errors.CommandFailedError(
281 str(e), device=str(self)), None, sys.exc_info()[2] 274 str(e), device=str(self)), None, sys.exc_info()[2]
282 275
283 @decorators.WithTimeoutAndRetriesFromInstance() 276 @decorators.WithTimeoutAndRetriesFromInstance()
284 def RunShellCommand(self, cmd, check_return=False, as_root=False, 277 def RunShellCommand(self, cmd, check_return=False, as_root=False, cwd=None,
285 timeout=None, retries=None): 278 env=None, timeout=None, retries=None):
286 """Run an ADB shell command. 279 """Run an ADB shell command.
287 280
288 TODO(jbudorick) Switch the default value of check_return to True after 281 TODO(jbudorick) Switch the default value of check_return to True after
289 AndroidCommands is gone. 282 AndroidCommands is gone.
290 283
291 Args: 284 Args:
292 cmd: A list containing the command to run on the device and any arguments. 285 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 286 check_return: A boolean indicating whether or not the return code should
294 be checked. 287 be checked.
295 as_root: A boolean indicating whether the shell command should be run 288 as_root: A boolean indicating whether the shell command should be run
296 with root privileges. 289 with root privileges.
290 cwd: The device directory in which the command should be run.
291 env: The environment variables with which the command should be run.
297 timeout: timeout in seconds 292 timeout: timeout in seconds
298 retries: number of retries 293 retries: number of retries
299 294
300 Returns: 295 Returns:
301 The output of the command. 296 The output of the command.
302 297
303 Raises: 298 Raises:
304 CommandFailedError if check_return is True and the return code is nozero. 299 CommandFailedError if check_return is True and the return code is nozero.
305 CommandTimeoutError on timeout. 300 CommandTimeoutError on timeout.
306 DeviceUnreachableError on missing device. 301 DeviceUnreachableError on missing device.
307 """ 302 """
308 return self._RunShellCommandImpl(cmd, check_return=check_return, 303 return self._RunShellCommandImpl(
309 as_root=as_root, timeout=timeout) 304 cmd, check_return=check_return, as_root=as_root, cwd=cwd, env=env,
305 timeout=timeout)
310 306
311 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, 307 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False,
312 timeout=None): 308 cwd=None, env=None, timeout=None):
313 """Implementation of RunShellCommand. 309 # TODO(jbudorick): Remove the timeout parameter once this is no longer
314 310 # 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): 311 if isinstance(cmd, list):
334 cmd = ' '.join(cmd) 312 cmd = ' '.join(cmd)
335 if as_root and not self.HasRoot(): 313 if as_root and not self._HasRootImpl():
336 cmd = 'su -c %s' % cmd 314 cmd = 'su -c %s' % cmd
315 if env:
316 cmd = '%s %s' % (
317 ' '.join('%s=%s' % (k, v) for k, v in env.iteritems()), cmd)
318 if cwd:
319 cmd = 'cd %s && %s' % (cwd, cmd)
337 if check_return: 320 if check_return:
338 code, output = self.old_interface.GetShellCommandStatusAndOutput( 321 code, output = self.old_interface.GetShellCommandStatusAndOutput(
339 cmd, timeout_time=timeout) 322 cmd, timeout_time=timeout)
340 if int(code) != 0: 323 if int(code) != 0:
341 raise device_errors.AdbCommandFailedError( 324 raise device_errors.AdbCommandFailedError(
342 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) 325 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self))
343 else: 326 else:
344 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) 327 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout)
345 return output 328 return output
346 329
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after
494 DeviceUnreachableError on missing device. 477 DeviceUnreachableError on missing device.
495 """ 478 """
496 self.old_interface.SendKeyEvent(keycode) 479 self.old_interface.SendKeyEvent(keycode)
497 480
498 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT 481 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
499 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES 482 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES
500 483
501 @decorators.WithTimeoutAndRetriesDefaults( 484 @decorators.WithTimeoutAndRetriesDefaults(
502 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, 485 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT,
503 PUSH_CHANGED_FILES_DEFAULT_RETRIES) 486 PUSH_CHANGED_FILES_DEFAULT_RETRIES)
504 def PushChangedFiles(self, host_path, device_path, timeout=None, 487 def PushChangedFiles(self, host_device_tuples, timeout=None,
505 retries=None): 488 retries=None):
506 """Push files to the device, skipping files that don't need updating. 489 """Push files to the device, skipping files that don't need updating.
507 490
508 Args: 491 Args:
509 host_path: A string containing the absolute path to the file or directory 492 host_device_tuples: A list of (host_path, device_path) tuples, where
510 on the host that should be minimally pushed to the device. 493 |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 494 that should be minimially pushed to the device, and |device_path| is
512 the device. 495 an absolute path of the destination on the device.
513 timeout: timeout in seconds 496 timeout: timeout in seconds
514 retries: number of retries 497 retries: number of retries
515 498
516 Raises: 499 Raises:
517 CommandFailedError on failure. 500 CommandFailedError on failure.
518 CommandTimeoutError on timeout. 501 CommandTimeoutError on timeout.
519 DeviceUnreachableError on missing device. 502 DeviceUnreachableError on missing device.
520 """ 503 """
521 self.old_interface.PushIfNeeded(host_path, device_path) 504
505 files = []
506 for h, d in host_device_tuples:
507 if os.path.isdir(h) and not self._FileExistsImpl(d):
508 self._RunShellCommandImpl(['mkdir', '-p', '"%s"' % d],
cjhopman 2014/10/09 17:50:23 It's may be a little faster to just unconditionall
jbudorick 2014/10/09 19:26:40 dropped the _FileExistsImpl call
509 check_return=True)
510 files += self.old_interface.GetFilesChanged(h, d)
511
512 if not files:
513 return
514
515 size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
516 file_count = len(files)
517 dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
518 for h, _ in host_device_tuples)
519 dir_file_count = 0
520 for h, _ in host_device_tuples:
521 if os.path.isdir(h):
522 dir_file_count += sum(len(f) for _r, _d, f in os.walk(h))
523 else:
524 dir_file_count += 1
525
526 push_duration = self._ApproximateDuration(
527 file_count, file_count, size, False)
528 dir_push_duration = self._ApproximateDuration(
529 len(host_device_tuples), dir_file_count, dir_size, False)
530 zip_duration = self._ApproximateDuration(1, 1, size, True)
531
532 if dir_push_duration < push_duration and dir_push_duration < zip_duration:
533 self._PushChangedFilesIndividually(host_device_tuples)
534 elif push_duration < zip_duration:
535 self._PushChangedFilesIndividually(files)
536 else:
537 self._PushChangedFilesZipped(files)
538 self._RunShellCommandImpl(
539 ['chmod', '-R', '777'] + [d for _, d in host_device_tuples],
540 as_root=True)
541
542 @staticmethod
543 def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
544 # We approximate the time to push a set of files to a device as:
545 # t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
546 # t: total time (sec)
547 # c1: adb call time delay (sec)
548 # a: number of times adb is called (unitless)
549 # c2: push time delay (sec)
550 # f: number of files pushed via adb (unitless)
551 # c3: zip time delay (sec)
552 # c4: zip rate (bytes/sec)
553 # b: total number of bytes (bytes)
554 # c5: transfer rate (bytes/sec)
555 # c6: compression ratio (unitless)
556
557 # All of these are approximations.
558 ADB_CALL_PENALTY = 0.1 # seconds
559 ADB_PUSH_PENALTY = 0.01 # seconds
560 ZIP_PENALTY = 2.0 # seconds
561 ZIP_RATE = 10000000.0 # bytes / second
562 TRANSFER_RATE = 2000000.0 # bytes / second
563 COMPRESSION_RATIO = 2.0 # unitless
564
565 adb_call_time = ADB_CALL_PENALTY * adb_calls
566 adb_push_setup_time = ADB_PUSH_PENALTY * file_count
567 if is_zipping:
568 zip_time = ZIP_PENALTY + byte_count / ZIP_RATE
569 transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
570 else:
571 zip_time = 0
572 transfer_time = byte_count / TRANSFER_RATE
573 return (adb_call_time + adb_push_setup_time + zip_time + transfer_time)
574
575 def _PushChangedFilesIndividually(self, files):
576 for h, d in files:
577 self.adb.Push(h, d)
578
579 def _PushChangedFilesZipped(self, files):
580 if not files:
581 return
582
583 self._InstallCommands()
584 zip_dir = tempfile.mkdtemp()
cjhopman 2014/10/09 17:50:23 this can use tempfile.NamedTemporaryFile for the z
jbudorick 2014/10/09 19:26:40 What I actually want is a temporary file _name_, n
cjhopman 2014/10/09 20:27:39 You can actually do: with tempfile.NamedTemporary
jbudorick 2014/10/10 09:33:47 I was thinking python would choke on having the sa
585 try:
586 zip_path = os.path.abspath(os.path.join(zip_dir, 'tmp.zip'))
587
588 zip_proc = multiprocessing.Process(
589 target=DeviceUtils._CreateDeviceZip,
590 args=(zip_path, files))
591 zip_proc.start()
592 zip_proc.join()
593
594 zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl()
595 try:
596 self.adb.Push(zip_path, zip_on_device)
597 self._RunShellCommandImpl(
598 ['unzip', zip_on_device],
599 as_root=True, check_return=True,
600 env={'PATH': '$PATH:%s' % install_commands.BIN_DIR})
601 finally:
602 if zip_proc.is_alive():
603 zip_proc.terminate()
604 if self._IsOnlineImpl():
605 self._RunShellCommandImpl(['rm', zip_on_device])
606 finally:
607 shutil.rmtree(zip_dir)
608
609 def _InstallCommands(self):
610 if not self._commands_installed and not install_commands.Installed(self):
611 install_commands.InstallCommands(self)
612 self._commands_installed = True
613
614 @staticmethod
615 def _CreateDeviceZip(zip_path, host_device_tuples):
616 with zipfile.ZipFile(zip_path, 'w') as zip_file:
617 def AddDirectory(z, h, d):
618 z.write(h, d, zipfile.ZIP_STORED)
619 for i in os.listdir(h):
620 hi = os.path.join(h, i)
621 di = '%s/%s' % (d, i)
622 if os.path.isdir(i):
623 AddDirectory(z, hi, di)
624 else:
625 z.write(hi, di, zipfile.ZIP_DEFLATED)
626
627 for host_path, device_path in host_device_tuples:
cjhopman 2014/10/09 17:50:23 I think this would be simpler with os.walk. somet
jbudorick 2014/10/09 19:26:40 Done with some tweaks.
628 if os.path.isdir(host_path):
629 AddDirectory(zip_file, host_path, device_path)
630 else:
631 zip_file.write(host_path, device_path, zipfile.ZIP_DEFLATED)
522 632
523 @decorators.WithTimeoutAndRetriesFromInstance() 633 @decorators.WithTimeoutAndRetriesFromInstance()
524 def FileExists(self, device_path, timeout=None, retries=None): 634 def FileExists(self, device_path, timeout=None, retries=None):
525 """Checks whether the given file exists on the device. 635 """Checks whether the given file exists on the device.
526 636
527 Args: 637 Args:
528 device_path: A string containing the absolute path to the file on the 638 device_path: A string containing the absolute path to the file on the
529 device. 639 device.
530 timeout: timeout in seconds 640 timeout: timeout in seconds
531 retries: number of retries 641 retries: number of retries
532 642
533 Returns: 643 Returns:
534 True if the file exists on the device, False otherwise. 644 True if the file exists on the device, False otherwise.
535 645
536 Raises: 646 Raises:
537 CommandTimeoutError on timeout. 647 CommandTimeoutError on timeout.
538 DeviceUnreachableError on missing device. 648 DeviceUnreachableError on missing device.
539 """ 649 """
540 return self._FileExistsImpl(device_path) 650 return self._FileExistsImpl(device_path)
541 651
542 def _FileExistsImpl(self, device_path): 652 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) 653 return self.old_interface.FileExistsOnDevice(device_path)
558 654
559 @decorators.WithTimeoutAndRetriesFromInstance() 655 @decorators.WithTimeoutAndRetriesFromInstance()
560 def PullFile(self, device_path, host_path, timeout=None, retries=None): 656 def PullFile(self, device_path, host_path, timeout=None, retries=None):
561 """Pull a file from the device. 657 """Pull a file from the device.
562 658
563 Args: 659 Args:
564 device_path: A string containing the absolute path of the file to pull 660 device_path: A string containing the absolute path of the file to pull
565 from the device. 661 from the device.
566 host_path: A string containing the absolute path of the destination on 662 host_path: A string containing the absolute path of the destination on
(...skipping 24 matching lines...) Expand all
591 retries: number of retries 687 retries: number of retries
592 688
593 Returns: 689 Returns:
594 The contents of the file at |device_path| as a list of lines. 690 The contents of the file at |device_path| as a list of lines.
595 691
596 Raises: 692 Raises:
597 CommandFailedError if the file can't be read. 693 CommandFailedError if the file can't be read.
598 CommandTimeoutError on timeout. 694 CommandTimeoutError on timeout.
599 DeviceUnreachableError on missing device. 695 DeviceUnreachableError on missing device.
600 """ 696 """
601 # TODO(jbudorick) Evaluate whether we awant to return a list of lines after 697 # 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. 698 # the implementation switch, and if file not found should raise exception.
603 if as_root: 699 if as_root:
604 if not self.old_interface.CanAccessProtectedFileContents(): 700 if not self.old_interface.CanAccessProtectedFileContents():
605 raise device_errors.CommandFailedError( 701 raise device_errors.CommandFailedError(
606 'Cannot read from %s with root privileges.' % device_path) 702 'Cannot read from %s with root privileges.' % device_path)
607 return self.old_interface.GetProtectedFileContents(device_path) 703 return self.old_interface.GetProtectedFileContents(device_path)
608 else: 704 else:
609 return self.old_interface.GetFileContents(device_path) 705 return self.old_interface.GetFileContents(device_path)
610 706
611 @decorators.WithTimeoutAndRetriesFromInstance() 707 @decorators.WithTimeoutAndRetriesFromInstance()
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
748 A dict mapping process name to PID for each process that contained the 844 A dict mapping process name to PID for each process that contained the
749 provided |process_name|. 845 provided |process_name|.
750 846
751 Raises: 847 Raises:
752 CommandTimeoutError on timeout. 848 CommandTimeoutError on timeout.
753 DeviceUnreachableError on missing device. 849 DeviceUnreachableError on missing device.
754 """ 850 """
755 return self._GetPidsImpl(process_name) 851 return self._GetPidsImpl(process_name)
756 852
757 def _GetPidsImpl(self, process_name): 853 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 = {} 854 procs_pids = {}
774 for line in self._RunShellCommandImpl('ps'): 855 for line in self._RunShellCommandImpl('ps'):
775 try: 856 try:
776 ps_data = line.split() 857 ps_data = line.split()
777 if process_name in ps_data[-1]: 858 if process_name in ps_data[-1]:
778 procs_pids[ps_data[-1]] = ps_data[1] 859 procs_pids[ps_data[-1]] = ps_data[1]
779 except IndexError: 860 except IndexError:
780 pass 861 pass
781 return procs_pids 862 return procs_pids
782 863
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
863 A Parallelizer operating over |devices|. 944 A Parallelizer operating over |devices|.
864 """ 945 """
865 if not devices or len(devices) == 0: 946 if not devices or len(devices) == 0:
866 devices = pylib.android_commands.GetAttachedDevices() 947 devices = pylib.android_commands.GetAttachedDevices()
867 parallelizer_type = (parallelizer.Parallelizer if async 948 parallelizer_type = (parallelizer.Parallelizer if async
868 else parallelizer.SyncParallelizer) 949 else parallelizer.SyncParallelizer)
869 return parallelizer_type([ 950 return parallelizer_type([
870 d if isinstance(d, DeviceUtils) else DeviceUtils(d) 951 d if isinstance(d, DeviceUtils) else DeviceUtils(d)
871 for d in devices]) 952 for d in devices])
872 953
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698