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

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

Issue 1314913009: [Android] Move some pylib modules into devil/ (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 5 years, 3 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 2013 The Chromium Authors. All rights reserved. 1 # Copyright 2015 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 """This module wraps Android's adb tool. 5 # pylint: disable=unused-wildcard-import
6 # pylint: disable=wildcard-import
6 7
7 This is a thin wrapper around the adb interface. Any additional complexity 8 from devil.android.sdk.adb_wrapper import *
8 should be delegated to a higher level (ex. DeviceUtils).
9 """
10
11 import collections
12 import errno
13 import logging
14 import os
15 import re
16
17 from pylib import cmd_helper
18 from pylib import constants
19 from pylib.device import decorators
20 from pylib.device import device_errors
21 from pylib.utils import timeout_retry
22
23
24 _DEFAULT_TIMEOUT = 30
25 _DEFAULT_RETRIES = 2
26
27 _EMULATOR_RE = re.compile(r'^emulator-[0-9]+$')
28
29 _READY_STATE = 'device'
30
31
32 def _VerifyLocalFileExists(path):
33 """Verifies a local file exists.
34
35 Args:
36 path: Path to the local file.
37
38 Raises:
39 IOError: If the file doesn't exist.
40 """
41 if not os.path.exists(path):
42 raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path)
43
44
45 DeviceStat = collections.namedtuple('DeviceStat',
46 ['st_mode', 'st_size', 'st_time'])
47
48
49 class AdbWrapper(object):
50 """A wrapper around a local Android Debug Bridge executable."""
51
52 def __init__(self, device_serial):
53 """Initializes the AdbWrapper.
54
55 Args:
56 device_serial: The device serial number as a string.
57 """
58 if not device_serial:
59 raise ValueError('A device serial must be specified')
60 self._device_serial = str(device_serial)
61
62 # pylint: disable=unused-argument
63 @classmethod
64 def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
65 if cpu_affinity is not None:
66 cmd = ['taskset', '-c', str(cpu_affinity)]
67 else:
68 cmd = []
69 cmd.append(constants.GetAdbPath())
70 if device_serial is not None:
71 cmd.extend(['-s', device_serial])
72 cmd.extend(args)
73 return cmd
74 # pylint: enable=unused-argument
75
76 # pylint: disable=unused-argument
77 @classmethod
78 @decorators.WithTimeoutAndRetries
79 def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
80 check_error=True, cpu_affinity=None):
81 status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
82 cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
83 timeout_retry.CurrentTimeoutThread().GetRemainingTime())
84 if status != 0:
85 raise device_errors.AdbCommandFailedError(
86 args, output, status, device_serial)
87 # This catches some errors, including when the device drops offline;
88 # unfortunately adb is very inconsistent with error reporting so many
89 # command failures present differently.
90 if check_error and output.startswith('error:'):
91 raise device_errors.AdbCommandFailedError(args, output)
92 return output
93 # pylint: enable=unused-argument
94
95 def _RunDeviceAdbCmd(self, args, timeout, retries, check_error=True):
96 """Runs an adb command on the device associated with this object.
97
98 Args:
99 args: A list of arguments to adb.
100 timeout: Timeout in seconds.
101 retries: Number of retries.
102 check_error: Check that the command doesn't return an error message. This
103 does NOT check the exit status of shell commands.
104
105 Returns:
106 The output of the command.
107 """
108 return self._RunAdbCmd(args, timeout=timeout, retries=retries,
109 device_serial=self._device_serial,
110 check_error=check_error)
111
112 def _IterRunDeviceAdbCmd(self, args, timeout):
113 """Runs an adb command and returns an iterator over its output lines.
114
115 Args:
116 args: A list of arguments to adb.
117 timeout: Timeout in seconds.
118
119 Yields:
120 The output of the command line by line.
121 """
122 return cmd_helper.IterCmdOutputLines(
123 self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
124
125 def __eq__(self, other):
126 """Consider instances equal if they refer to the same device.
127
128 Args:
129 other: The instance to compare equality with.
130
131 Returns:
132 True if the instances are considered equal, false otherwise.
133 """
134 return self._device_serial == str(other)
135
136 def __str__(self):
137 """The string representation of an instance.
138
139 Returns:
140 The device serial number as a string.
141 """
142 return self._device_serial
143
144 def __repr__(self):
145 return '%s(\'%s\')' % (self.__class__.__name__, self)
146
147 # pylint: disable=unused-argument
148 @classmethod
149 def IsServerOnline(cls):
150 status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
151 output = [int(x) for x in output.split()]
152 logging.info('PIDs for adb found: %r', output)
153 return status == 0
154 # pylint: enable=unused-argument
155
156 @classmethod
157 def KillServer(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
158 cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries)
159
160 @classmethod
161 def StartServer(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
162 # CPU affinity is used to reduce adb instability http://crbug.com/268450
163 cls._RunAdbCmd(['start-server'], timeout=timeout, retries=retries,
164 cpu_affinity=0)
165
166 @classmethod
167 def GetDevices(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
168 """DEPRECATED. Refer to Devices(...) below."""
169 # TODO(jbudorick): Remove this function once no more clients are using it.
170 return cls.Devices(timeout=timeout, retries=retries)
171
172 @classmethod
173 def Devices(cls, desired_state=_READY_STATE, long_list=False,
174 timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
175 """Get the list of active attached devices.
176
177 Args:
178 desired_state: If not None, limit the devices returned to only those
179 in the given state.
180 long_list: Whether to use the long listing format.
181 timeout: (optional) Timeout per try in seconds.
182 retries: (optional) Number of retries to attempt.
183
184 Yields:
185 AdbWrapper instances.
186 """
187 lines = cls._RawDevices(long_list=long_list, timeout=timeout,
188 retries=retries)
189 return [AdbWrapper(line[0]) for line in lines
190 if ((long_list or len(line) == 2)
191 and (not desired_state or line[1] == desired_state))]
192
193 @classmethod
194 def _RawDevices(cls, long_list=False, timeout=_DEFAULT_TIMEOUT,
195 retries=_DEFAULT_RETRIES):
196 cmd = ['devices']
197 if long_list:
198 cmd.append('-l')
199 output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries)
200 return [line.split() for line in output.splitlines()[1:]]
201
202 def GetDeviceSerial(self):
203 """Gets the device serial number associated with this object.
204
205 Returns:
206 Device serial number as a string.
207 """
208 return self._device_serial
209
210 def Push(self, local, remote, timeout=60*5, retries=_DEFAULT_RETRIES):
211 """Pushes a file from the host to the device.
212
213 Args:
214 local: Path on the host filesystem.
215 remote: Path on the device filesystem.
216 timeout: (optional) Timeout per try in seconds.
217 retries: (optional) Number of retries to attempt.
218 """
219 _VerifyLocalFileExists(local)
220 self._RunDeviceAdbCmd(['push', local, remote], timeout, retries)
221
222 def Pull(self, remote, local, timeout=60*5, retries=_DEFAULT_RETRIES):
223 """Pulls a file from the device to the host.
224
225 Args:
226 remote: Path on the device filesystem.
227 local: Path on the host filesystem.
228 timeout: (optional) Timeout per try in seconds.
229 retries: (optional) Number of retries to attempt.
230 """
231 cmd = ['pull', remote, local]
232 self._RunDeviceAdbCmd(cmd, timeout, retries)
233 try:
234 _VerifyLocalFileExists(local)
235 except IOError:
236 raise device_errors.AdbCommandFailedError(
237 cmd, 'File not found on host: %s' % local, device_serial=str(self))
238
239 def Shell(self, command, expect_status=0, timeout=_DEFAULT_TIMEOUT,
240 retries=_DEFAULT_RETRIES):
241 """Runs a shell command on the device.
242
243 Args:
244 command: A string with the shell command to run.
245 expect_status: (optional) Check that the command's exit status matches
246 this value. Default is 0. If set to None the test is skipped.
247 timeout: (optional) Timeout per try in seconds.
248 retries: (optional) Number of retries to attempt.
249
250 Returns:
251 The output of the shell command as a string.
252
253 Raises:
254 device_errors.AdbCommandFailedError: If the exit status doesn't match
255 |expect_status|.
256 """
257 if expect_status is None:
258 args = ['shell', command]
259 else:
260 args = ['shell', '(%s);echo %%$?' % command.rstrip()]
261 output = self._RunDeviceAdbCmd(args, timeout, retries, check_error=False)
262 if expect_status is not None:
263 output_end = output.rfind('%')
264 if output_end < 0:
265 # causes the status string to become empty and raise a ValueError
266 output_end = len(output)
267
268 try:
269 status = int(output[output_end+1:])
270 except ValueError:
271 logging.warning('exit status of shell command %r missing.', command)
272 raise device_errors.AdbShellCommandFailedError(
273 command, output, status=None, device_serial=self._device_serial)
274 output = output[:output_end]
275 if status != expect_status:
276 raise device_errors.AdbShellCommandFailedError(
277 command, output, status=status, device_serial=self._device_serial)
278 return output
279
280 def IterShell(self, command, timeout):
281 """Runs a shell command and returns an iterator over its output lines.
282
283 Args:
284 command: A string with the shell command to run.
285 timeout: Timeout in seconds.
286
287 Yields:
288 The output of the command line by line.
289 """
290 args = ['shell', command]
291 return cmd_helper.IterCmdOutputLines(
292 self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
293
294 def Ls(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
295 """List the contents of a directory on the device.
296
297 Args:
298 path: Path on the device filesystem.
299 timeout: (optional) Timeout per try in seconds.
300 retries: (optional) Number of retries to attempt.
301
302 Returns:
303 A list of pairs (filename, stat) for each file found in the directory,
304 where the stat object has the properties: st_mode, st_size, and st_time.
305
306 Raises:
307 AdbCommandFailedError if |path| does not specify a valid and accessible
308 directory in the device.
309 """
310 def ParseLine(line):
311 cols = line.split(None, 3)
312 filename = cols.pop()
313 stat = DeviceStat(*[int(num, base=16) for num in cols])
314 return (filename, stat)
315
316 cmd = ['ls', path]
317 lines = self._RunDeviceAdbCmd(
318 cmd, timeout=timeout, retries=retries).splitlines()
319 if lines:
320 return [ParseLine(line) for line in lines]
321 else:
322 raise device_errors.AdbCommandFailedError(
323 cmd, 'path does not specify an accessible directory in the device',
324 device_serial=self._device_serial)
325
326 def Logcat(self, clear=False, dump=False, filter_specs=None,
327 logcat_format=None, ring_buffer=None, timeout=None,
328 retries=_DEFAULT_RETRIES):
329 """Get an iterable over the logcat output.
330
331 Args:
332 clear: If true, clear the logcat.
333 dump: If true, dump the current logcat contents.
334 filter_specs: If set, a list of specs to filter the logcat.
335 logcat_format: If set, the format in which the logcat should be output.
336 Options include "brief", "process", "tag", "thread", "raw", "time",
337 "threadtime", and "long"
338 ring_buffer: If set, a list of alternate ring buffers to request.
339 Options include "main", "system", "radio", "events", "crash" or "all".
340 The default is equivalent to ["main", "system", "crash"].
341 timeout: (optional) If set, timeout per try in seconds. If clear or dump
342 is set, defaults to _DEFAULT_TIMEOUT.
343 retries: (optional) If clear or dump is set, the number of retries to
344 attempt. Otherwise, does nothing.
345
346 Yields:
347 logcat output line by line.
348 """
349 cmd = ['logcat']
350 use_iter = True
351 if clear:
352 cmd.append('-c')
353 use_iter = False
354 if dump:
355 cmd.append('-d')
356 use_iter = False
357 if logcat_format:
358 cmd.extend(['-v', logcat_format])
359 if ring_buffer:
360 for buffer_name in ring_buffer:
361 cmd.extend(['-b', buffer_name])
362 if filter_specs:
363 cmd.extend(filter_specs)
364
365 if use_iter:
366 return self._IterRunDeviceAdbCmd(cmd, timeout)
367 else:
368 timeout = timeout if timeout is not None else _DEFAULT_TIMEOUT
369 return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()
370
371 def Forward(self, local, remote, timeout=_DEFAULT_TIMEOUT,
372 retries=_DEFAULT_RETRIES):
373 """Forward socket connections from the local socket to the remote socket.
374
375 Sockets are specified by one of:
376 tcp:<port>
377 localabstract:<unix domain socket name>
378 localreserved:<unix domain socket name>
379 localfilesystem:<unix domain socket name>
380 dev:<character device name>
381 jdwp:<process pid> (remote only)
382
383 Args:
384 local: The host socket.
385 remote: The device socket.
386 timeout: (optional) Timeout per try in seconds.
387 retries: (optional) Number of retries to attempt.
388 """
389 self._RunDeviceAdbCmd(['forward', str(local), str(remote)], timeout,
390 retries)
391
392 def ForwardRemove(self, local, timeout=_DEFAULT_TIMEOUT,
393 retries=_DEFAULT_RETRIES):
394 """Remove a forward socket connection.
395
396 Args:
397 local: The host socket.
398 timeout: (optional) Timeout per try in seconds.
399 retries: (optional) Number of retries to attempt.
400 """
401 self._RunDeviceAdbCmd(['forward', '--remove', str(local)], timeout,
402 retries)
403
404 def ForwardList(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
405 """List all currently forwarded socket connections.
406
407 Args:
408 timeout: (optional) Timeout per try in seconds.
409 retries: (optional) Number of retries to attempt.
410 """
411 return self._RunDeviceAdbCmd(['forward', '--list'], timeout, retries)
412
413 def JDWP(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
414 """List of PIDs of processes hosting a JDWP transport.
415
416 Args:
417 timeout: (optional) Timeout per try in seconds.
418 retries: (optional) Number of retries to attempt.
419
420 Returns:
421 A list of PIDs as strings.
422 """
423 return [a.strip() for a in
424 self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
425
426 def Install(self, apk_path, forward_lock=False, reinstall=False,
427 sd_card=False, timeout=60*2, retries=_DEFAULT_RETRIES):
428 """Install an apk on the device.
429
430 Args:
431 apk_path: Host path to the APK file.
432 forward_lock: (optional) If set forward-locks the app.
433 reinstall: (optional) If set reinstalls the app, keeping its data.
434 sd_card: (optional) If set installs on the SD card.
435 timeout: (optional) Timeout per try in seconds.
436 retries: (optional) Number of retries to attempt.
437 """
438 _VerifyLocalFileExists(apk_path)
439 cmd = ['install']
440 if forward_lock:
441 cmd.append('-l')
442 if reinstall:
443 cmd.append('-r')
444 if sd_card:
445 cmd.append('-s')
446 cmd.append(apk_path)
447 output = self._RunDeviceAdbCmd(cmd, timeout, retries)
448 if 'Success' not in output:
449 raise device_errors.AdbCommandFailedError(
450 cmd, output, device_serial=self._device_serial)
451
452 def InstallMultiple(self, apk_paths, forward_lock=False, reinstall=False,
453 sd_card=False, allow_downgrade=False, partial=False,
454 timeout=60*2, retries=_DEFAULT_RETRIES):
455 """Install an apk with splits on the device.
456
457 Args:
458 apk_paths: Host path to the APK file.
459 forward_lock: (optional) If set forward-locks the app.
460 reinstall: (optional) If set reinstalls the app, keeping its data.
461 sd_card: (optional) If set installs on the SD card.
462 timeout: (optional) Timeout per try in seconds.
463 retries: (optional) Number of retries to attempt.
464 allow_downgrade: (optional) Allow versionCode downgrade.
465 partial: (optional) Package ID if apk_paths doesn't include all .apks.
466 """
467 for path in apk_paths:
468 _VerifyLocalFileExists(path)
469 cmd = ['install-multiple']
470 if forward_lock:
471 cmd.append('-l')
472 if reinstall:
473 cmd.append('-r')
474 if sd_card:
475 cmd.append('-s')
476 if allow_downgrade:
477 cmd.append('-d')
478 if partial:
479 cmd.extend(('-p', partial))
480 cmd.extend(apk_paths)
481 output = self._RunDeviceAdbCmd(cmd, timeout, retries)
482 if 'Success' not in output:
483 raise device_errors.AdbCommandFailedError(
484 cmd, output, device_serial=self._device_serial)
485
486 def Uninstall(self, package, keep_data=False, timeout=_DEFAULT_TIMEOUT,
487 retries=_DEFAULT_RETRIES):
488 """Remove the app |package| from the device.
489
490 Args:
491 package: The package to uninstall.
492 keep_data: (optional) If set keep the data and cache directories.
493 timeout: (optional) Timeout per try in seconds.
494 retries: (optional) Number of retries to attempt.
495 """
496 cmd = ['uninstall']
497 if keep_data:
498 cmd.append('-k')
499 cmd.append(package)
500 output = self._RunDeviceAdbCmd(cmd, timeout, retries)
501 if 'Failure' in output:
502 raise device_errors.AdbCommandFailedError(
503 cmd, output, device_serial=self._device_serial)
504
505 def Backup(self, path, packages=None, apk=False, shared=False,
506 nosystem=True, include_all=False, timeout=_DEFAULT_TIMEOUT,
507 retries=_DEFAULT_RETRIES):
508 """Write an archive of the device's data to |path|.
509
510 Args:
511 path: Local path to store the backup file.
512 packages: List of to packages to be backed up.
513 apk: (optional) If set include the .apk files in the archive.
514 shared: (optional) If set buckup the device's SD card.
515 nosystem: (optional) If set exclude system applications.
516 include_all: (optional) If set back up all installed applications and
517 |packages| is optional.
518 timeout: (optional) Timeout per try in seconds.
519 retries: (optional) Number of retries to attempt.
520 """
521 cmd = ['backup', '-f', path]
522 if apk:
523 cmd.append('-apk')
524 if shared:
525 cmd.append('-shared')
526 if nosystem:
527 cmd.append('-nosystem')
528 if include_all:
529 cmd.append('-all')
530 if packages:
531 cmd.extend(packages)
532 assert bool(packages) ^ bool(include_all), (
533 'Provide \'packages\' or set \'include_all\' but not both.')
534 ret = self._RunDeviceAdbCmd(cmd, timeout, retries)
535 _VerifyLocalFileExists(path)
536 return ret
537
538 def Restore(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
539 """Restore device contents from the backup archive.
540
541 Args:
542 path: Host path to the backup archive.
543 timeout: (optional) Timeout per try in seconds.
544 retries: (optional) Number of retries to attempt.
545 """
546 _VerifyLocalFileExists(path)
547 self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries)
548
549 def WaitForDevice(self, timeout=60*5, retries=_DEFAULT_RETRIES):
550 """Block until the device is online.
551
552 Args:
553 timeout: (optional) Timeout per try in seconds.
554 retries: (optional) Number of retries to attempt.
555 """
556 self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries)
557
558 def GetState(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
559 """Get device state.
560
561 Args:
562 timeout: (optional) Timeout per try in seconds.
563 retries: (optional) Number of retries to attempt.
564
565 Returns:
566 One of 'offline', 'bootloader', or 'device'.
567 """
568 # TODO(jbudorick): Revert to using get-state once it doesn't cause a
569 # a protocol fault.
570 # return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()
571
572 lines = self._RawDevices(timeout=timeout, retries=retries)
573 for line in lines:
574 if len(line) >= 2 and line[0] == self._device_serial:
575 return line[1]
576 return 'offline'
577
578
579 def GetDevPath(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
580 """Gets the device path.
581
582 Args:
583 timeout: (optional) Timeout per try in seconds.
584 retries: (optional) Number of retries to attempt.
585
586 Returns:
587 The device path (e.g. usb:3-4)
588 """
589 return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries)
590
591 def Remount(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
592 """Remounts the /system partition on the device read-write."""
593 self._RunDeviceAdbCmd(['remount'], timeout, retries)
594
595 def Reboot(self, to_bootloader=False, timeout=60*5,
596 retries=_DEFAULT_RETRIES):
597 """Reboots the device.
598
599 Args:
600 to_bootloader: (optional) If set reboots to the bootloader.
601 timeout: (optional) Timeout per try in seconds.
602 retries: (optional) Number of retries to attempt.
603 """
604 if to_bootloader:
605 cmd = ['reboot-bootloader']
606 else:
607 cmd = ['reboot']
608 self._RunDeviceAdbCmd(cmd, timeout, retries)
609
610 def Root(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
611 """Restarts the adbd daemon with root permissions, if possible.
612
613 Args:
614 timeout: (optional) Timeout per try in seconds.
615 retries: (optional) Number of retries to attempt.
616 """
617 output = self._RunDeviceAdbCmd(['root'], timeout, retries)
618 if 'cannot' in output:
619 raise device_errors.AdbCommandFailedError(
620 ['root'], output, device_serial=self._device_serial)
621
622 def Emu(self, cmd, timeout=_DEFAULT_TIMEOUT,
623 retries=_DEFAULT_RETRIES):
624 """Runs an emulator console command.
625
626 See http://developer.android.com/tools/devices/emulator.html#console
627
628 Args:
629 cmd: The command to run on the emulator console.
630 timeout: (optional) Timeout per try in seconds.
631 retries: (optional) Number of retries to attempt.
632
633 Returns:
634 The output of the emulator console command.
635 """
636 if isinstance(cmd, basestring):
637 cmd = [cmd]
638 return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries)
639
640 @property
641 def is_emulator(self):
642 return _EMULATOR_RE.match(self._device_serial)
643
644 @property
645 def is_ready(self):
646 try:
647 return self.GetState() == _READY_STATE
648 except device_errors.CommandFailedError:
649 return False
OLDNEW
« no previous file with comments | « build/android/pylib/constants/keyevent.py ('k') | build/android/pylib/device/adb_wrapper_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698