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