[Cronet] Delay StartNetLog and StopNetLog until native request context is initialized
[chromium-blink-merge.git] / build / android / pylib / device / adb_wrapper.py
blob36f8f484b00fbe2ec05c4c440ab13af10dde71f2
1 # Copyright 2013 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """This module wraps Android's adb tool.
7 This is a thin wrapper around the adb interface. Any additional complexity
8 should be delegated to a higher level (ex. DeviceUtils).
9 """
11 import collections
12 import errno
13 import logging
14 import os
16 from pylib import cmd_helper
17 from pylib import constants
18 from pylib.device import decorators
19 from pylib.device import device_errors
20 from pylib.utils import timeout_retry
23 _DEFAULT_TIMEOUT = 30
24 _DEFAULT_RETRIES = 2
27 def _VerifyLocalFileExists(path):
28 """Verifies a local file exists.
30 Args:
31 path: Path to the local file.
33 Raises:
34 IOError: If the file doesn't exist.
35 """
36 if not os.path.exists(path):
37 raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path)
40 DeviceStat = collections.namedtuple('DeviceStat',
41 ['st_mode', 'st_size', 'st_time'])
44 class AdbWrapper(object):
45 """A wrapper around a local Android Debug Bridge executable."""
47 def __init__(self, device_serial):
48 """Initializes the AdbWrapper.
50 Args:
51 device_serial: The device serial number as a string.
52 """
53 if not device_serial:
54 raise ValueError('A device serial must be specified')
55 self._device_serial = str(device_serial)
57 # pylint: disable=unused-argument
58 @classmethod
59 def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None):
60 if cpu_affinity is not None:
61 cmd = ['taskset', '-c', str(cpu_affinity)]
62 else:
63 cmd = []
64 cmd.append(constants.GetAdbPath())
65 if device_serial is not None:
66 cmd.extend(['-s', device_serial])
67 cmd.extend(args)
68 return cmd
69 # pylint: enable=unused-argument
71 # pylint: disable=unused-argument
72 @classmethod
73 @decorators.WithTimeoutAndRetries
74 def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None,
75 check_error=True, cpu_affinity=None):
76 status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout(
77 cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity),
78 timeout_retry.CurrentTimeoutThread().GetRemainingTime())
79 if status != 0:
80 raise device_errors.AdbCommandFailedError(
81 args, output, status, device_serial)
82 # This catches some errors, including when the device drops offline;
83 # unfortunately adb is very inconsistent with error reporting so many
84 # command failures present differently.
85 if check_error and output.startswith('error:'):
86 raise device_errors.AdbCommandFailedError(args, output)
87 return output
88 # pylint: enable=unused-argument
90 def _RunDeviceAdbCmd(self, args, timeout, retries, check_error=True):
91 """Runs an adb command on the device associated with this object.
93 Args:
94 args: A list of arguments to adb.
95 timeout: Timeout in seconds.
96 retries: Number of retries.
97 check_error: Check that the command doesn't return an error message. This
98 does NOT check the exit status of shell commands.
100 Returns:
101 The output of the command.
103 return self._RunAdbCmd(args, timeout=timeout, retries=retries,
104 device_serial=self._device_serial,
105 check_error=check_error)
107 def _IterRunDeviceAdbCmd(self, args, timeout):
108 """Runs an adb command and returns an iterator over its output lines.
110 Args:
111 args: A list of arguments to adb.
112 timeout: Timeout in seconds.
114 Yields:
115 The output of the command line by line.
117 return cmd_helper.IterCmdOutputLines(
118 self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
120 def __eq__(self, other):
121 """Consider instances equal if they refer to the same device.
123 Args:
124 other: The instance to compare equality with.
126 Returns:
127 True if the instances are considered equal, false otherwise.
129 return self._device_serial == str(other)
131 def __str__(self):
132 """The string representation of an instance.
134 Returns:
135 The device serial number as a string.
137 return self._device_serial
139 def __repr__(self):
140 return '%s(\'%s\')' % (self.__class__.__name__, self)
142 # pylint: disable=unused-argument
143 @classmethod
144 def IsServerOnline(cls):
145 status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb'])
146 output = [int(x) for x in output.split()]
147 logging.info('PIDs for adb found: %r', output)
148 return status == 0
149 # pylint: enable=unused-argument
151 @classmethod
152 def KillServer(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
153 cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries)
155 @classmethod
156 def StartServer(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
157 # CPU affinity is used to reduce adb instability http://crbug.com/268450
158 cls._RunAdbCmd(['start-server'], timeout=timeout, retries=retries,
159 cpu_affinity=0)
161 # TODO(craigdh): Determine the filter criteria that should be supported.
162 @classmethod
163 def GetDevices(cls, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
164 """Get the list of active attached devices.
166 Args:
167 timeout: (optional) Timeout per try in seconds.
168 retries: (optional) Number of retries to attempt.
170 Yields:
171 AdbWrapper instances.
173 output = cls._RunAdbCmd(['devices'], timeout=timeout, retries=retries)
174 lines = [line.split() for line in output.splitlines()]
175 return [AdbWrapper(line[0]) for line in lines
176 if len(line) == 2 and line[1] == 'device']
178 def GetDeviceSerial(self):
179 """Gets the device serial number associated with this object.
181 Returns:
182 Device serial number as a string.
184 return self._device_serial
186 def Push(self, local, remote, timeout=60*5, retries=_DEFAULT_RETRIES):
187 """Pushes a file from the host to the device.
189 Args:
190 local: Path on the host filesystem.
191 remote: Path on the device filesystem.
192 timeout: (optional) Timeout per try in seconds.
193 retries: (optional) Number of retries to attempt.
195 _VerifyLocalFileExists(local)
196 self._RunDeviceAdbCmd(['push', local, remote], timeout, retries)
198 def Pull(self, remote, local, timeout=60*5, retries=_DEFAULT_RETRIES):
199 """Pulls a file from the device to the host.
201 Args:
202 remote: Path on the device filesystem.
203 local: Path on the host filesystem.
204 timeout: (optional) Timeout per try in seconds.
205 retries: (optional) Number of retries to attempt.
207 cmd = ['pull', remote, local]
208 self._RunDeviceAdbCmd(cmd, timeout, retries)
209 try:
210 _VerifyLocalFileExists(local)
211 except IOError:
212 raise device_errors.AdbCommandFailedError(
213 cmd, 'File not found on host: %s' % local, device_serial=str(self))
215 def Shell(self, command, expect_status=0, timeout=_DEFAULT_TIMEOUT,
216 retries=_DEFAULT_RETRIES):
217 """Runs a shell command on the device.
219 Args:
220 command: A string with the shell command to run.
221 expect_status: (optional) Check that the command's exit status matches
222 this value. Default is 0. If set to None the test is skipped.
223 timeout: (optional) Timeout per try in seconds.
224 retries: (optional) Number of retries to attempt.
226 Returns:
227 The output of the shell command as a string.
229 Raises:
230 device_errors.AdbCommandFailedError: If the exit status doesn't match
231 |expect_status|.
233 if expect_status is None:
234 args = ['shell', command]
235 else:
236 args = ['shell', '%s; echo %%$?;' % command.rstrip()]
237 output = self._RunDeviceAdbCmd(args, timeout, retries, check_error=False)
238 if expect_status is not None:
239 output_end = output.rfind('%')
240 if output_end < 0:
241 # causes the status string to become empty and raise a ValueError
242 output_end = len(output)
244 try:
245 status = int(output[output_end+1:])
246 except ValueError:
247 logging.warning('exit status of shell command %r missing.', command)
248 raise device_errors.AdbShellCommandFailedError(
249 command, output, status=None, device_serial=self._device_serial)
250 output = output[:output_end]
251 if status != expect_status:
252 raise device_errors.AdbShellCommandFailedError(
253 command, output, status=status, device_serial=self._device_serial)
254 return output
256 def IterShell(self, command, timeout):
257 """Runs a shell command and returns an iterator over its output lines.
259 Args:
260 command: A string with the shell command to run.
261 timeout: Timeout in seconds.
263 Yields:
264 The output of the command line by line.
266 args = ['shell', command]
267 return cmd_helper.IterCmdOutputLines(
268 self._BuildAdbCmd(args, self._device_serial), timeout=timeout)
270 def Ls(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
271 """List the contents of a directory on the device.
273 Args:
274 path: Path on the device filesystem.
275 timeout: (optional) Timeout per try in seconds.
276 retries: (optional) Number of retries to attempt.
278 Returns:
279 A list of pairs (filename, stat) for each file found in the directory,
280 where the stat object has the properties: st_mode, st_size, and st_time.
282 Raises:
283 AdbCommandFailedError if |path| does not specify a valid and accessible
284 directory in the device.
286 def ParseLine(line):
287 cols = line.split(None, 3)
288 filename = cols.pop()
289 stat = DeviceStat(*[int(num, base=16) for num in cols])
290 return (filename, stat)
292 cmd = ['ls', path]
293 lines = self._RunDeviceAdbCmd(
294 cmd, timeout=timeout, retries=retries).splitlines()
295 if lines:
296 return [ParseLine(line) for line in lines]
297 else:
298 raise device_errors.AdbCommandFailedError(
299 cmd, 'path does not specify an accessible directory in the device',
300 device_serial=self._device_serial)
302 def Logcat(self, clear=False, dump=False, filter_specs=None,
303 logcat_format=None, ring_buffer=None, timeout=None,
304 retries=_DEFAULT_RETRIES):
305 """Get an iterable over the logcat output.
307 Args:
308 clear: If true, clear the logcat.
309 dump: If true, dump the current logcat contents.
310 filter_specs: If set, a list of specs to filter the logcat.
311 logcat_format: If set, the format in which the logcat should be output.
312 Options include "brief", "process", "tag", "thread", "raw", "time",
313 "threadtime", and "long"
314 ring_buffer: If set, a list of alternate ring buffers to request.
315 Options include "main", "system", "radio", "events", "crash" or "all".
316 The default is equivalent to ["main", "system", "crash"].
317 timeout: (optional) If set, timeout per try in seconds. If clear or dump
318 is set, defaults to _DEFAULT_TIMEOUT.
319 retries: (optional) If clear or dump is set, the number of retries to
320 attempt. Otherwise, does nothing.
322 Yields:
323 logcat output line by line.
325 cmd = ['logcat']
326 use_iter = True
327 if clear:
328 cmd.append('-c')
329 use_iter = False
330 if dump:
331 cmd.append('-d')
332 use_iter = False
333 if logcat_format:
334 cmd.extend(['-v', logcat_format])
335 if ring_buffer:
336 for buffer_name in ring_buffer:
337 cmd.extend(['-b', buffer_name])
338 if filter_specs:
339 cmd.extend(filter_specs)
341 if use_iter:
342 return self._IterRunDeviceAdbCmd(cmd, timeout)
343 else:
344 timeout = timeout if timeout is not None else _DEFAULT_TIMEOUT
345 return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()
347 def Forward(self, local, remote, timeout=_DEFAULT_TIMEOUT,
348 retries=_DEFAULT_RETRIES):
349 """Forward socket connections from the local socket to the remote socket.
351 Sockets are specified by one of:
352 tcp:<port>
353 localabstract:<unix domain socket name>
354 localreserved:<unix domain socket name>
355 localfilesystem:<unix domain socket name>
356 dev:<character device name>
357 jdwp:<process pid> (remote only)
359 Args:
360 local: The host socket.
361 remote: The device socket.
362 timeout: (optional) Timeout per try in seconds.
363 retries: (optional) Number of retries to attempt.
365 self._RunDeviceAdbCmd(['forward', str(local), str(remote)], timeout,
366 retries)
368 def JDWP(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
369 """List of PIDs of processes hosting a JDWP transport.
371 Args:
372 timeout: (optional) Timeout per try in seconds.
373 retries: (optional) Number of retries to attempt.
375 Returns:
376 A list of PIDs as strings.
378 return [a.strip() for a in
379 self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')]
381 def Install(self, apk_path, forward_lock=False, reinstall=False,
382 sd_card=False, timeout=60*2, retries=_DEFAULT_RETRIES):
383 """Install an apk on the device.
385 Args:
386 apk_path: Host path to the APK file.
387 forward_lock: (optional) If set forward-locks the app.
388 reinstall: (optional) If set reinstalls the app, keeping its data.
389 sd_card: (optional) If set installs on the SD card.
390 timeout: (optional) Timeout per try in seconds.
391 retries: (optional) Number of retries to attempt.
393 _VerifyLocalFileExists(apk_path)
394 cmd = ['install']
395 if forward_lock:
396 cmd.append('-l')
397 if reinstall:
398 cmd.append('-r')
399 if sd_card:
400 cmd.append('-s')
401 cmd.append(apk_path)
402 output = self._RunDeviceAdbCmd(cmd, timeout, retries)
403 if 'Success' not in output:
404 raise device_errors.AdbCommandFailedError(
405 cmd, output, device_serial=self._device_serial)
407 def Uninstall(self, package, keep_data=False, timeout=_DEFAULT_TIMEOUT,
408 retries=_DEFAULT_RETRIES):
409 """Remove the app |package| from the device.
411 Args:
412 package: The package to uninstall.
413 keep_data: (optional) If set keep the data and cache directories.
414 timeout: (optional) Timeout per try in seconds.
415 retries: (optional) Number of retries to attempt.
417 cmd = ['uninstall']
418 if keep_data:
419 cmd.append('-k')
420 cmd.append(package)
421 output = self._RunDeviceAdbCmd(cmd, timeout, retries)
422 if 'Failure' in output:
423 raise device_errors.AdbCommandFailedError(
424 cmd, output, device_serial=self._device_serial)
426 def Backup(self, path, packages=None, apk=False, shared=False,
427 nosystem=True, include_all=False, timeout=_DEFAULT_TIMEOUT,
428 retries=_DEFAULT_RETRIES):
429 """Write an archive of the device's data to |path|.
431 Args:
432 path: Local path to store the backup file.
433 packages: List of to packages to be backed up.
434 apk: (optional) If set include the .apk files in the archive.
435 shared: (optional) If set buckup the device's SD card.
436 nosystem: (optional) If set exclude system applications.
437 include_all: (optional) If set back up all installed applications and
438 |packages| is optional.
439 timeout: (optional) Timeout per try in seconds.
440 retries: (optional) Number of retries to attempt.
442 cmd = ['backup', path]
443 if apk:
444 cmd.append('-apk')
445 if shared:
446 cmd.append('-shared')
447 if nosystem:
448 cmd.append('-nosystem')
449 if include_all:
450 cmd.append('-all')
451 if packages:
452 cmd.extend(packages)
453 assert bool(packages) ^ bool(include_all), (
454 'Provide \'packages\' or set \'include_all\' but not both.')
455 ret = self._RunDeviceAdbCmd(cmd, timeout, retries)
456 _VerifyLocalFileExists(path)
457 return ret
459 def Restore(self, path, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
460 """Restore device contents from the backup archive.
462 Args:
463 path: Host path to the backup archive.
464 timeout: (optional) Timeout per try in seconds.
465 retries: (optional) Number of retries to attempt.
467 _VerifyLocalFileExists(path)
468 self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries)
470 def WaitForDevice(self, timeout=60*5, retries=_DEFAULT_RETRIES):
471 """Block until the device is online.
473 Args:
474 timeout: (optional) Timeout per try in seconds.
475 retries: (optional) Number of retries to attempt.
477 self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries)
479 def GetState(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
480 """Get device state.
482 Args:
483 timeout: (optional) Timeout per try in seconds.
484 retries: (optional) Number of retries to attempt.
486 Returns:
487 One of 'offline', 'bootloader', or 'device'.
489 return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip()
491 def GetDevPath(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
492 """Gets the device path.
494 Args:
495 timeout: (optional) Timeout per try in seconds.
496 retries: (optional) Number of retries to attempt.
498 Returns:
499 The device path (e.g. usb:3-4)
501 return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries)
503 def Remount(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
504 """Remounts the /system partition on the device read-write."""
505 self._RunDeviceAdbCmd(['remount'], timeout, retries)
507 def Reboot(self, to_bootloader=False, timeout=60*5,
508 retries=_DEFAULT_RETRIES):
509 """Reboots the device.
511 Args:
512 to_bootloader: (optional) If set reboots to the bootloader.
513 timeout: (optional) Timeout per try in seconds.
514 retries: (optional) Number of retries to attempt.
516 if to_bootloader:
517 cmd = ['reboot-bootloader']
518 else:
519 cmd = ['reboot']
520 self._RunDeviceAdbCmd(cmd, timeout, retries)
522 def Root(self, timeout=_DEFAULT_TIMEOUT, retries=_DEFAULT_RETRIES):
523 """Restarts the adbd daemon with root permissions, if possible.
525 Args:
526 timeout: (optional) Timeout per try in seconds.
527 retries: (optional) Number of retries to attempt.
529 output = self._RunDeviceAdbCmd(['root'], timeout, retries)
530 if 'cannot' in output:
531 raise device_errors.AdbCommandFailedError(
532 ['root'], output, device_serial=self._device_serial)