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. 4 5"""This module wraps Android's adb tool. 6 7This is a thin wrapper around the adb interface. Any additional complexity 8should be delegated to a higher level (ex. DeviceUtils). 9""" 10 11import collections 12import distutils.version 13import errno 14import logging 15import os 16import posixpath 17import re 18import subprocess 19 20from devil import devil_env 21from devil.android import decorators 22from devil.android import device_errors 23from devil.utils import cmd_helper 24from devil.utils import lazy 25from devil.utils import timeout_retry 26 27with devil_env.SysPath(devil_env.DEPENDENCY_MANAGER_PATH): 28 import dependency_manager # pylint: disable=import-error 29 30 31ADB_KEYS_FILE = '/data/misc/adb/adb_keys' 32 33DEFAULT_TIMEOUT = 30 34DEFAULT_RETRIES = 2 35 36_ADB_VERSION_RE = re.compile(r'Android Debug Bridge version (\d+\.\d+\.\d+)') 37_EMULATOR_RE = re.compile(r'^emulator-[0-9]+$') 38_READY_STATE = 'device' 39_VERITY_DISABLE_RE = re.compile('Verity (already)? disabled') 40_VERITY_ENABLE_RE = re.compile('Verity (already)? enabled') 41 42 43def VerifyLocalFileExists(path): 44 """Verifies a local file exists. 45 46 Args: 47 path: Path to the local file. 48 49 Raises: 50 IOError: If the file doesn't exist. 51 """ 52 if not os.path.exists(path): 53 raise IOError(errno.ENOENT, os.strerror(errno.ENOENT), path) 54 55 56def _FindAdb(): 57 try: 58 return devil_env.config.LocalPath('adb') 59 except dependency_manager.NoPathFoundError: 60 pass 61 62 try: 63 return os.path.join(devil_env.config.LocalPath('android_sdk'), 64 'platform-tools', 'adb') 65 except dependency_manager.NoPathFoundError: 66 pass 67 68 try: 69 return devil_env.config.FetchPath('adb') 70 except dependency_manager.NoPathFoundError: 71 raise device_errors.NoAdbError() 72 73 74def _GetVersion(): 75 # pylint: disable=protected-access 76 raw_version = AdbWrapper._RunAdbCmd(['version'], timeout=2, retries=0) 77 for l in raw_version.splitlines(): 78 m = _ADB_VERSION_RE.search(l) 79 if m: 80 return m.group(1) 81 return None 82 83 84def _ShouldRetryAdbCmd(exc): 85 return not isinstance(exc, device_errors.NoAdbError) 86 87 88DeviceStat = collections.namedtuple('DeviceStat', 89 ['st_mode', 'st_size', 'st_time']) 90 91 92def _IsExtraneousLine(line, send_cmd): 93 """Determine if a line read from stdout in persistent shell is extraneous. 94 95 The results output to stdout by the persistent shell process 96 (in PersistentShell below) often include "extraneous" lines that are 97 not part of the output of the shell command. These "extraneous" lines 98 do not always appear and are of two forms: shell prompt lines and lines 99 that just duplicate what the input command was. This function 100 detects these extraneous lines. Since all these lines have the 101 original command in them, that is what it detects ror. 102 103 Args: 104 line: Output line to check. 105 send_cmd: Command that was sent to adb persistent shell. 106 """ 107 return send_cmd.rstrip() in line 108 109 110class AdbWrapper(object): 111 """A wrapper around a local Android Debug Bridge executable.""" 112 113 _adb_path = lazy.WeakConstant(_FindAdb) 114 _adb_version = lazy.WeakConstant(_GetVersion) 115 116 def __init__(self, device_serial): 117 """Initializes the AdbWrapper. 118 119 Args: 120 device_serial: The device serial number as a string. 121 """ 122 if not device_serial: 123 raise ValueError('A device serial must be specified') 124 self._device_serial = str(device_serial) 125 126 class PersistentShell(object): 127 '''Class to use persistent shell for ADB. 128 129 This class allows a persistent ADB shell to be created, where multiple 130 commands can be passed into it. This avoids the overhead of starting 131 up a new ADB shell for each command. 132 133 Example of use: 134 with PersistentShell('123456789') as pshell: 135 pshell.RunCommand('which ls') 136 pshell.RunCommandAndClose('echo TEST') 137 ''' 138 def __init__(self, serial): 139 """Initialization function: 140 141 Args: 142 serial: Serial number of device. 143 """ 144 self._cmd = [AdbWrapper.GetAdbPath(), '-s', serial, 'shell'] 145 self._process = None 146 147 def __enter__(self): 148 self.Start() 149 self.WaitForReady() 150 return self 151 152 def __exit__(self, exc_type, exc_value, tb): 153 self.Stop() 154 155 def Start(self): 156 """Start the shell.""" 157 if self._process is not None: 158 raise RuntimeError('Persistent shell already running.') 159 self._process = subprocess.Popen(self._cmd, 160 stdin=subprocess.PIPE, 161 stdout=subprocess.PIPE, 162 shell=False) 163 164 def WaitForReady(self): 165 """Wait for the shell to be ready after starting. 166 167 Sends an echo command, then waits until it gets a response. 168 """ 169 self._process.stdin.write('echo\n') 170 output_line = self._process.stdout.readline() 171 while output_line.rstrip() != '': 172 output_line = self._process.stdout.readline() 173 174 def RunCommand(self, command, close=False): 175 """Runs an ADB command and returns the output. 176 177 Note that there can be approximately 40 ms of additional latency 178 between sending the command and receiving the results if close=False 179 due to the use of Nagle's algorithm in the TCP socket between the 180 adb server and client. To avoid this extra latency, set close=True. 181 182 Args: 183 command: Command to send. 184 Returns: 185 The command output, given as a list of lines, and the exit code 186 """ 187 188 if close: 189 def run_cmd(cmd): 190 send_cmd = '( %s ); echo $?; exit;\n' % cmd.rstrip() 191 (output, _) = self._process.communicate(send_cmd) 192 self._process = None 193 for x in output.splitlines(): 194 yield x 195 196 else: 197 def run_cmd(cmd): 198 send_cmd = '( %s ); echo DONE:$?;\n' % cmd.rstrip() 199 self._process.stdin.write(send_cmd) 200 while True: 201 output_line = self._process.stdout.readline().rstrip() 202 if output_line[:5] == 'DONE:': 203 yield output_line[5:] 204 break 205 yield output_line 206 207 result = [line for line in run_cmd(command) 208 if not _IsExtraneousLine(line, command)] 209 210 return (result[:-1], int(result[-1])) 211 212 def Stop(self): 213 """Stops the ADB process if it is still running.""" 214 if self._process is not None: 215 self._process.stdin.write('exit\n') 216 self._process = None 217 218 @classmethod 219 def GetAdbPath(cls): 220 return cls._adb_path.read() 221 222 @classmethod 223 def Version(cls): 224 return cls._adb_version.read() 225 226 @classmethod 227 def _BuildAdbCmd(cls, args, device_serial, cpu_affinity=None): 228 if cpu_affinity is not None: 229 cmd = ['taskset', '-c', str(cpu_affinity)] 230 else: 231 cmd = [] 232 cmd.append(cls.GetAdbPath()) 233 if device_serial is not None: 234 cmd.extend(['-s', device_serial]) 235 cmd.extend(args) 236 return cmd 237 238 # pylint: disable=unused-argument 239 @classmethod 240 @decorators.WithTimeoutAndConditionalRetries(_ShouldRetryAdbCmd) 241 def _RunAdbCmd(cls, args, timeout=None, retries=None, device_serial=None, 242 check_error=True, cpu_affinity=None): 243 # pylint: disable=no-member 244 try: 245 status, output = cmd_helper.GetCmdStatusAndOutputWithTimeout( 246 cls._BuildAdbCmd(args, device_serial, cpu_affinity=cpu_affinity), 247 timeout_retry.CurrentTimeoutThreadGroup().GetRemainingTime()) 248 except OSError as e: 249 if e.errno in (errno.ENOENT, errno.ENOEXEC): 250 raise device_errors.NoAdbError(msg=str(e)) 251 else: 252 raise 253 254 if status != 0: 255 raise device_errors.AdbCommandFailedError( 256 args, output, status, device_serial) 257 # This catches some errors, including when the device drops offline; 258 # unfortunately adb is very inconsistent with error reporting so many 259 # command failures present differently. 260 if check_error and output.startswith('error:'): 261 raise device_errors.AdbCommandFailedError(args, output) 262 return output 263 # pylint: enable=unused-argument 264 265 def _RunDeviceAdbCmd(self, args, timeout, retries, check_error=True): 266 """Runs an adb command on the device associated with this object. 267 268 Args: 269 args: A list of arguments to adb. 270 timeout: Timeout in seconds. 271 retries: Number of retries. 272 check_error: Check that the command doesn't return an error message. This 273 does NOT check the exit status of shell commands. 274 275 Returns: 276 The output of the command. 277 """ 278 return self._RunAdbCmd(args, timeout=timeout, retries=retries, 279 device_serial=self._device_serial, 280 check_error=check_error) 281 282 def _IterRunDeviceAdbCmd(self, args, timeout): 283 """Runs an adb command and returns an iterator over its output lines. 284 285 Args: 286 args: A list of arguments to adb. 287 timeout: Timeout in seconds. 288 289 Yields: 290 The output of the command line by line. 291 """ 292 return cmd_helper.IterCmdOutputLines( 293 self._BuildAdbCmd(args, self._device_serial), timeout=timeout) 294 295 def __eq__(self, other): 296 """Consider instances equal if they refer to the same device. 297 298 Args: 299 other: The instance to compare equality with. 300 301 Returns: 302 True if the instances are considered equal, false otherwise. 303 """ 304 return self._device_serial == str(other) 305 306 def __str__(self): 307 """The string representation of an instance. 308 309 Returns: 310 The device serial number as a string. 311 """ 312 return self._device_serial 313 314 def __repr__(self): 315 return '%s(\'%s\')' % (self.__class__.__name__, self) 316 317 # pylint: disable=unused-argument 318 @classmethod 319 def IsServerOnline(cls): 320 status, output = cmd_helper.GetCmdStatusAndOutput(['pgrep', 'adb']) 321 output = [int(x) for x in output.split()] 322 logging.info('PIDs for adb found: %r', output) 323 return status == 0 324 # pylint: enable=unused-argument 325 326 @classmethod 327 def KillServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 328 cls._RunAdbCmd(['kill-server'], timeout=timeout, retries=retries) 329 330 @classmethod 331 def StartServer(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 332 # CPU affinity is used to reduce adb instability http://crbug.com/268450 333 cls._RunAdbCmd(['start-server'], timeout=timeout, retries=retries, 334 cpu_affinity=0) 335 336 @classmethod 337 def GetDevices(cls, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 338 """DEPRECATED. Refer to Devices(...) below.""" 339 # TODO(jbudorick): Remove this function once no more clients are using it. 340 return cls.Devices(timeout=timeout, retries=retries) 341 342 @classmethod 343 def Devices(cls, desired_state=_READY_STATE, long_list=False, 344 timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 345 """Get the list of active attached devices. 346 347 Args: 348 desired_state: If not None, limit the devices returned to only those 349 in the given state. 350 long_list: Whether to use the long listing format. 351 timeout: (optional) Timeout per try in seconds. 352 retries: (optional) Number of retries to attempt. 353 354 Yields: 355 AdbWrapper instances. 356 """ 357 lines = cls._RawDevices(long_list=long_list, timeout=timeout, 358 retries=retries) 359 if long_list: 360 return [ 361 [AdbWrapper(line[0])] + line[1:] 362 for line in lines 363 if (len(line) >= 2 and (not desired_state or line[1] == desired_state)) 364 ] 365 else: 366 return [ 367 AdbWrapper(line[0]) 368 for line in lines 369 if (len(line) == 2 and (not desired_state or line[1] == desired_state)) 370 ] 371 372 @classmethod 373 def _RawDevices(cls, long_list=False, timeout=DEFAULT_TIMEOUT, 374 retries=DEFAULT_RETRIES): 375 cmd = ['devices'] 376 if long_list: 377 cmd.append('-l') 378 output = cls._RunAdbCmd(cmd, timeout=timeout, retries=retries) 379 return [line.split() for line in output.splitlines()[1:]] 380 381 def GetDeviceSerial(self): 382 """Gets the device serial number associated with this object. 383 384 Returns: 385 Device serial number as a string. 386 """ 387 return self._device_serial 388 389 def Push(self, local, remote, timeout=60 * 5, retries=DEFAULT_RETRIES): 390 """Pushes a file from the host to the device. 391 392 Args: 393 local: Path on the host filesystem. 394 remote: Path on the device filesystem. 395 timeout: (optional) Timeout per try in seconds. 396 retries: (optional) Number of retries to attempt. 397 """ 398 VerifyLocalFileExists(local) 399 400 if (distutils.version.LooseVersion(self.Version()) < 401 distutils.version.LooseVersion('1.0.36')): 402 403 # Different versions of adb handle pushing a directory to an existing 404 # directory differently. 405 406 # In the version packaged with the M SDK, 1.0.32, the following push: 407 # foo/bar -> /sdcard/foo/bar 408 # where bar is an existing directory both on the host and the device 409 # results in the contents of bar/ on the host being pushed to bar/ on 410 # the device, i.e. 411 # foo/bar/A -> /sdcard/foo/bar/A 412 # foo/bar/B -> /sdcard/foo/bar/B 413 # ... etc. 414 415 # In the version packaged with the N SDK, 1.0.36, the same push under 416 # the same conditions results in a second bar/ directory being created 417 # underneath the first bar/ directory on the device, i.e. 418 # foo/bar/A -> /sdcard/foo/bar/bar/A 419 # foo/bar/B -> /sdcard/foo/bar/bar/B 420 # ... etc. 421 422 # In order to provide a consistent interface to clients, we check whether 423 # the target is an existing directory on the device and, if so, modifies 424 # the target passed to adb to emulate the behavior on 1.0.36 and above. 425 426 # Note that this behavior may have started before 1.0.36; that's simply 427 # the earliest version we've confirmed thus far. 428 429 try: 430 self.Shell('test -d %s' % remote, timeout=timeout, retries=retries) 431 remote = posixpath.join(remote, posixpath.basename(local)) 432 except device_errors.AdbShellCommandFailedError: 433 # The target directory doesn't exist on the device, so we can use it 434 # without modification. 435 pass 436 437 self._RunDeviceAdbCmd(['push', local, remote], timeout, retries) 438 439 def Pull(self, remote, local, timeout=60 * 5, retries=DEFAULT_RETRIES): 440 """Pulls a file from the device to the host. 441 442 Args: 443 remote: Path on the device filesystem. 444 local: Path on the host filesystem. 445 timeout: (optional) Timeout per try in seconds. 446 retries: (optional) Number of retries to attempt. 447 """ 448 cmd = ['pull', remote, local] 449 self._RunDeviceAdbCmd(cmd, timeout, retries) 450 try: 451 VerifyLocalFileExists(local) 452 except IOError: 453 raise device_errors.AdbCommandFailedError( 454 cmd, 'File not found on host: %s' % local, device_serial=str(self)) 455 456 def Shell(self, command, expect_status=0, timeout=DEFAULT_TIMEOUT, 457 retries=DEFAULT_RETRIES): 458 """Runs a shell command on the device. 459 460 Args: 461 command: A string with the shell command to run. 462 expect_status: (optional) Check that the command's exit status matches 463 this value. Default is 0. If set to None the test is skipped. 464 timeout: (optional) Timeout per try in seconds. 465 retries: (optional) Number of retries to attempt. 466 467 Returns: 468 The output of the shell command as a string. 469 470 Raises: 471 device_errors.AdbCommandFailedError: If the exit status doesn't match 472 |expect_status|. 473 """ 474 if expect_status is None: 475 args = ['shell', command] 476 else: 477 args = ['shell', '( %s );echo %%$?' % command.rstrip()] 478 output = self._RunDeviceAdbCmd(args, timeout, retries, check_error=False) 479 if expect_status is not None: 480 output_end = output.rfind('%') 481 if output_end < 0: 482 # causes the status string to become empty and raise a ValueError 483 output_end = len(output) 484 485 try: 486 status = int(output[output_end + 1:]) 487 except ValueError: 488 logging.warning('exit status of shell command %r missing.', command) 489 raise device_errors.AdbShellCommandFailedError( 490 command, output, status=None, device_serial=self._device_serial) 491 output = output[:output_end] 492 if status != expect_status: 493 raise device_errors.AdbShellCommandFailedError( 494 command, output, status=status, device_serial=self._device_serial) 495 return output 496 497 def IterShell(self, command, timeout): 498 """Runs a shell command and returns an iterator over its output lines. 499 500 Args: 501 command: A string with the shell command to run. 502 timeout: Timeout in seconds. 503 504 Yields: 505 The output of the command line by line. 506 """ 507 args = ['shell', command] 508 return cmd_helper.IterCmdOutputLines( 509 self._BuildAdbCmd(args, self._device_serial), timeout=timeout) 510 511 def Ls(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 512 """List the contents of a directory on the device. 513 514 Args: 515 path: Path on the device filesystem. 516 timeout: (optional) Timeout per try in seconds. 517 retries: (optional) Number of retries to attempt. 518 519 Returns: 520 A list of pairs (filename, stat) for each file found in the directory, 521 where the stat object has the properties: st_mode, st_size, and st_time. 522 523 Raises: 524 AdbCommandFailedError if |path| does not specify a valid and accessible 525 directory in the device, or the output of "adb ls" command is less 526 than four columns 527 """ 528 def ParseLine(line, cmd): 529 cols = line.split(None, 3) 530 if len(cols) < 4: 531 raise device_errors.AdbCommandFailedError( 532 cmd, line, "the output should be 4 columns, but is only %d columns" 533 % len(cols), device_serial=self._device_serial) 534 filename = cols.pop() 535 stat = DeviceStat(*[int(num, base=16) for num in cols]) 536 return (filename, stat) 537 538 cmd = ['ls', path] 539 lines = self._RunDeviceAdbCmd( 540 cmd, timeout=timeout, retries=retries).splitlines() 541 if lines: 542 return [ParseLine(line, cmd) for line in lines] 543 else: 544 raise device_errors.AdbCommandFailedError( 545 cmd, 'path does not specify an accessible directory in the device', 546 device_serial=self._device_serial) 547 548 def Logcat(self, clear=False, dump=False, filter_specs=None, 549 logcat_format=None, ring_buffer=None, timeout=None, 550 retries=DEFAULT_RETRIES): 551 """Get an iterable over the logcat output. 552 553 Args: 554 clear: If true, clear the logcat. 555 dump: If true, dump the current logcat contents. 556 filter_specs: If set, a list of specs to filter the logcat. 557 logcat_format: If set, the format in which the logcat should be output. 558 Options include "brief", "process", "tag", "thread", "raw", "time", 559 "threadtime", and "long" 560 ring_buffer: If set, a list of alternate ring buffers to request. 561 Options include "main", "system", "radio", "events", "crash" or "all". 562 The default is equivalent to ["main", "system", "crash"]. 563 timeout: (optional) If set, timeout per try in seconds. If clear or dump 564 is set, defaults to DEFAULT_TIMEOUT. 565 retries: (optional) If clear or dump is set, the number of retries to 566 attempt. Otherwise, does nothing. 567 568 Yields: 569 logcat output line by line. 570 """ 571 cmd = ['logcat'] 572 use_iter = True 573 if clear: 574 cmd.append('-c') 575 use_iter = False 576 if dump: 577 cmd.append('-d') 578 use_iter = False 579 if logcat_format: 580 cmd.extend(['-v', logcat_format]) 581 if ring_buffer: 582 for buffer_name in ring_buffer: 583 cmd.extend(['-b', buffer_name]) 584 if filter_specs: 585 cmd.extend(filter_specs) 586 587 if use_iter: 588 return self._IterRunDeviceAdbCmd(cmd, timeout) 589 else: 590 timeout = timeout if timeout is not None else DEFAULT_TIMEOUT 591 return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines() 592 593 def Forward(self, local, remote, allow_rebind=False, 594 timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 595 """Forward socket connections from the local socket to the remote socket. 596 597 Sockets are specified by one of: 598 tcp:<port> 599 localabstract:<unix domain socket name> 600 localreserved:<unix domain socket name> 601 localfilesystem:<unix domain socket name> 602 dev:<character device name> 603 jdwp:<process pid> (remote only) 604 605 Args: 606 local: The host socket. 607 remote: The device socket. 608 allow_rebind: A boolean indicating whether adb may rebind a local socket; 609 otherwise, the default, an exception is raised if the local socket is 610 already being forwarded. 611 timeout: (optional) Timeout per try in seconds. 612 retries: (optional) Number of retries to attempt. 613 """ 614 cmd = ['forward'] 615 if not allow_rebind: 616 cmd.append('--no-rebind') 617 cmd.extend([str(local), str(remote)]) 618 self._RunDeviceAdbCmd(cmd, timeout, retries) 619 620 def ForwardRemove(self, local, timeout=DEFAULT_TIMEOUT, 621 retries=DEFAULT_RETRIES): 622 """Remove a forward socket connection. 623 624 Args: 625 local: The host socket. 626 timeout: (optional) Timeout per try in seconds. 627 retries: (optional) Number of retries to attempt. 628 """ 629 self._RunDeviceAdbCmd(['forward', '--remove', str(local)], timeout, 630 retries) 631 632 def ForwardList(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 633 """List all currently forwarded socket connections. 634 635 Args: 636 timeout: (optional) Timeout per try in seconds. 637 retries: (optional) Number of retries to attempt. 638 """ 639 return self._RunDeviceAdbCmd(['forward', '--list'], timeout, retries) 640 641 def JDWP(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 642 """List of PIDs of processes hosting a JDWP transport. 643 644 Args: 645 timeout: (optional) Timeout per try in seconds. 646 retries: (optional) Number of retries to attempt. 647 648 Returns: 649 A list of PIDs as strings. 650 """ 651 return [a.strip() for a in 652 self._RunDeviceAdbCmd(['jdwp'], timeout, retries).split('\n')] 653 654 def Install(self, apk_path, forward_lock=False, allow_downgrade=False, 655 reinstall=False, sd_card=False, timeout=60 * 2, 656 retries=DEFAULT_RETRIES): 657 """Install an apk on the device. 658 659 Args: 660 apk_path: Host path to the APK file. 661 forward_lock: (optional) If set forward-locks the app. 662 allow_downgrade: (optional) If set, allows for downgrades. 663 reinstall: (optional) If set reinstalls the app, keeping its data. 664 sd_card: (optional) If set installs on the SD card. 665 timeout: (optional) Timeout per try in seconds. 666 retries: (optional) Number of retries to attempt. 667 """ 668 VerifyLocalFileExists(apk_path) 669 cmd = ['install'] 670 if forward_lock: 671 cmd.append('-l') 672 if reinstall: 673 cmd.append('-r') 674 if sd_card: 675 cmd.append('-s') 676 if allow_downgrade: 677 cmd.append('-d') 678 cmd.append(apk_path) 679 output = self._RunDeviceAdbCmd(cmd, timeout, retries) 680 if 'Success' not in output: 681 raise device_errors.AdbCommandFailedError( 682 cmd, output, device_serial=self._device_serial) 683 684 def InstallMultiple(self, apk_paths, forward_lock=False, reinstall=False, 685 sd_card=False, allow_downgrade=False, partial=False, 686 timeout=60 * 2, retries=DEFAULT_RETRIES): 687 """Install an apk with splits on the device. 688 689 Args: 690 apk_paths: Host path to the APK file. 691 forward_lock: (optional) If set forward-locks the app. 692 reinstall: (optional) If set reinstalls the app, keeping its data. 693 sd_card: (optional) If set installs on the SD card. 694 allow_downgrade: (optional) Allow versionCode downgrade. 695 partial: (optional) Package ID if apk_paths doesn't include all .apks. 696 timeout: (optional) Timeout per try in seconds. 697 retries: (optional) Number of retries to attempt. 698 """ 699 for path in apk_paths: 700 VerifyLocalFileExists(path) 701 cmd = ['install-multiple'] 702 if forward_lock: 703 cmd.append('-l') 704 if reinstall: 705 cmd.append('-r') 706 if sd_card: 707 cmd.append('-s') 708 if allow_downgrade: 709 cmd.append('-d') 710 if partial: 711 cmd.extend(('-p', partial)) 712 cmd.extend(apk_paths) 713 output = self._RunDeviceAdbCmd(cmd, timeout, retries) 714 if 'Success' not in output: 715 raise device_errors.AdbCommandFailedError( 716 cmd, output, device_serial=self._device_serial) 717 718 def Uninstall(self, package, keep_data=False, timeout=DEFAULT_TIMEOUT, 719 retries=DEFAULT_RETRIES): 720 """Remove the app |package| from the device. 721 722 Args: 723 package: The package to uninstall. 724 keep_data: (optional) If set keep the data and cache directories. 725 timeout: (optional) Timeout per try in seconds. 726 retries: (optional) Number of retries to attempt. 727 """ 728 cmd = ['uninstall'] 729 if keep_data: 730 cmd.append('-k') 731 cmd.append(package) 732 output = self._RunDeviceAdbCmd(cmd, timeout, retries) 733 if 'Failure' in output: 734 raise device_errors.AdbCommandFailedError( 735 cmd, output, device_serial=self._device_serial) 736 737 def Backup(self, path, packages=None, apk=False, shared=False, 738 nosystem=True, include_all=False, timeout=DEFAULT_TIMEOUT, 739 retries=DEFAULT_RETRIES): 740 """Write an archive of the device's data to |path|. 741 742 Args: 743 path: Local path to store the backup file. 744 packages: List of to packages to be backed up. 745 apk: (optional) If set include the .apk files in the archive. 746 shared: (optional) If set buckup the device's SD card. 747 nosystem: (optional) If set exclude system applications. 748 include_all: (optional) If set back up all installed applications and 749 |packages| is optional. 750 timeout: (optional) Timeout per try in seconds. 751 retries: (optional) Number of retries to attempt. 752 """ 753 cmd = ['backup', '-f', path] 754 if apk: 755 cmd.append('-apk') 756 if shared: 757 cmd.append('-shared') 758 if nosystem: 759 cmd.append('-nosystem') 760 if include_all: 761 cmd.append('-all') 762 if packages: 763 cmd.extend(packages) 764 assert bool(packages) ^ bool(include_all), ( 765 'Provide \'packages\' or set \'include_all\' but not both.') 766 ret = self._RunDeviceAdbCmd(cmd, timeout, retries) 767 VerifyLocalFileExists(path) 768 return ret 769 770 def Restore(self, path, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 771 """Restore device contents from the backup archive. 772 773 Args: 774 path: Host path to the backup archive. 775 timeout: (optional) Timeout per try in seconds. 776 retries: (optional) Number of retries to attempt. 777 """ 778 VerifyLocalFileExists(path) 779 self._RunDeviceAdbCmd(['restore'] + [path], timeout, retries) 780 781 def WaitForDevice(self, timeout=60 * 5, retries=DEFAULT_RETRIES): 782 """Block until the device is online. 783 784 Args: 785 timeout: (optional) Timeout per try in seconds. 786 retries: (optional) Number of retries to attempt. 787 """ 788 self._RunDeviceAdbCmd(['wait-for-device'], timeout, retries) 789 790 def GetState(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 791 """Get device state. 792 793 Args: 794 timeout: (optional) Timeout per try in seconds. 795 retries: (optional) Number of retries to attempt. 796 797 Returns: 798 One of 'offline', 'bootloader', or 'device'. 799 """ 800 # TODO(jbudorick): Revert to using get-state once it doesn't cause a 801 # a protocol fault. 802 # return self._RunDeviceAdbCmd(['get-state'], timeout, retries).strip() 803 804 lines = self._RawDevices(timeout=timeout, retries=retries) 805 for line in lines: 806 if len(line) >= 2 and line[0] == self._device_serial: 807 return line[1] 808 return 'offline' 809 810 def GetDevPath(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 811 """Gets the device path. 812 813 Args: 814 timeout: (optional) Timeout per try in seconds. 815 retries: (optional) Number of retries to attempt. 816 817 Returns: 818 The device path (e.g. usb:3-4) 819 """ 820 return self._RunDeviceAdbCmd(['get-devpath'], timeout, retries) 821 822 def Remount(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 823 """Remounts the /system partition on the device read-write.""" 824 self._RunDeviceAdbCmd(['remount'], timeout, retries) 825 826 def Reboot(self, to_bootloader=False, timeout=60 * 5, 827 retries=DEFAULT_RETRIES): 828 """Reboots the device. 829 830 Args: 831 to_bootloader: (optional) If set reboots to the bootloader. 832 timeout: (optional) Timeout per try in seconds. 833 retries: (optional) Number of retries to attempt. 834 """ 835 if to_bootloader: 836 cmd = ['reboot-bootloader'] 837 else: 838 cmd = ['reboot'] 839 self._RunDeviceAdbCmd(cmd, timeout, retries) 840 841 def Root(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 842 """Restarts the adbd daemon with root permissions, if possible. 843 844 Args: 845 timeout: (optional) Timeout per try in seconds. 846 retries: (optional) Number of retries to attempt. 847 """ 848 output = self._RunDeviceAdbCmd(['root'], timeout, retries) 849 if 'cannot' in output: 850 raise device_errors.AdbCommandFailedError( 851 ['root'], output, device_serial=self._device_serial) 852 853 def Emu(self, cmd, timeout=DEFAULT_TIMEOUT, 854 retries=DEFAULT_RETRIES): 855 """Runs an emulator console command. 856 857 See http://developer.android.com/tools/devices/emulator.html#console 858 859 Args: 860 cmd: The command to run on the emulator console. 861 timeout: (optional) Timeout per try in seconds. 862 retries: (optional) Number of retries to attempt. 863 864 Returns: 865 The output of the emulator console command. 866 """ 867 if isinstance(cmd, basestring): 868 cmd = [cmd] 869 return self._RunDeviceAdbCmd(['emu'] + cmd, timeout, retries) 870 871 def DisableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 872 """Disable Marshmallow's Verity security feature""" 873 output = self._RunDeviceAdbCmd(['disable-verity'], timeout, retries) 874 if output and _VERITY_DISABLE_RE.search(output): 875 raise device_errors.AdbCommandFailedError( 876 ['disable-verity'], output, device_serial=self._device_serial) 877 878 def EnableVerity(self, timeout=DEFAULT_TIMEOUT, retries=DEFAULT_RETRIES): 879 """Enable Marshmallow's Verity security feature""" 880 output = self._RunDeviceAdbCmd(['enable-verity'], timeout, retries) 881 if output and _VERITY_ENABLE_RE.search(output): 882 raise device_errors.AdbCommandFailedError( 883 ['enable-verity'], output, device_serial=self._device_serial) 884 885 @property 886 def is_emulator(self): 887 return _EMULATOR_RE.match(self._device_serial) 888 889 @property 890 def is_ready(self): 891 try: 892 return self.GetState() == _READY_STATE 893 except device_errors.CommandFailedError: 894 return False 895