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

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

Issue 1124763003: Update from https://crrev.com/327068 (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: update nacl, buildtools, fix display_change_notifier_unittest Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 # Copyright 2014 The Chromium Authors. All rights reserved. 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 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 4
5 """Provides a variety of device interactions based on adb. 5 """Provides a variety of device interactions based on adb.
6 6
7 Eventually, this will be based on adb_wrapper. 7 Eventually, this will be based on adb_wrapper.
8 """ 8 """
9 # pylint: disable=unused-argument 9 # pylint: disable=unused-argument
10 10
11 import collections 11 import collections
12 import contextlib 12 import contextlib
13 import itertools 13 import itertools
14 import logging 14 import logging
15 import multiprocessing 15 import multiprocessing
16 import os 16 import os
17 import posixpath 17 import posixpath
18 import re 18 import re
19 import shutil 19 import shutil
20 import sys 20 import sys
21 import tempfile 21 import tempfile
22 import time 22 import time
23 import zipfile 23 import zipfile
24 24
25 import pylib.android_commands 25 import pylib.android_commands
26 from pylib import cmd_helper 26 from pylib import cmd_helper
27 from pylib import constants 27 from pylib import constants
28 from pylib import device_signal
28 from pylib.device import adb_wrapper 29 from pylib.device import adb_wrapper
29 from pylib.device import decorators 30 from pylib.device import decorators
31 from pylib.device import device_blacklist
30 from pylib.device import device_errors 32 from pylib.device import device_errors
31 from pylib.device import intent 33 from pylib.device import intent
32 from pylib.device import logcat_monitor 34 from pylib.device import logcat_monitor
33 from pylib.device.commands import install_commands 35 from pylib.device.commands import install_commands
34 from pylib.utils import apk_helper 36 from pylib.utils import apk_helper
35 from pylib.utils import base_error 37 from pylib.utils import base_error
36 from pylib.utils import device_temp_file 38 from pylib.utils import device_temp_file
37 from pylib.utils import host_utils 39 from pylib.utils import host_utils
38 from pylib.utils import md5sum 40 from pylib.utils import md5sum
39 from pylib.utils import parallelizer 41 from pylib.utils import parallelizer
(...skipping 25 matching lines...) Expand all
65 'enable_command': ( 67 'enable_command': (
66 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' 68 'echo 0x4A > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
67 'echo 1 > /sys/class/power_supply/usb/online'), 69 'echo 1 > /sys/class/power_supply/usb/online'),
68 'disable_command': ( 70 'disable_command': (
69 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && ' 71 'echo 0xCA > /sys/kernel/debug/bq24192/INPUT_SRC_CONT && '
70 'chmod 644 /sys/class/power_supply/usb/online && ' 72 'chmod 644 /sys/class/power_supply/usb/online && '
71 'echo 0 > /sys/class/power_supply/usb/online'), 73 'echo 0 > /sys/class/power_supply/usb/online'),
72 }, 74 },
73 ] 75 ]
74 76
77
75 @decorators.WithExplicitTimeoutAndRetries( 78 @decorators.WithExplicitTimeoutAndRetries(
76 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES) 79 _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
77 def GetAVDs(): 80 def GetAVDs():
78 """Returns a list of Android Virtual Devices. 81 """Returns a list of Android Virtual Devices.
79 82
80 Returns: 83 Returns:
81 A list containing the configured AVDs. 84 A list containing the configured AVDs.
82 """ 85 """
83 lines = cmd_helper.GetCmdOutput([ 86 lines = cmd_helper.GetCmdOutput([
84 os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android'), 87 os.path.join(constants.ANDROID_SDK_ROOT, 'tools', 'android'),
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
161 self.old_interface = pylib.android_commands.AndroidCommands(str(device)) 164 self.old_interface = pylib.android_commands.AndroidCommands(str(device))
162 elif isinstance(device, pylib.android_commands.AndroidCommands): 165 elif isinstance(device, pylib.android_commands.AndroidCommands):
163 self.adb = adb_wrapper.AdbWrapper(device.GetDevice()) 166 self.adb = adb_wrapper.AdbWrapper(device.GetDevice())
164 self.old_interface = device 167 self.old_interface = device
165 else: 168 else:
166 raise ValueError('Unsupported device value: %r' % device) 169 raise ValueError('Unsupported device value: %r' % device)
167 self._commands_installed = None 170 self._commands_installed = None
168 self._default_timeout = default_timeout 171 self._default_timeout = default_timeout
169 self._default_retries = default_retries 172 self._default_retries = default_retries
170 self._cache = {} 173 self._cache = {}
174 self._client_caches = {}
171 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR) 175 assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
172 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR) 176 assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
173 177
174 def __str__(self): 178 def __str__(self):
175 """Returns the device serial.""" 179 """Returns the device serial."""
176 return self.adb.GetDeviceSerial() 180 return self.adb.GetDeviceSerial()
177 181
178 @decorators.WithTimeoutAndRetriesFromInstance() 182 @decorators.WithTimeoutAndRetriesFromInstance()
179 def IsOnline(self, timeout=None, retries=None): 183 def IsOnline(self, timeout=None, retries=None):
180 """Checks whether the device is online. 184 """Checks whether the device is online.
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after
399 retries: number of retries 403 retries: number of retries
400 404
401 Raises: 405 Raises:
402 CommandTimeoutError on timeout. 406 CommandTimeoutError on timeout.
403 DeviceUnreachableError on missing device. 407 DeviceUnreachableError on missing device.
404 """ 408 """
405 def device_offline(): 409 def device_offline():
406 return not self.IsOnline() 410 return not self.IsOnline()
407 411
408 self.adb.Reboot() 412 self.adb.Reboot()
409 self._cache = {} 413 self._ClearCache()
410 timeout_retry.WaitFor(device_offline, wait_period=1) 414 timeout_retry.WaitFor(device_offline, wait_period=1)
411 if block: 415 if block:
412 self.WaitUntilFullyBooted(wifi=wifi) 416 self.WaitUntilFullyBooted(wifi=wifi)
413 417
414 INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT 418 INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT
415 INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES 419 INSTALL_DEFAULT_RETRIES = _DEFAULT_RETRIES
416 420
417 @decorators.WithTimeoutAndRetriesDefaults( 421 @decorators.WithTimeoutAndRetriesDefaults(
418 INSTALL_DEFAULT_TIMEOUT, 422 INSTALL_DEFAULT_TIMEOUT,
419 INSTALL_DEFAULT_RETRIES) 423 INSTALL_DEFAULT_RETRIES)
(...skipping 19 matching lines...) Expand all
439 should_install = bool(self._GetChangedFilesImpl(apk_path, device_path)) 443 should_install = bool(self._GetChangedFilesImpl(apk_path, device_path))
440 if should_install and not reinstall: 444 if should_install and not reinstall:
441 self.adb.Uninstall(package_name) 445 self.adb.Uninstall(package_name)
442 else: 446 else:
443 should_install = True 447 should_install = True
444 if should_install: 448 if should_install:
445 self.adb.Install(apk_path, reinstall=reinstall) 449 self.adb.Install(apk_path, reinstall=reinstall)
446 450
447 @decorators.WithTimeoutAndRetriesFromInstance() 451 @decorators.WithTimeoutAndRetriesFromInstance()
448 def RunShellCommand(self, cmd, check_return=False, cwd=None, env=None, 452 def RunShellCommand(self, cmd, check_return=False, cwd=None, env=None,
449 as_root=False, single_line=False, timeout=None, 453 as_root=False, single_line=False, large_output=False,
450 retries=None): 454 timeout=None, retries=None):
451 """Run an ADB shell command. 455 """Run an ADB shell command.
452 456
453 The command to run |cmd| should be a sequence of program arguments or else 457 The command to run |cmd| should be a sequence of program arguments or else
454 a single string. 458 a single string.
455 459
456 When |cmd| is a sequence, it is assumed to contain the name of the command 460 When |cmd| is a sequence, it is assumed to contain the name of the command
457 to run followed by its arguments. In this case, arguments are passed to the 461 to run followed by its arguments. In this case, arguments are passed to the
458 command exactly as given, without any further processing by the shell. This 462 command exactly as given, without any further processing by the shell. This
459 allows to easily pass arguments containing spaces or special characters 463 allows to easily pass arguments containing spaces or special characters
460 without having to worry about getting quoting right. Whenever possible, it 464 without having to worry about getting quoting right. Whenever possible, it
(...skipping 12 matching lines...) Expand all
473 cmd: A string with the full command to run on the device, or a sequence 477 cmd: A string with the full command to run on the device, or a sequence
474 containing the command and its arguments. 478 containing the command and its arguments.
475 check_return: A boolean indicating whether or not the return code should 479 check_return: A boolean indicating whether or not the return code should
476 be checked. 480 be checked.
477 cwd: The device directory in which the command should be run. 481 cwd: The device directory in which the command should be run.
478 env: The environment variables with which the command should be run. 482 env: The environment variables with which the command should be run.
479 as_root: A boolean indicating whether the shell command should be run 483 as_root: A boolean indicating whether the shell command should be run
480 with root privileges. 484 with root privileges.
481 single_line: A boolean indicating if only a single line of output is 485 single_line: A boolean indicating if only a single line of output is
482 expected. 486 expected.
487 large_output: Uses a work-around for large shell command output. Without
488 this large output will be truncated.
483 timeout: timeout in seconds 489 timeout: timeout in seconds
484 retries: number of retries 490 retries: number of retries
485 491
486 Returns: 492 Returns:
487 If single_line is False, the output of the command as a list of lines, 493 If single_line is False, the output of the command as a list of lines,
488 otherwise, a string with the unique line of output emmited by the command 494 otherwise, a string with the unique line of output emmited by the command
489 (with the optional newline at the end stripped). 495 (with the optional newline at the end stripped).
490 496
491 Raises: 497 Raises:
492 AdbCommandFailedError if check_return is True and the exit code of 498 AdbCommandFailedError if check_return is True and the exit code of
493 the command run on the device is non-zero. 499 the command run on the device is non-zero.
494 CommandFailedError if single_line is True but the output contains two or 500 CommandFailedError if single_line is True but the output contains two or
495 more lines. 501 more lines.
496 CommandTimeoutError on timeout. 502 CommandTimeoutError on timeout.
497 DeviceUnreachableError on missing device. 503 DeviceUnreachableError on missing device.
498 """ 504 """
499 def env_quote(key, value): 505 def env_quote(key, value):
500 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key): 506 if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
501 raise KeyError('Invalid shell variable name %r' % key) 507 raise KeyError('Invalid shell variable name %r' % key)
502 # using double quotes here to allow interpolation of shell variables 508 # using double quotes here to allow interpolation of shell variables
503 return '%s=%s' % (key, cmd_helper.DoubleQuote(value)) 509 return '%s=%s' % (key, cmd_helper.DoubleQuote(value))
504 510
505 def do_run(cmd): 511 def run(cmd):
512 return self.adb.Shell(cmd)
513
514 def handle_check_return(cmd):
506 try: 515 try:
507 return self.adb.Shell(cmd) 516 return run(cmd)
508 except device_errors.AdbCommandFailedError as exc: 517 except device_errors.AdbCommandFailedError as exc:
509 if check_return: 518 if check_return:
510 raise 519 raise
511 else: 520 else:
512 return exc.output 521 return exc.output
513 522
523 def handle_large_command(cmd):
524 if len(cmd) < self._MAX_ADB_COMMAND_LENGTH:
525 return handle_check_return(cmd)
526 else:
527 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
528 self._WriteFileWithPush(script.name, cmd)
529 logging.info('Large shell command will be run from file: %s ...',
530 cmd[:100])
531 return handle_check_return('sh %s' % script.name_quoted)
532
533 def handle_large_output(cmd, large_output_mode):
534 if large_output_mode:
535 with device_temp_file.DeviceTempFile(self.adb) as large_output_file:
536 cmd = '%s > %s' % (cmd, large_output_file.name)
537 logging.info('Large output mode enabled. Will write output to device '
538 ' and read results from file.')
539 handle_large_command(cmd)
540 return self.ReadFile(large_output_file.name)
541 else:
542 try:
543 return handle_large_command(cmd)
544 except device_errors.AdbCommandFailedError as exc:
545 if exc.status is None:
546 logging.exception('No output found for %s', cmd)
547 logging.warning('Attempting to run in large_output mode.')
548 logging.warning('Use RunShellCommand(..., large_output=True) for '
549 'shell commands that expect a lot of output.')
550 return handle_large_output(cmd, True)
551 else:
552 raise
553
514 if not isinstance(cmd, basestring): 554 if not isinstance(cmd, basestring):
515 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd) 555 cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
516 if env: 556 if env:
517 env = ' '.join(env_quote(k, v) for k, v in env.iteritems()) 557 env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
518 cmd = '%s %s' % (env, cmd) 558 cmd = '%s %s' % (env, cmd)
519 if cwd: 559 if cwd:
520 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd) 560 cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
521 if as_root and self.NeedsSU(): 561 if as_root and self.NeedsSU():
522 # "su -c sh -c" allows using shell features in |cmd| 562 # "su -c sh -c" allows using shell features in |cmd|
523 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd) 563 cmd = 'su -c sh -c %s' % cmd_helper.SingleQuote(cmd)
524 if timeout is None:
525 timeout = self._default_timeout
526 564
527 if len(cmd) < self._MAX_ADB_COMMAND_LENGTH: 565 output = handle_large_output(cmd, large_output).splitlines()
528 output = do_run(cmd)
529 else:
530 with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
531 self._WriteFileWithPush(script.name, cmd)
532 logging.info('Large shell command will be run from file: %s ...',
533 cmd[:100])
534 output = do_run('sh %s' % script.name_quoted)
535 566
536 output = output.splitlines()
537 if single_line: 567 if single_line:
538 if not output: 568 if not output:
539 return '' 569 return ''
540 elif len(output) == 1: 570 elif len(output) == 1:
541 return output[0] 571 return output[0]
542 else: 572 else:
543 msg = 'one line of output was expected, but got: %s' 573 msg = 'one line of output was expected, but got: %s'
544 raise device_errors.CommandFailedError(msg % output, str(self)) 574 raise device_errors.CommandFailedError(msg % output, str(self))
545 else: 575 else:
546 return output 576 return output
547 577
578 def _RunPipedShellCommand(self, script, **kwargs):
579 PIPESTATUS_LEADER = 'PIPESTATUS: '
580
581 script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER
582 kwargs['check_return'] = True
583 output = self.RunShellCommand(script, **kwargs)
584 pipestatus_line = output[-1]
585
586 if not pipestatus_line.startswith(PIPESTATUS_LEADER):
587 logging.error('Pipe exit statuses of shell script missing.')
588 raise device_errors.AdbShellCommandFailedError(
589 script, output, status=None,
590 device_serial=self.adb.GetDeviceSerial())
591
592 output = output[:-1]
593 statuses = [
594 int(s) for s in pipestatus_line[len(PIPESTATUS_LEADER):].split()]
595 if any(statuses):
596 raise device_errors.AdbShellCommandFailedError(
597 script, output, status=statuses,
598 device_serial=self.adb.GetDeviceSerial())
599 return output
600
548 @decorators.WithTimeoutAndRetriesFromInstance() 601 @decorators.WithTimeoutAndRetriesFromInstance()
549 def KillAll(self, process_name, signum=9, as_root=False, blocking=False, 602 def KillAll(self, process_name, signum=device_signal.SIGKILL, as_root=False,
550 timeout=None, retries=None): 603 blocking=False, quiet=False, timeout=None, retries=None):
551 """Kill all processes with the given name on the device. 604 """Kill all processes with the given name on the device.
552 605
553 Args: 606 Args:
554 process_name: A string containing the name of the process to kill. 607 process_name: A string containing the name of the process to kill.
555 signum: An integer containing the signal number to send to kill. Defaults 608 signum: An integer containing the signal number to send to kill. Defaults
556 to 9 (SIGKILL). 609 to SIGKILL (9).
557 as_root: A boolean indicating whether the kill should be executed with 610 as_root: A boolean indicating whether the kill should be executed with
558 root privileges. 611 root privileges.
559 blocking: A boolean indicating whether we should wait until all processes 612 blocking: A boolean indicating whether we should wait until all processes
560 with the given |process_name| are dead. 613 with the given |process_name| are dead.
614 quiet: A boolean indicating whether to ignore the fact that no processes
615 to kill were found.
561 timeout: timeout in seconds 616 timeout: timeout in seconds
562 retries: number of retries 617 retries: number of retries
563 618
619 Returns:
620 The number of processes attempted to kill.
621
564 Raises: 622 Raises:
565 CommandFailedError if no process was killed. 623 CommandFailedError if no process was killed and |quiet| is False.
566 CommandTimeoutError on timeout. 624 CommandTimeoutError on timeout.
567 DeviceUnreachableError on missing device. 625 DeviceUnreachableError on missing device.
568 """ 626 """
569 pids = self._GetPidsImpl(process_name) 627 pids = self.GetPids(process_name)
570 if not pids: 628 if not pids:
571 raise device_errors.CommandFailedError( 629 if quiet:
572 'No process "%s"' % process_name, str(self)) 630 return 0
631 else:
632 raise device_errors.CommandFailedError(
633 'No process "%s"' % process_name, str(self))
573 634
574 cmd = ['kill', '-%d' % signum] + pids.values() 635 cmd = ['kill', '-%d' % signum] + pids.values()
575 self.RunShellCommand(cmd, as_root=as_root, check_return=True) 636 self.RunShellCommand(cmd, as_root=as_root, check_return=True)
576 637
577 if blocking: 638 if blocking:
639 # TODO(perezu): use timeout_retry.WaitFor
578 wait_period = 0.1 640 wait_period = 0.1
579 while self._GetPidsImpl(process_name): 641 while self.GetPids(process_name):
580 time.sleep(wait_period) 642 time.sleep(wait_period)
581 643
582 return len(pids) 644 return len(pids)
583 645
584 @decorators.WithTimeoutAndRetriesFromInstance() 646 @decorators.WithTimeoutAndRetriesFromInstance()
585 def StartActivity(self, intent_obj, blocking=False, trace_file_name=None, 647 def StartActivity(self, intent_obj, blocking=False, trace_file_name=None,
586 force_stop=False, timeout=None, retries=None): 648 force_stop=False, timeout=None, retries=None):
587 """Start package's activity on the device. 649 """Start package's activity on the device.
588 650
589 Args: 651 Args:
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
784 def _GetChangedFilesImpl(self, host_path, device_path): 846 def _GetChangedFilesImpl(self, host_path, device_path):
785 real_host_path = os.path.realpath(host_path) 847 real_host_path = os.path.realpath(host_path)
786 try: 848 try:
787 real_device_path = self.RunShellCommand( 849 real_device_path = self.RunShellCommand(
788 ['realpath', device_path], single_line=True, check_return=True) 850 ['realpath', device_path], single_line=True, check_return=True)
789 except device_errors.CommandFailedError: 851 except device_errors.CommandFailedError:
790 real_device_path = None 852 real_device_path = None
791 if not real_device_path: 853 if not real_device_path:
792 return [(host_path, device_path)] 854 return [(host_path, device_path)]
793 855
794 host_hash_tuples = md5sum.CalculateHostMd5Sums([real_host_path]) 856 host_checksums = md5sum.CalculateHostMd5Sums([real_host_path])
795 device_paths_to_md5 = ( 857 device_paths_to_md5 = (
796 real_device_path if os.path.isfile(real_host_path) 858 real_device_path if os.path.isfile(real_host_path)
797 else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path)) 859 else ('%s/%s' % (real_device_path, os.path.relpath(p, real_host_path))
798 for _, p in host_hash_tuples)) 860 for p in host_checksums.iterkeys()))
799 device_hash_tuples = md5sum.CalculateDeviceMd5Sums( 861 device_checksums = md5sum.CalculateDeviceMd5Sums(
800 device_paths_to_md5, self) 862 device_paths_to_md5, self)
801 863
802 if os.path.isfile(host_path): 864 if os.path.isfile(host_path):
803 if (not device_hash_tuples 865 host_checksum = host_checksums.get(real_host_path)
804 or device_hash_tuples[0].hash != host_hash_tuples[0].hash): 866 device_checksum = device_checksums.get(real_device_path)
867 if host_checksum != device_checksum:
805 return [(host_path, device_path)] 868 return [(host_path, device_path)]
806 else: 869 else:
807 return [] 870 return []
808 else: 871 else:
809 device_tuple_dict = dict((d.path, d.hash) for d in device_hash_tuples)
810 to_push = [] 872 to_push = []
811 for host_hash, host_abs_path in ( 873 for host_abs_path, host_checksum in host_checksums.iteritems():
812 (h.hash, h.path) for h in host_hash_tuples):
813 device_abs_path = '%s/%s' % ( 874 device_abs_path = '%s/%s' % (
814 real_device_path, os.path.relpath(host_abs_path, real_host_path)) 875 real_device_path, os.path.relpath(host_abs_path, real_host_path))
815 if (device_abs_path not in device_tuple_dict 876 if (device_checksums.get(device_abs_path) != host_checksum):
816 or device_tuple_dict[device_abs_path] != host_hash):
817 to_push.append((host_abs_path, device_abs_path)) 877 to_push.append((host_abs_path, device_abs_path))
818 return to_push 878 return to_push
819 879
820 def _InstallCommands(self): 880 def _InstallCommands(self):
821 if self._commands_installed is None: 881 if self._commands_installed is None:
822 try: 882 try:
823 if not install_commands.Installed(self): 883 if not install_commands.Installed(self):
824 install_commands.InstallCommands(self) 884 install_commands.InstallCommands(self)
825 self._commands_installed = True 885 self._commands_installed = True
826 except Exception as e: 886 except Exception as e:
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
984 ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root, 1044 ls_out = self.RunShellCommand(['ls', '-l', device_path], as_root=as_root,
985 check_return=True) 1045 check_return=True)
986 for line in ls_out: 1046 for line in ls_out:
987 m = self._LS_RE.match(line) 1047 m = self._LS_RE.match(line)
988 if m and m.group('name') == posixpath.basename(device_path): 1048 if m and m.group('name') == posixpath.basename(device_path):
989 size = int(m.group('size')) 1049 size = int(m.group('size'))
990 break 1050 break
991 else: 1051 else:
992 logging.warning('Could not determine size of %s.', device_path) 1052 logging.warning('Could not determine size of %s.', device_path)
993 1053
994 if size is None or size <= self._MAX_ADB_OUTPUT_LENGTH: 1054 if 0 < size <= self._MAX_ADB_OUTPUT_LENGTH:
995 return _JoinLines(self.RunShellCommand( 1055 return _JoinLines(self.RunShellCommand(
996 ['cat', device_path], as_root=as_root, check_return=True)) 1056 ['cat', device_path], as_root=as_root, check_return=True))
997 elif as_root and self.NeedsSU(): 1057 elif as_root and self.NeedsSU():
998 with device_temp_file.DeviceTempFile(self.adb) as device_temp: 1058 with device_temp_file.DeviceTempFile(self.adb) as device_temp:
999 self.RunShellCommand(['cp', device_path, device_temp.name], 1059 self.RunShellCommand(['cp', device_path, device_temp.name],
1000 as_root=True, check_return=True) 1060 as_root=True, check_return=True)
1001 return self._ReadFileWithPull(device_temp.name) 1061 return self._ReadFileWithPull(device_temp.name)
1002 else: 1062 else:
1003 return self._ReadFileWithPull(device_path) 1063 return self._ReadFileWithPull(device_path)
1004 1064
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
1319 retries: number of retries 1379 retries: number of retries
1320 1380
1321 Returns: 1381 Returns:
1322 A dict mapping process name to PID for each process that contained the 1382 A dict mapping process name to PID for each process that contained the
1323 provided |process_name|. 1383 provided |process_name|.
1324 1384
1325 Raises: 1385 Raises:
1326 CommandTimeoutError on timeout. 1386 CommandTimeoutError on timeout.
1327 DeviceUnreachableError on missing device. 1387 DeviceUnreachableError on missing device.
1328 """ 1388 """
1329 return self._GetPidsImpl(process_name) 1389 procs_pids = {}
1390 try:
1391 ps_output = self._RunPipedShellCommand(
1392 'ps | grep -F %s' % cmd_helper.SingleQuote(process_name))
1393 except device_errors.AdbShellCommandFailedError as e:
1394 if e.status and isinstance(e.status, list) and not e.status[0]:
1395 # If ps succeeded but grep failed, there were no processes with the
1396 # given name.
1397 return procs_pids
1398 else:
1399 raise
1330 1400
1331 def _GetPidsImpl(self, process_name): 1401 for line in ps_output:
1332 procs_pids = {}
1333 for line in self.RunShellCommand('ps', check_return=True):
1334 try: 1402 try:
1335 ps_data = line.split() 1403 ps_data = line.split()
1336 if process_name in ps_data[-1]: 1404 if process_name in ps_data[-1]:
1337 procs_pids[ps_data[-1]] = ps_data[1] 1405 procs_pids[ps_data[-1]] = ps_data[1]
1338 except IndexError: 1406 except IndexError:
1339 pass 1407 pass
1340 return procs_pids 1408 return procs_pids
1341 1409
1342 @decorators.WithTimeoutAndRetriesFromInstance() 1410 @decorators.WithTimeoutAndRetriesFromInstance()
1343 def TakeScreenshot(self, host_path=None, timeout=None, retries=None): 1411 def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
1395 except device_errors.CommandFailedError: 1463 except device_errors.CommandFailedError:
1396 logging.exception('Error getting memory usage from status') 1464 logging.exception('Error getting memory usage from status')
1397 1465
1398 return result 1466 return result
1399 1467
1400 def _GetMemoryUsageForPidFromSmaps(self, pid): 1468 def _GetMemoryUsageForPidFromSmaps(self, pid):
1401 SMAPS_COLUMNS = ( 1469 SMAPS_COLUMNS = (
1402 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean', 1470 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean',
1403 'Private_Dirty') 1471 'Private_Dirty')
1404 1472
1405 showmap_out = self.RunShellCommand( 1473 showmap_out = self._RunPipedShellCommand(
1406 ['showmap', str(pid)], as_root=True, check_return=True) 1474 'showmap %d | grep TOTAL' % int(pid), as_root=True)
1407 if not showmap_out:
1408 raise device_errors.CommandFailedError('No output from showmap')
1409 1475
1410 split_totals = showmap_out[-1].split() 1476 split_totals = showmap_out[-1].split()
1411 if (not split_totals 1477 if (not split_totals
1412 or len(split_totals) != 9 1478 or len(split_totals) != 9
1413 or split_totals[-1] != 'TOTAL'): 1479 or split_totals[-1] != 'TOTAL'):
1414 raise device_errors.CommandFailedError( 1480 raise device_errors.CommandFailedError(
1415 'Invalid output from showmap: %s' % '\n'.join(showmap_out)) 1481 'Invalid output from showmap: %s' % '\n'.join(showmap_out))
1416 1482
1417 return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals))) 1483 return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals)))
1418 1484
(...skipping 13 matching lines...) Expand all
1432 Parameters passed to this function are passed directly to 1498 Parameters passed to this function are passed directly to
1433 |logcat_monitor.LogcatMonitor| and are documented there. 1499 |logcat_monitor.LogcatMonitor| and are documented there.
1434 1500
1435 Args: 1501 Args:
1436 timeout: timeout in seconds 1502 timeout: timeout in seconds
1437 retries: number of retries 1503 retries: number of retries
1438 """ 1504 """
1439 return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs) 1505 return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs)
1440 1506
1441 @decorators.WithTimeoutAndRetriesFromInstance() 1507 @decorators.WithTimeoutAndRetriesFromInstance()
1442 def GetBatteryInfo(self, timeout=None, retries=None):
1443 """Gets battery info for the device.
1444
1445 Args:
1446 timeout: timeout in seconds
1447 retries: number of retries
1448 Returns:
1449 A dict containing various battery information as reported by dumpsys
1450 battery.
1451 """
1452 result = {}
1453 # Skip the first line, which is just a header.
1454 for line in self.RunShellCommand(
1455 ['dumpsys', 'battery'], check_return=True)[1:]:
1456 # If usb charging has been disabled, an extra line of header exists.
1457 if 'UPDATES STOPPED' in line:
1458 logging.warning('Dumpsys battery not receiving updates. '
1459 'Run dumpsys battery reset if this is in error.')
1460 elif ':' not in line:
1461 logging.warning('Unknown line found in dumpsys battery.')
1462 logging.warning(line)
1463 else:
1464 k, v = line.split(': ', 1)
1465 result[k.strip()] = v.strip()
1466 return result
1467
1468 @decorators.WithTimeoutAndRetriesFromInstance()
1469 def GetCharging(self, timeout=None, retries=None):
1470 """Gets the charging state of the device.
1471
1472 Args:
1473 timeout: timeout in seconds
1474 retries: number of retries
1475 Returns:
1476 True if the device is charging, false otherwise.
1477 """
1478 battery_info = self.GetBatteryInfo()
1479 for k in ('AC powered', 'USB powered', 'Wireless powered'):
1480 if (k in battery_info and
1481 battery_info[k].lower() in ('true', '1', 'yes')):
1482 return True
1483 return False
1484
1485 @decorators.WithTimeoutAndRetriesFromInstance()
1486 def SetCharging(self, enabled, timeout=None, retries=None):
1487 """Enables or disables charging on the device.
1488
1489 Args:
1490 enabled: A boolean indicating whether charging should be enabled or
1491 disabled.
1492 timeout: timeout in seconds
1493 retries: number of retries
1494 """
1495 if 'charging_config' not in self._cache:
1496 for c in _CONTROL_CHARGING_COMMANDS:
1497 if self.FileExists(c['witness_file']):
1498 self._cache['charging_config'] = c
1499 break
1500 else:
1501 raise device_errors.CommandFailedError(
1502 'Unable to find charging commands.')
1503
1504 if enabled:
1505 command = self._cache['charging_config']['enable_command']
1506 else:
1507 command = self._cache['charging_config']['disable_command']
1508
1509 def set_and_verify_charging():
1510 self.RunShellCommand(command, check_return=True)
1511 return self.GetCharging() == enabled
1512
1513 timeout_retry.WaitFor(set_and_verify_charging, wait_period=1)
1514
1515 # TODO(rnephew): Make private when all use cases can use the context manager.
1516 @decorators.WithTimeoutAndRetriesFromInstance()
1517 def DisableBatteryUpdates(self, timeout=None, retries=None):
1518 """ Resets battery data and makes device appear like it is not
1519 charging so that it will collect power data since last charge.
1520
1521 Args:
1522 timeout: timeout in seconds
1523 retries: number of retries
1524 """
1525 def battery_updates_disabled():
1526 return self.GetCharging() is False
1527
1528 self.RunShellCommand(
1529 ['dumpsys', 'batterystats', '--reset'], check_return=True)
1530 battery_data = self.RunShellCommand(
1531 ['dumpsys', 'batterystats', '--charged', '--checkin'],
1532 check_return=True)
1533 ROW_TYPE_INDEX = 3
1534 PWI_POWER_INDEX = 5
1535 for line in battery_data:
1536 l = line.split(',')
1537 if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi'
1538 and l[PWI_POWER_INDEX] != 0):
1539 raise device_errors.CommandFailedError(
1540 'Non-zero pmi value found after reset.')
1541 self.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'],
1542 check_return=True)
1543 timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
1544
1545 # TODO(rnephew): Make private when all use cases can use the context manager.
1546 @decorators.WithTimeoutAndRetriesFromInstance()
1547 def EnableBatteryUpdates(self, timeout=None, retries=None):
1548 """ Restarts device charging so that dumpsys no longer collects power data.
1549
1550 Args:
1551 timeout: timeout in seconds
1552 retries: number of retries
1553 """
1554 def battery_updates_enabled():
1555 return self.GetCharging() is True
1556
1557 self.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '1'],
1558 check_return=True)
1559 self.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True)
1560 timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
1561
1562 @contextlib.contextmanager
1563 def BatteryMeasurement(self, timeout=None, retries=None):
1564 """Context manager that enables battery data collection. It makes
1565 the device appear to stop charging so that dumpsys will start collecting
1566 power data since last charge. Once the with block is exited, charging is
1567 resumed and power data since last charge is no longer collected.
1568
1569 Only for devices L and higher.
1570
1571 Example usage:
1572 with BatteryMeasurement():
1573 browser_actions()
1574 get_power_data() # report usage within this block
1575 after_measurements() # Anything that runs after power
1576 # measurements are collected
1577
1578 Args:
1579 timeout: timeout in seconds
1580 retries: number of retries
1581 """
1582 if self.build_version_sdk < constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP:
1583 raise device_errors.CommandFailedError('Device must be L or higher.')
1584 try:
1585 self.DisableBatteryUpdates(timeout=timeout, retries=retries)
1586 yield
1587 finally:
1588 self.EnableBatteryUpdates(timeout=timeout, retries=retries)
1589
1590 @decorators.WithTimeoutAndRetriesFromInstance()
1591 def GetDevicePieWrapper(self, timeout=None, retries=None): 1508 def GetDevicePieWrapper(self, timeout=None, retries=None):
1592 """Gets the absolute path to the run_pie wrapper on the device. 1509 """Gets the absolute path to the run_pie wrapper on the device.
1593 1510
1594 We have to build our device executables to be PIE, but they need to be able 1511 We have to build our device executables to be PIE, but they need to be able
1595 to run on versions of android that don't support PIE (i.e. ICS and below). 1512 to run on versions of android that don't support PIE (i.e. ICS and below).
1596 To do so, we push a wrapper to the device that lets older android versions 1513 To do so, we push a wrapper to the device that lets older android versions
1597 run PIE executables. This method pushes that wrapper to the device if 1514 run PIE executables. This method pushes that wrapper to the device if
1598 necessary and returns the path to it. 1515 necessary and returns the path to it.
1599 1516
1600 This is exposed publicly to allow clients to write scripts using run_pie 1517 This is exposed publicly to allow clients to write scripts using run_pie
(...skipping 14 matching lines...) Expand all
1615 host_pie_path = os.path.join(constants.GetOutDirectory(), 'run_pie') 1532 host_pie_path = os.path.join(constants.GetOutDirectory(), 'run_pie')
1616 if not os.path.exists(host_pie_path): 1533 if not os.path.exists(host_pie_path):
1617 raise device_errors.CommandFailedError('Please build run_pie') 1534 raise device_errors.CommandFailedError('Please build run_pie')
1618 pie = '%s/run_pie' % constants.TEST_EXECUTABLE_DIR 1535 pie = '%s/run_pie' % constants.TEST_EXECUTABLE_DIR
1619 self.adb.Push(host_pie_path, pie) 1536 self.adb.Push(host_pie_path, pie)
1620 1537
1621 self._cache['run_pie'] = pie 1538 self._cache['run_pie'] = pie
1622 1539
1623 return self._cache['run_pie'] 1540 return self._cache['run_pie']
1624 1541
1542 def GetClientCache(self, client_name):
1543 """Returns client cache."""
1544 if client_name not in self._client_caches:
1545 self._client_caches[client_name] = {}
1546 return self._client_caches[client_name]
1547
1548 def _ClearCache(self):
1549 """Clears all caches."""
1550 for client in self._client_caches:
1551 self._client_caches[client].clear()
1552 self._cache.clear()
1553
1625 @classmethod 1554 @classmethod
1626 def parallel(cls, devices=None, async=False): 1555 def parallel(cls, devices=None, async=False):
1627 """Creates a Parallelizer to operate over the provided list of devices. 1556 """Creates a Parallelizer to operate over the provided list of devices.
1628 1557
1629 If |devices| is either |None| or an empty list, the Parallelizer will 1558 If |devices| is either |None| or an empty list, the Parallelizer will
1630 operate over all attached devices. 1559 operate over all attached devices that have not been blacklisted.
1631 1560
1632 Args: 1561 Args:
1633 devices: A list of either DeviceUtils instances or objects from 1562 devices: A list of either DeviceUtils instances or objects from
1634 from which DeviceUtils instances can be constructed. If None, 1563 from which DeviceUtils instances can be constructed. If None,
1635 all attached devices will be used. 1564 all attached devices will be used.
1636 async: If true, returns a Parallelizer that runs operations 1565 async: If true, returns a Parallelizer that runs operations
1637 asynchronously. 1566 asynchronously.
1638 1567
1639 Returns: 1568 Returns:
1640 A Parallelizer operating over |devices|. 1569 A Parallelizer operating over |devices|.
1641 """ 1570 """
1642 if not devices: 1571 if not devices:
1643 devices = adb_wrapper.AdbWrapper.GetDevices() 1572 devices = cls.HealthyDevices()
1644 if not devices: 1573 if not devices:
1645 raise device_errors.NoDevicesError() 1574 raise device_errors.NoDevicesError()
1575
1646 devices = [d if isinstance(d, cls) else cls(d) for d in devices] 1576 devices = [d if isinstance(d, cls) else cls(d) for d in devices]
1647 if async: 1577 if async:
1648 return parallelizer.Parallelizer(devices) 1578 return parallelizer.Parallelizer(devices)
1649 else: 1579 else:
1650 return parallelizer.SyncParallelizer(devices) 1580 return parallelizer.SyncParallelizer(devices)
1581
1582 @classmethod
1583 def HealthyDevices(cls):
1584 blacklist = device_blacklist.ReadBlacklist()
1585 def blacklisted(adb):
1586 if adb.GetDeviceSerial() in blacklist:
1587 logging.warning('Device %s is blacklisted.', adb.GetDeviceSerial())
1588 return True
1589 return False
1590
1591 return [cls(adb) for adb in adb_wrapper.AdbWrapper.Devices()
1592 if not blacklisted(adb)]
1593
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698