1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5"""Provides a variety of device interactions based on adb. 6 7Eventually, this will be based on adb_wrapper. 8""" 9# pylint: disable=W0613 10 11import pipes 12import sys 13import time 14 15import pylib.android_commands 16from pylib.device import adb_wrapper 17from pylib.device import decorators 18from pylib.device import device_errors 19from pylib.utils import apk_helper 20from pylib.utils import parallelizer 21 22_DEFAULT_TIMEOUT = 30 23_DEFAULT_RETRIES = 3 24 25 26@decorators.WithExplicitTimeoutAndRetries( 27 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 28def GetAVDs(): 29 """Returns a list of Android Virtual Devices. 30 31 Returns: 32 A list containing the configured AVDs. 33 """ 34 return pylib.android_commands.GetAVDs() 35 36 37@decorators.WithExplicitTimeoutAndRetries( 38 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 39def RestartServer(): 40 """Restarts the adb server. 41 42 Raises: 43 CommandFailedError if we fail to kill or restart the server. 44 """ 45 pylib.android_commands.AndroidCommands().RestartAdbServer() 46 47 48class DeviceUtils(object): 49 50 def __init__(self, device, default_timeout=_DEFAULT_TIMEOUT, 51 default_retries=_DEFAULT_RETRIES): 52 """DeviceUtils constructor. 53 54 Args: 55 device: Either a device serial, an existing AdbWrapper instance, an 56 an existing AndroidCommands instance, or nothing. 57 default_timeout: An integer containing the default number of seconds to 58 wait for an operation to complete if no explicit value 59 is provided. 60 default_retries: An integer containing the default number or times an 61 operation should be retried on failure if no explicit 62 value is provided. 63 """ 64 self.old_interface = None 65 if isinstance(device, basestring): 66 self.old_interface = pylib.android_commands.AndroidCommands(device) 67 elif isinstance(device, adb_wrapper.AdbWrapper): 68 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) 69 elif isinstance(device, pylib.android_commands.AndroidCommands): 70 self.old_interface = device 71 elif not device: 72 self.old_interface = pylib.android_commands.AndroidCommands() 73 else: 74 raise ValueError('Unsupported type passed for argument "device"') 75 self._default_timeout = default_timeout 76 self._default_retries = default_retries 77 assert(hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)) 78 assert(hasattr(self, decorators.DEFAULT_RETRIES_ATTR)) 79 80 @decorators.WithTimeoutAndRetriesFromInstance() 81 def IsOnline(self, timeout=None, retries=None): 82 """Checks whether the device is online. 83 84 Args: 85 timeout: timeout in seconds 86 retries: number of retries 87 88 Returns: 89 True if the device is online, False otherwise. 90 91 Raises: 92 CommandTimeoutError on timeout. 93 """ 94 return self.old_interface.IsOnline() 95 96 @decorators.WithTimeoutAndRetriesFromInstance() 97 def HasRoot(self, timeout=None, retries=None): 98 """Checks whether or not adbd has root privileges. 99 100 Args: 101 timeout: timeout in seconds 102 retries: number of retries 103 104 Returns: 105 True if adbd has root privileges, False otherwise. 106 107 Raises: 108 CommandTimeoutError on timeout. 109 DeviceUnreachableError on missing device. 110 """ 111 return self._HasRootImpl() 112 113 def _HasRootImpl(self): 114 """Implementation of HasRoot. 115 116 This is split from HasRoot to allow other DeviceUtils methods to call 117 HasRoot without spawning a new timeout thread. 118 119 Returns: 120 Same as for |HasRoot|. 121 122 Raises: 123 Same as for |HasRoot|. 124 """ 125 return self.old_interface.IsRootEnabled() 126 127 @decorators.WithTimeoutAndRetriesFromInstance() 128 def EnableRoot(self, timeout=None, retries=None): 129 """Restarts adbd with root privileges. 130 131 Args: 132 timeout: timeout in seconds 133 retries: number of retries 134 135 Raises: 136 CommandFailedError if root could not be enabled. 137 CommandTimeoutError on timeout. 138 """ 139 if not self.old_interface.EnableAdbRoot(): 140 raise device_errors.CommandFailedError( 141 'Could not enable root.', device=str(self)) 142 143 @decorators.WithTimeoutAndRetriesFromInstance() 144 def GetExternalStoragePath(self, timeout=None, retries=None): 145 """Get the device's path to its SD card. 146 147 Args: 148 timeout: timeout in seconds 149 retries: number of retries 150 151 Returns: 152 The device's path to its SD card. 153 154 Raises: 155 CommandFailedError if the external storage path could not be determined. 156 CommandTimeoutError on timeout. 157 DeviceUnreachableError on missing device. 158 """ 159 try: 160 return self.old_interface.GetExternalStorage() 161 except AssertionError as e: 162 raise device_errors.CommandFailedError( 163 str(e), device=str(self)), None, sys.exc_info()[2] 164 165 @decorators.WithTimeoutAndRetriesFromInstance() 166 def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None): 167 """Wait for the device to fully boot. 168 169 This means waiting for the device to boot, the package manager to be 170 available, and the SD card to be ready. It can optionally mean waiting 171 for wifi to come up, too. 172 173 Args: 174 wifi: A boolean indicating if we should wait for wifi to come up or not. 175 timeout: timeout in seconds 176 retries: number of retries 177 178 Raises: 179 CommandFailedError on failure. 180 CommandTimeoutError if one of the component waits times out. 181 DeviceUnreachableError if the device becomes unresponsive. 182 """ 183 self._WaitUntilFullyBootedImpl(wifi=wifi, timeout=timeout) 184 185 def _WaitUntilFullyBootedImpl(self, wifi=False, timeout=None): 186 """Implementation of WaitUntilFullyBooted. 187 188 This is split from WaitUntilFullyBooted to allow other DeviceUtils methods 189 to call WaitUntilFullyBooted without spawning a new timeout thread. 190 191 TODO(jbudorick) Remove the timeout parameter once this is no longer 192 implemented via AndroidCommands. 193 194 Args: 195 wifi: Same as for |WaitUntilFullyBooted|. 196 timeout: timeout in seconds 197 198 Raises: 199 Same as for |WaitUntilFullyBooted|. 200 """ 201 if timeout is None: 202 timeout = self._default_timeout 203 self.old_interface.WaitForSystemBootCompleted(timeout) 204 self.old_interface.WaitForDevicePm() 205 self.old_interface.WaitForSdCardReady(timeout) 206 if wifi: 207 while not 'Wi-Fi is enabled' in ( 208 self._RunShellCommandImpl('dumpsys wifi')): 209 time.sleep(1) 210 211 REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT 212 REBOOT_DEFAULT_RETRIES = _DEFAULT_RETRIES 213 214 @decorators.WithTimeoutAndRetriesDefaults( 215 REBOOT_DEFAULT_TIMEOUT, 216 REBOOT_DEFAULT_RETRIES) 217 def Reboot(self, block=True, timeout=None, retries=None): 218 """Reboot the device. 219 220 Args: 221 block: A boolean indicating if we should wait for the reboot to complete. 222 timeout: timeout in seconds 223 retries: number of retries 224 225 Raises: 226 CommandTimeoutError on timeout. 227 DeviceUnreachableError on missing device. 228 """ 229 self.old_interface.Reboot() 230 if block: 231 self._WaitUntilFullyBootedImpl(timeout=timeout) 232 233 INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT 234 INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES 235 236 @decorators.WithTimeoutAndRetriesDefaults( 237 INSTALL_DEFAULT_TIMEOUT, 238 INSTALL_DEFAULT_RETRIES) 239 def Install(self, apk_path, reinstall=False, timeout=None, retries=None): 240 """Install an APK. 241 242 Noop if an identical APK is already installed. 243 244 Args: 245 apk_path: A string containing the path to the APK to install. 246 reinstall: A boolean indicating if we should keep any existing app data. 247 timeout: timeout in seconds 248 retries: number of retries 249 250 Raises: 251 CommandFailedError if the installation fails. 252 CommandTimeoutError if the installation times out. 253 DeviceUnreachableError on missing device. 254 """ 255 package_name = apk_helper.GetPackageName(apk_path) 256 device_path = self.old_interface.GetApplicationPath(package_name) 257 if device_path is not None: 258 files_changed = self.old_interface.GetFilesChanged( 259 apk_path, device_path, ignore_filenames=True) 260 if len(files_changed) > 0: 261 should_install = True 262 if not reinstall: 263 out = self.old_interface.Uninstall(package_name) 264 for line in out.splitlines(): 265 if 'Failure' in line: 266 raise device_errors.CommandFailedError( 267 line.strip(), device=str(self)) 268 else: 269 should_install = False 270 else: 271 should_install = True 272 if should_install: 273 try: 274 out = self.old_interface.Install(apk_path, reinstall=reinstall) 275 for line in out.splitlines(): 276 if 'Failure' in line: 277 raise device_errors.CommandFailedError( 278 line.strip(), device=str(self)) 279 except AssertionError as e: 280 raise device_errors.CommandFailedError( 281 str(e), device=str(self)), None, sys.exc_info()[2] 282 283 @decorators.WithTimeoutAndRetriesFromInstance() 284 def RunShellCommand(self, cmd, check_return=False, as_root=False, 285 timeout=None, retries=None): 286 """Run an ADB shell command. 287 288 TODO(jbudorick) Switch the default value of check_return to True after 289 AndroidCommands is gone. 290 291 Args: 292 cmd: A list containing the command to run on the device and any arguments. 293 check_return: A boolean indicating whether or not the return code should 294 be checked. 295 as_root: A boolean indicating whether the shell command should be run 296 with root privileges. 297 timeout: timeout in seconds 298 retries: number of retries 299 300 Returns: 301 The output of the command. 302 303 Raises: 304 CommandFailedError if check_return is True and the return code is nozero. 305 CommandTimeoutError on timeout. 306 DeviceUnreachableError on missing device. 307 """ 308 return self._RunShellCommandImpl(cmd, check_return=check_return, 309 as_root=as_root, timeout=timeout) 310 311 def _RunShellCommandImpl(self, cmd, check_return=False, as_root=False, 312 timeout=None): 313 """Implementation of RunShellCommand. 314 315 This is split from RunShellCommand to allow other DeviceUtils methods to 316 call RunShellCommand without spawning a new timeout thread. 317 318 TODO(jbudorick) Remove the timeout parameter once this is no longer 319 implemented via AndroidCommands. 320 321 Args: 322 cmd: Same as for |RunShellCommand|. 323 check_return: Same as for |RunShellCommand|. 324 as_root: Same as for |RunShellCommand|. 325 timeout: timeout in seconds 326 327 Raises: 328 Same as for |RunShellCommand|. 329 330 Returns: 331 Same as for |RunShellCommand|. 332 """ 333 if isinstance(cmd, list): 334 cmd = ' '.join(cmd) 335 if as_root and not self.HasRoot(): 336 cmd = 'su -c %s' % cmd 337 if check_return: 338 code, output = self.old_interface.GetShellCommandStatusAndOutput( 339 cmd, timeout_time=timeout) 340 if int(code) != 0: 341 raise device_errors.AdbCommandFailedError( 342 cmd.split(), 'Nonzero exit code (%d)' % code, device=str(self)) 343 else: 344 output = self.old_interface.RunShellCommand(cmd, timeout_time=timeout) 345 return output 346 347 @decorators.WithTimeoutAndRetriesFromInstance() 348 def KillAll(self, process_name, signum=9, as_root=False, blocking=False, 349 timeout=None, retries=None): 350 """Kill all processes with the given name on the device. 351 352 Args: 353 process_name: A string containing the name of the process to kill. 354 signum: An integer containing the signal number to send to kill. Defaults 355 to 9 (SIGKILL). 356 as_root: A boolean indicating whether the kill should be executed with 357 root privileges. 358 blocking: A boolean indicating whether we should wait until all processes 359 with the given |process_name| are dead. 360 timeout: timeout in seconds 361 retries: number of retries 362 363 Raises: 364 CommandFailedError if no process was killed. 365 CommandTimeoutError on timeout. 366 DeviceUnreachableError on missing device. 367 """ 368 pids = self._GetPidsImpl(process_name) 369 if not pids: 370 raise device_errors.CommandFailedError( 371 'No process "%s"' % process_name, device=str(self)) 372 373 cmd = 'kill -%d %s' % (signum, ' '.join(pids.values())) 374 self._RunShellCommandImpl(cmd, as_root=as_root) 375 376 if blocking: 377 wait_period = 0.1 378 while self._GetPidsImpl(process_name): 379 time.sleep(wait_period) 380 381 return len(pids) 382 383 @decorators.WithTimeoutAndRetriesFromInstance() 384 def StartActivity(self, intent, blocking=False, trace_file_name=None, 385 force_stop=False, timeout=None, retries=None): 386 """Start package's activity on the device. 387 388 Args: 389 intent: An Intent to send. 390 blocking: A boolean indicating whether we should wait for the activity to 391 finish launching. 392 trace_file_name: If present, a string that both indicates that we want to 393 profile the activity and contains the path to which the 394 trace should be saved. 395 force_stop: A boolean indicating whether we should stop the activity 396 before starting it. 397 timeout: timeout in seconds 398 retries: number of retries 399 400 Raises: 401 CommandFailedError if the activity could not be started. 402 CommandTimeoutError on timeout. 403 DeviceUnreachableError on missing device. 404 """ 405 single_category = (intent.category[0] if isinstance(intent.category, list) 406 else intent.category) 407 output = self.old_interface.StartActivity( 408 intent.package, intent.activity, wait_for_completion=blocking, 409 action=intent.action, category=single_category, data=intent.data, 410 extras=intent.extras, trace_file_name=trace_file_name, 411 force_stop=force_stop, flags=intent.flags) 412 for l in output: 413 if l.startswith('Error:'): 414 raise device_errors.CommandFailedError(l, device=str(self)) 415 416 @decorators.WithTimeoutAndRetriesFromInstance() 417 def BroadcastIntent(self, intent, timeout=None, retries=None): 418 """Send a broadcast intent. 419 420 Args: 421 intent: An Intent to broadcast. 422 timeout: timeout in seconds 423 retries: number of retries 424 425 Raises: 426 CommandTimeoutError on timeout. 427 DeviceUnreachableError on missing device. 428 """ 429 package, old_intent = intent.action.rsplit('.', 1) 430 if intent.extras is None: 431 args = [] 432 else: 433 args = ['-e %s%s' % (k, ' "%s"' % v if v else '') 434 for k, v in intent.extras.items() if len(k) > 0] 435 self.old_interface.BroadcastIntent(package, old_intent, *args) 436 437 @decorators.WithTimeoutAndRetriesFromInstance() 438 def GoHome(self, timeout=None, retries=None): 439 """Return to the home screen. 440 441 Args: 442 timeout: timeout in seconds 443 retries: number of retries 444 445 Raises: 446 CommandTimeoutError on timeout. 447 DeviceUnreachableError on missing device. 448 """ 449 self.old_interface.GoHome() 450 451 @decorators.WithTimeoutAndRetriesFromInstance() 452 def ForceStop(self, package, timeout=None, retries=None): 453 """Close the application. 454 455 Args: 456 package: A string containing the name of the package to stop. 457 timeout: timeout in seconds 458 retries: number of retries 459 460 Raises: 461 CommandTimeoutError on timeout. 462 DeviceUnreachableError on missing device. 463 """ 464 self.old_interface.CloseApplication(package) 465 466 @decorators.WithTimeoutAndRetriesFromInstance() 467 def ClearApplicationState(self, package, timeout=None, retries=None): 468 """Clear all state for the given package. 469 470 Args: 471 package: A string containing the name of the package to stop. 472 timeout: timeout in seconds 473 retries: number of retries 474 475 Raises: 476 CommandTimeoutError on timeout. 477 DeviceUnreachableError on missing device. 478 """ 479 self.old_interface.ClearApplicationState(package) 480 481 @decorators.WithTimeoutAndRetriesFromInstance() 482 def SendKeyEvent(self, keycode, timeout=None, retries=None): 483 """Sends a keycode to the device. 484 485 See: http://developer.android.com/reference/android/view/KeyEvent.html 486 487 Args: 488 keycode: A integer keycode to send to the device. 489 timeout: timeout in seconds 490 retries: number of retries 491 492 Raises: 493 CommandTimeoutError on timeout. 494 DeviceUnreachableError on missing device. 495 """ 496 self.old_interface.SendKeyEvent(keycode) 497 498 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT 499 PUSH_CHANGED_FILES_DEFAULT_RETRIES = _DEFAULT_RETRIES 500 501 @decorators.WithTimeoutAndRetriesDefaults( 502 PUSH_CHANGED_FILES_DEFAULT_TIMEOUT, 503 PUSH_CHANGED_FILES_DEFAULT_RETRIES) 504 def PushChangedFiles(self, host_path, device_path, timeout=None, 505 retries=None): 506 """Push files to the device, skipping files that don't need updating. 507 508 Args: 509 host_path: A string containing the absolute path to the file or directory 510 on the host that should be minimally pushed to the device. 511 device_path: A string containing the absolute path of the destination on 512 the device. 513 timeout: timeout in seconds 514 retries: number of retries 515 516 Raises: 517 CommandFailedError on failure. 518 CommandTimeoutError on timeout. 519 DeviceUnreachableError on missing device. 520 """ 521 self.old_interface.PushIfNeeded(host_path, device_path) 522 523 @decorators.WithTimeoutAndRetriesFromInstance() 524 def FileExists(self, device_path, timeout=None, retries=None): 525 """Checks whether the given file exists on the device. 526 527 Args: 528 device_path: A string containing the absolute path to the file on the 529 device. 530 timeout: timeout in seconds 531 retries: number of retries 532 533 Returns: 534 True if the file exists on the device, False otherwise. 535 536 Raises: 537 CommandTimeoutError on timeout. 538 DeviceUnreachableError on missing device. 539 """ 540 return self._FileExistsImpl(device_path) 541 542 def _FileExistsImpl(self, device_path): 543 """Implementation of FileExists. 544 545 This is split from FileExists to allow other DeviceUtils methods to call 546 FileExists without spawning a new timeout thread. 547 548 Args: 549 device_path: Same as for |FileExists|. 550 551 Returns: 552 True if the file exists on the device, False otherwise. 553 554 Raises: 555 Same as for |FileExists|. 556 """ 557 return self.old_interface.FileExistsOnDevice(device_path) 558 559 @decorators.WithTimeoutAndRetriesFromInstance() 560 def PullFile(self, device_path, host_path, timeout=None, retries=None): 561 """Pull a file from the device. 562 563 Args: 564 device_path: A string containing the absolute path of the file to pull 565 from the device. 566 host_path: A string containing the absolute path of the destination on 567 the host. 568 timeout: timeout in seconds 569 retries: number of retries 570 571 Raises: 572 CommandFailedError on failure. 573 CommandTimeoutError on timeout. 574 """ 575 try: 576 self.old_interface.PullFileFromDevice(device_path, host_path) 577 except AssertionError as e: 578 raise device_errors.CommandFailedError( 579 str(e), device=str(self)), None, sys.exc_info()[2] 580 581 @decorators.WithTimeoutAndRetriesFromInstance() 582 def ReadFile(self, device_path, as_root=False, timeout=None, retries=None): 583 """Reads the contents of a file from the device. 584 585 Args: 586 device_path: A string containing the absolute path of the file to read 587 from the device. 588 as_root: A boolean indicating whether the read should be executed with 589 root privileges. 590 timeout: timeout in seconds 591 retries: number of retries 592 593 Returns: 594 The contents of the file at |device_path| as a list of lines. 595 596 Raises: 597 CommandFailedError if the file can't be read. 598 CommandTimeoutError on timeout. 599 DeviceUnreachableError on missing device. 600 """ 601 # TODO(jbudorick) Evaluate whether we awant to return a list of lines after 602 # the implementation switch, and if file not found should raise exception. 603 if as_root: 604 if not self.old_interface.CanAccessProtectedFileContents(): 605 raise device_errors.CommandFailedError( 606 'Cannot read from %s with root privileges.' % device_path) 607 return self.old_interface.GetProtectedFileContents(device_path) 608 else: 609 return self.old_interface.GetFileContents(device_path) 610 611 @decorators.WithTimeoutAndRetriesFromInstance() 612 def WriteFile(self, device_path, contents, as_root=False, timeout=None, 613 retries=None): 614 """Writes |contents| to a file on the device. 615 616 Args: 617 device_path: A string containing the absolute path to the file to write 618 on the device. 619 contents: A string containing the data to write to the device. 620 as_root: A boolean indicating whether the write should be executed with 621 root privileges. 622 timeout: timeout in seconds 623 retries: number of retries 624 625 Raises: 626 CommandFailedError if the file could not be written on the device. 627 CommandTimeoutError on timeout. 628 DeviceUnreachableError on missing device. 629 """ 630 if as_root: 631 if not self.old_interface.CanAccessProtectedFileContents(): 632 raise device_errors.CommandFailedError( 633 'Cannot write to %s with root privileges.' % device_path) 634 self.old_interface.SetProtectedFileContents(device_path, contents) 635 else: 636 self.old_interface.SetFileContents(device_path, contents) 637 638 @decorators.WithTimeoutAndRetriesFromInstance() 639 def WriteTextFile(self, device_path, text, as_root=False, timeout=None, 640 retries=None): 641 """Writes |text| to a file on the device. 642 643 Assuming that |text| is a small string, this is typically more efficient 644 than |WriteFile|, as no files are pushed into the device. 645 646 Args: 647 device_path: A string containing the absolute path to the file to write 648 on the device. 649 text: A short string of text to write to the file on the device. 650 as_root: A boolean indicating whether the write should be executed with 651 root privileges. 652 timeout: timeout in seconds 653 retries: number of retries 654 655 Raises: 656 CommandFailedError if the file could not be written on the device. 657 CommandTimeoutError on timeout. 658 DeviceUnreachableError on missing device. 659 """ 660 self._RunShellCommandImpl('echo {1} > {0}'.format(device_path, 661 pipes.quote(text)), check_return=True, as_root=as_root) 662 663 @decorators.WithTimeoutAndRetriesFromInstance() 664 def Ls(self, device_path, timeout=None, retries=None): 665 """Lists the contents of a directory on the device. 666 667 Args: 668 device_path: A string containing the path of the directory on the device 669 to list. 670 timeout: timeout in seconds 671 retries: number of retries 672 673 Returns: 674 The contents of the directory specified by |device_path|. 675 676 Raises: 677 CommandTimeoutError on timeout. 678 DeviceUnreachableError on missing device. 679 """ 680 return self.old_interface.ListPathContents(device_path) 681 682 @decorators.WithTimeoutAndRetriesFromInstance() 683 def SetJavaAsserts(self, enabled, timeout=None, retries=None): 684 """Enables or disables Java asserts. 685 686 Args: 687 enabled: A boolean indicating whether Java asserts should be enabled 688 or disabled. 689 timeout: timeout in seconds 690 retries: number of retries 691 692 Returns: 693 True if the device-side property changed and a restart is required as a 694 result, False otherwise. 695 696 Raises: 697 CommandTimeoutError on timeout. 698 """ 699 return self.old_interface.SetJavaAssertsEnabled(enabled) 700 701 @decorators.WithTimeoutAndRetriesFromInstance() 702 def GetProp(self, property_name, timeout=None, retries=None): 703 """Gets a property from the device. 704 705 Args: 706 property_name: A string containing the name of the property to get from 707 the device. 708 timeout: timeout in seconds 709 retries: number of retries 710 711 Returns: 712 The value of the device's |property_name| property. 713 714 Raises: 715 CommandTimeoutError on timeout. 716 """ 717 return self.old_interface.system_properties[property_name] 718 719 @decorators.WithTimeoutAndRetriesFromInstance() 720 def SetProp(self, property_name, value, timeout=None, retries=None): 721 """Sets a property on the device. 722 723 Args: 724 property_name: A string containing the name of the property to set on 725 the device. 726 value: A string containing the value to set to the property on the 727 device. 728 timeout: timeout in seconds 729 retries: number of retries 730 731 Raises: 732 CommandTimeoutError on timeout. 733 """ 734 self.old_interface.system_properties[property_name] = value 735 736 @decorators.WithTimeoutAndRetriesFromInstance() 737 def GetPids(self, process_name, timeout=None, retries=None): 738 """Returns the PIDs of processes with the given name. 739 740 Note that the |process_name| is often the package name. 741 742 Args: 743 process_name: A string containing the process name to get the PIDs for. 744 timeout: timeout in seconds 745 retries: number of retries 746 747 Returns: 748 A dict mapping process name to PID for each process that contained the 749 provided |process_name|. 750 751 Raises: 752 CommandTimeoutError on timeout. 753 DeviceUnreachableError on missing device. 754 """ 755 return self._GetPidsImpl(process_name) 756 757 def _GetPidsImpl(self, process_name): 758 """Implementation of GetPids. 759 760 This is split from GetPids to allow other DeviceUtils methods to call 761 GetPids without spawning a new timeout thread. 762 763 Args: 764 process_name: A string containing the process name to get the PIDs for. 765 766 Returns: 767 A dict mapping process name to PID for each process that contained the 768 provided |process_name|. 769 770 Raises: 771 DeviceUnreachableError on missing device. 772 """ 773 procs_pids = {} 774 for line in self._RunShellCommandImpl('ps'): 775 try: 776 ps_data = line.split() 777 if process_name in ps_data[-1]: 778 procs_pids[ps_data[-1]] = ps_data[1] 779 except IndexError: 780 pass 781 return procs_pids 782 783 @decorators.WithTimeoutAndRetriesFromInstance() 784 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): 785 """Takes a screenshot of the device. 786 787 Args: 788 host_path: A string containing the path on the host to save the 789 screenshot to. If None, a file name will be generated. 790 timeout: timeout in seconds 791 retries: number of retries 792 793 Returns: 794 The name of the file on the host to which the screenshot was saved. 795 796 Raises: 797 CommandFailedError on failure. 798 CommandTimeoutError on timeout. 799 DeviceUnreachableError on missing device. 800 """ 801 return self.old_interface.TakeScreenshot(host_path) 802 803 @decorators.WithTimeoutAndRetriesFromInstance() 804 def GetIOStats(self, timeout=None, retries=None): 805 """Gets cumulative disk IO stats since boot for all processes. 806 807 Args: 808 timeout: timeout in seconds 809 retries: number of retries 810 811 Returns: 812 A dict containing |num_reads|, |num_writes|, |read_ms|, and |write_ms|. 813 814 Raises: 815 CommandTimeoutError on timeout. 816 DeviceUnreachableError on missing device. 817 """ 818 return self.old_interface.GetIoStats() 819 820 @decorators.WithTimeoutAndRetriesFromInstance() 821 def GetMemoryUsageForPid(self, pid, timeout=None, retries=None): 822 """Gets the memory usage for the given PID. 823 824 Args: 825 pid: PID of the process. 826 timeout: timeout in seconds 827 retries: number of retries 828 829 Returns: 830 A 2-tuple containing: 831 - A dict containing the overall memory usage statistics for the PID. 832 - A dict containing memory usage statistics broken down by mapping. 833 834 Raises: 835 CommandTimeoutError on timeout. 836 """ 837 return self.old_interface.GetMemoryUsageForPid(pid) 838 839 def __str__(self): 840 """Returns the device serial.""" 841 s = self.old_interface.GetDevice() 842 if not s: 843 s = self.old_interface.Adb().GetSerialNumber() 844 if s == 'unknown': 845 raise device_errors.NoDevicesError() 846 return s 847 848 @staticmethod 849 def parallel(devices=None, async=False): 850 """Creates a Parallelizer to operate over the provided list of devices. 851 852 If |devices| is either |None| or an empty list, the Parallelizer will 853 operate over all attached devices. 854 855 Args: 856 devices: A list of either DeviceUtils instances or objects from 857 from which DeviceUtils instances can be constructed. If None, 858 all attached devices will be used. 859 async: If true, returns a Parallelizer that runs operations 860 asynchronously. 861 862 Returns: 863 A Parallelizer operating over |devices|. 864 """ 865 if not devices or len(devices) == 0: 866 devices = pylib.android_commands.GetAttachedDevices() 867 parallelizer_type = (parallelizer.Parallelizer if async 868 else parallelizer.SyncParallelizer) 869 return parallelizer_type([ 870 d if isinstance(d, DeviceUtils) else DeviceUtils(d) 871 for d in devices]) 872 873