Home | History | Annotate | Download | only in android
      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 
      7 Eventually, this will be based on adb_wrapper.
      8 """
      9 # pylint: disable=unused-argument
     10 
     11 import calendar
     12 import collections
     13 import itertools
     14 import json
     15 import logging
     16 import multiprocessing
     17 import os
     18 import posixpath
     19 import pprint
     20 import re
     21 import shutil
     22 import stat
     23 import tempfile
     24 import time
     25 import threading
     26 import uuid
     27 import zipfile
     28 
     29 from devil import base_error
     30 from devil import devil_env
     31 from devil.utils import cmd_helper
     32 from devil.android import apk_helper
     33 from devil.android import device_signal
     34 from devil.android import decorators
     35 from devil.android import device_errors
     36 from devil.android import device_temp_file
     37 from devil.android import install_commands
     38 from devil.android import logcat_monitor
     39 from devil.android import md5sum
     40 from devil.android.constants import chrome
     41 from devil.android.sdk import adb_wrapper
     42 from devil.android.sdk import gce_adb_wrapper
     43 from devil.android.sdk import intent
     44 from devil.android.sdk import keyevent
     45 from devil.android.sdk import split_select
     46 from devil.android.sdk import version_codes
     47 from devil.utils import host_utils
     48 from devil.utils import parallelizer
     49 from devil.utils import reraiser_thread
     50 from devil.utils import timeout_retry
     51 from devil.utils import zip_utils
     52 
     53 logger = logging.getLogger(__name__)
     54 
     55 _DEFAULT_TIMEOUT = 30
     56 _DEFAULT_RETRIES = 3
     57 
     58 # A sentinel object for default values
     59 # TODO(jbudorick,perezju): revisit how default values are handled by
     60 # the timeout_retry decorators.
     61 DEFAULT = object()
     62 
     63 _RESTART_ADBD_SCRIPT = """
     64   trap '' HUP
     65   trap '' TERM
     66   trap '' PIPE
     67   function restart() {
     68     stop adbd
     69     start adbd
     70   }
     71   restart &
     72 """
     73 
     74 # Not all permissions can be set.
     75 _PERMISSIONS_BLACKLIST = [
     76     'android.permission.ACCESS_LOCATION_EXTRA_COMMANDS',
     77     'android.permission.ACCESS_MOCK_LOCATION',
     78     'android.permission.ACCESS_NETWORK_STATE',
     79     'android.permission.ACCESS_NOTIFICATION_POLICY',
     80     'android.permission.ACCESS_WIFI_STATE',
     81     'android.permission.AUTHENTICATE_ACCOUNTS',
     82     'android.permission.BLUETOOTH',
     83     'android.permission.BLUETOOTH_ADMIN',
     84     'android.permission.BROADCAST_STICKY',
     85     'android.permission.CHANGE_NETWORK_STATE',
     86     'android.permission.CHANGE_WIFI_MULTICAST_STATE',
     87     'android.permission.CHANGE_WIFI_STATE',
     88     'android.permission.DISABLE_KEYGUARD',
     89     'android.permission.DOWNLOAD_WITHOUT_NOTIFICATION',
     90     'android.permission.EXPAND_STATUS_BAR',
     91     'android.permission.GET_PACKAGE_SIZE',
     92     'android.permission.INSTALL_SHORTCUT',
     93     'android.permission.INTERNET',
     94     'android.permission.KILL_BACKGROUND_PROCESSES',
     95     'android.permission.MANAGE_ACCOUNTS',
     96     'android.permission.MODIFY_AUDIO_SETTINGS',
     97     'android.permission.NFC',
     98     'android.permission.READ_SYNC_SETTINGS',
     99     'android.permission.READ_SYNC_STATS',
    100     'android.permission.RECEIVE_BOOT_COMPLETED',
    101     'android.permission.RECORD_VIDEO',
    102     'android.permission.REORDER_TASKS',
    103     'android.permission.REQUEST_INSTALL_PACKAGES',
    104     'android.permission.RUN_INSTRUMENTATION',
    105     'android.permission.SET_ALARM',
    106     'android.permission.SET_TIME_ZONE',
    107     'android.permission.SET_WALLPAPER',
    108     'android.permission.SET_WALLPAPER_HINTS',
    109     'android.permission.TRANSMIT_IR',
    110     'android.permission.USE_CREDENTIALS',
    111     'android.permission.USE_FINGERPRINT',
    112     'android.permission.VIBRATE',
    113     'android.permission.WAKE_LOCK',
    114     'android.permission.WRITE_SYNC_SETTINGS',
    115     'com.android.browser.permission.READ_HISTORY_BOOKMARKS',
    116     'com.android.browser.permission.WRITE_HISTORY_BOOKMARKS',
    117     'com.android.launcher.permission.INSTALL_SHORTCUT',
    118     'com.chrome.permission.DEVICE_EXTRAS',
    119     'com.google.android.apps.now.CURRENT_ACCOUNT_ACCESS',
    120     'com.google.android.c2dm.permission.RECEIVE',
    121     'com.google.android.providers.gsf.permission.READ_GSERVICES',
    122     'com.sec.enterprise.knox.MDM_CONTENT_PROVIDER',
    123 ]
    124 for package_info in chrome.PACKAGE_INFO.itervalues():
    125   _PERMISSIONS_BLACKLIST.extend([
    126       '%s.permission.C2D_MESSAGE' % package_info.package,
    127       '%s.permission.READ_WRITE_BOOKMARK_FOLDERS' % package_info.package,
    128       '%s.TOS_ACKED' % package_info.package])
    129 
    130 _CURRENT_FOCUS_CRASH_RE = re.compile(
    131     r'\s*mCurrentFocus.*Application (Error|Not Responding): (\S+)}')
    132 
    133 _GETPROP_RE = re.compile(r'\[(.*?)\]: \[(.*?)\]')
    134 _IPV4_ADDRESS_RE = re.compile(r'([0-9]{1,3}\.){3}[0-9]{1,3}\:[0-9]{4,5}')
    135 
    136 # Regex to parse the long (-l) output of 'ls' command, c.f.
    137 # https://github.com/landley/toybox/blob/master/toys/posix/ls.c#L446
    138 _LONG_LS_OUTPUT_RE = re.compile(
    139     r'(?P<st_mode>[\w-]{10})\s+'                  # File permissions
    140     r'(?:(?P<st_nlink>\d+)\s+)?'                  # Number of links (optional)
    141     r'(?P<st_owner>\w+)\s+'                       # Name of owner
    142     r'(?P<st_group>\w+)\s+'                       # Group of owner
    143     r'(?:'                                        # Either ...
    144       r'(?P<st_rdev_major>\d+),\s+'                 # Device major, and
    145       r'(?P<st_rdev_minor>\d+)\s+'                  # Device minor
    146     r'|'                                          # .. or
    147       r'(?P<st_size>\d+)\s+'                        # Size in bytes
    148     r')?'                                         # .. or nothing
    149     r'(?P<st_mtime>\d{4}-\d\d-\d\d \d\d:\d\d)\s+' # Modification date/time
    150     r'(?P<filename>.+?)'                          # File name
    151     r'(?: -> (?P<symbolic_link_to>.+))?'          # Symbolic link (optional)
    152     r'$'                                          # End of string
    153 )
    154 _LS_DATE_FORMAT = '%Y-%m-%d %H:%M'
    155 _FILE_MODE_RE = re.compile(r'[dbclps-](?:[r-][w-][xSs-]){2}[r-][w-][xTt-]$')
    156 _FILE_MODE_KIND = {
    157     'd': stat.S_IFDIR, 'b': stat.S_IFBLK, 'c': stat.S_IFCHR,
    158     'l': stat.S_IFLNK, 'p': stat.S_IFIFO, 's': stat.S_IFSOCK,
    159     '-': stat.S_IFREG}
    160 _FILE_MODE_PERMS = [
    161     stat.S_IRUSR, stat.S_IWUSR, stat.S_IXUSR,
    162     stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
    163     stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH,
    164 ]
    165 _FILE_MODE_SPECIAL = [
    166     ('s', stat.S_ISUID),
    167     ('s', stat.S_ISGID),
    168     ('t', stat.S_ISVTX),
    169 ]
    170 _SELINUX_MODE = {
    171     'enforcing': True,
    172     'permissive': False,
    173     'disabled': None
    174 }
    175 # Some devices require different logic for checking if root is necessary
    176 _SPECIAL_ROOT_DEVICE_LIST = [
    177     'marlin',
    178     'sailfish',
    179 ]
    180 
    181 
    182 @decorators.WithExplicitTimeoutAndRetries(
    183     _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
    184 def GetAVDs():
    185   """Returns a list of Android Virtual Devices.
    186 
    187   Returns:
    188     A list containing the configured AVDs.
    189   """
    190   lines = cmd_helper.GetCmdOutput([
    191       os.path.join(devil_env.config.LocalPath('android_sdk'),
    192                    'tools', 'android'),
    193       'list', 'avd']).splitlines()
    194   avds = []
    195   for line in lines:
    196     if 'Name:' not in line:
    197       continue
    198     key, value = (s.strip() for s in line.split(':', 1))
    199     if key == 'Name':
    200       avds.append(value)
    201   return avds
    202 
    203 
    204 @decorators.WithExplicitTimeoutAndRetries(
    205     _DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
    206 def RestartServer():
    207   """Restarts the adb server.
    208 
    209   Raises:
    210     CommandFailedError if we fail to kill or restart the server.
    211   """
    212   def adb_killed():
    213     return not adb_wrapper.AdbWrapper.IsServerOnline()
    214 
    215   def adb_started():
    216     return adb_wrapper.AdbWrapper.IsServerOnline()
    217 
    218   adb_wrapper.AdbWrapper.KillServer()
    219   if not timeout_retry.WaitFor(adb_killed, wait_period=1, max_tries=5):
    220     # TODO(perezju): raise an exception after fixng http://crbug.com/442319
    221     logger.warning('Failed to kill adb server')
    222   adb_wrapper.AdbWrapper.StartServer()
    223   if not timeout_retry.WaitFor(adb_started, wait_period=1, max_tries=5):
    224     raise device_errors.CommandFailedError('Failed to start adb server')
    225 
    226 
    227 def _ParseModeString(mode_str):
    228   """Parse a mode string, e.g. 'drwxrwxrwx', into a st_mode value.
    229 
    230   Effectively the reverse of |mode_to_string| in, e.g.:
    231   https://github.com/landley/toybox/blob/master/lib/lib.c#L896
    232   """
    233   if not _FILE_MODE_RE.match(mode_str):
    234     raise ValueError('Unexpected file mode %r', mode_str)
    235   mode = _FILE_MODE_KIND[mode_str[0]]
    236   for c, flag in zip(mode_str[1:], _FILE_MODE_PERMS):
    237     if c != '-' and c.islower():
    238       mode |= flag
    239   for c, (t, flag) in zip(mode_str[3::3], _FILE_MODE_SPECIAL):
    240     if c.lower() == t:
    241       mode |= flag
    242   return mode
    243 
    244 
    245 def _GetTimeStamp():
    246   """Return a basic ISO 8601 time stamp with the current local time."""
    247   return time.strftime('%Y%m%dT%H%M%S', time.localtime())
    248 
    249 
    250 def _JoinLines(lines):
    251   # makes sure that the last line is also terminated, and is more memory
    252   # efficient than first appending an end-line to each line and then joining
    253   # all of them together.
    254   return ''.join(s for line in lines for s in (line, '\n'))
    255 
    256 
    257 def _IsGceInstance(serial):
    258   return _IPV4_ADDRESS_RE.match(serial)
    259 
    260 
    261 def _CreateAdbWrapper(device):
    262   if _IsGceInstance(str(device)):
    263     return gce_adb_wrapper.GceAdbWrapper(str(device))
    264   else:
    265     if isinstance(device, adb_wrapper.AdbWrapper):
    266       return device
    267     else:
    268       return adb_wrapper.AdbWrapper(device)
    269 
    270 
    271 def _FormatPartialOutputError(output):
    272   lines = output.splitlines() if isinstance(output, basestring) else output
    273   message = ['Partial output found:']
    274   if len(lines) > 11:
    275     message.extend('- %s' % line for line in lines[:5])
    276     message.extend('<snip>')
    277     message.extend('- %s' % line for line in lines[-5:])
    278   else:
    279     message.extend('- %s' % line for line in lines)
    280   return '\n'.join(message)
    281 
    282 
    283 class DeviceUtils(object):
    284 
    285   _MAX_ADB_COMMAND_LENGTH = 512
    286   _MAX_ADB_OUTPUT_LENGTH = 32768
    287   _LAUNCHER_FOCUSED_RE = re.compile(
    288       r'\s*mCurrentFocus.*(Launcher|launcher).*')
    289   _VALID_SHELL_VARIABLE = re.compile('^[a-zA-Z_][a-zA-Z0-9_]*$')
    290 
    291   LOCAL_PROPERTIES_PATH = posixpath.join('/', 'data', 'local.prop')
    292 
    293   # Property in /data/local.prop that controls Java assertions.
    294   JAVA_ASSERT_PROPERTY = 'dalvik.vm.enableassertions'
    295 
    296   def __init__(self, device, enable_device_files_cache=False,
    297                default_timeout=_DEFAULT_TIMEOUT,
    298                default_retries=_DEFAULT_RETRIES):
    299     """DeviceUtils constructor.
    300 
    301     Args:
    302       device: Either a device serial, an existing AdbWrapper instance, or an
    303         an existing AndroidCommands instance.
    304       enable_device_files_cache: For PushChangedFiles(), cache checksums of
    305         pushed files rather than recomputing them on a subsequent call.
    306       default_timeout: An integer containing the default number of seconds to
    307         wait for an operation to complete if no explicit value is provided.
    308       default_retries: An integer containing the default number or times an
    309         operation should be retried on failure if no explicit value is provided.
    310     """
    311     self.adb = None
    312     if isinstance(device, basestring):
    313       self.adb = _CreateAdbWrapper(device)
    314     elif isinstance(device, adb_wrapper.AdbWrapper):
    315       self.adb = device
    316     else:
    317       raise ValueError('Unsupported device value: %r' % device)
    318     self._commands_installed = None
    319     self._default_timeout = default_timeout
    320     self._default_retries = default_retries
    321     self._enable_device_files_cache = enable_device_files_cache
    322     self._cache = {}
    323     self._client_caches = {}
    324     self._cache_lock = threading.RLock()
    325     assert hasattr(self, decorators.DEFAULT_TIMEOUT_ATTR)
    326     assert hasattr(self, decorators.DEFAULT_RETRIES_ATTR)
    327 
    328     self._ClearCache()
    329 
    330   @property
    331   def serial(self):
    332     """Returns the device serial."""
    333     return self.adb.GetDeviceSerial()
    334 
    335   def __eq__(self, other):
    336     """Checks whether |other| refers to the same device as |self|.
    337 
    338     Args:
    339       other: The object to compare to. This can be a basestring, an instance
    340         of adb_wrapper.AdbWrapper, or an instance of DeviceUtils.
    341     Returns:
    342       Whether |other| refers to the same device as |self|.
    343     """
    344     return self.serial == str(other)
    345 
    346   def __lt__(self, other):
    347     """Compares two instances of DeviceUtils.
    348 
    349     This merely compares their serial numbers.
    350 
    351     Args:
    352       other: The instance of DeviceUtils to compare to.
    353     Returns:
    354       Whether |self| is less than |other|.
    355     """
    356     return self.serial < other.serial
    357 
    358   def __str__(self):
    359     """Returns the device serial."""
    360     return self.serial
    361 
    362   @decorators.WithTimeoutAndRetriesFromInstance()
    363   def IsOnline(self, timeout=None, retries=None):
    364     """Checks whether the device is online.
    365 
    366     Args:
    367       timeout: timeout in seconds
    368       retries: number of retries
    369 
    370     Returns:
    371       True if the device is online, False otherwise.
    372 
    373     Raises:
    374       CommandTimeoutError on timeout.
    375     """
    376     try:
    377       return self.adb.GetState() == 'device'
    378     except base_error.BaseError as exc:
    379       logger.info('Failed to get state: %s', exc)
    380       return False
    381 
    382   @decorators.WithTimeoutAndRetriesFromInstance()
    383   def HasRoot(self, timeout=None, retries=None):
    384     """Checks whether or not adbd has root privileges.
    385 
    386     Args:
    387       timeout: timeout in seconds
    388       retries: number of retries
    389 
    390     Returns:
    391       True if adbd has root privileges, False otherwise.
    392 
    393     Raises:
    394       CommandTimeoutError on timeout.
    395       DeviceUnreachableError on missing device.
    396     """
    397     try:
    398       if self.product_name in _SPECIAL_ROOT_DEVICE_LIST:
    399         return self.GetProp('service.adb.root') == '1'
    400       self.RunShellCommand(['ls', '/root'], check_return=True)
    401       return True
    402     except device_errors.AdbCommandFailedError:
    403       return False
    404 
    405   def NeedsSU(self, timeout=DEFAULT, retries=DEFAULT):
    406     """Checks whether 'su' is needed to access protected resources.
    407 
    408     Args:
    409       timeout: timeout in seconds
    410       retries: number of retries
    411 
    412     Returns:
    413       True if 'su' is available on the device and is needed to to access
    414         protected resources; False otherwise if either 'su' is not available
    415         (e.g. because the device has a user build), or not needed (because adbd
    416         already has root privileges).
    417 
    418     Raises:
    419       CommandTimeoutError on timeout.
    420       DeviceUnreachableError on missing device.
    421     """
    422     if 'needs_su' not in self._cache:
    423       cmd = '%s && ! ls /root' % self._Su('ls /root')
    424       if self.product_name in _SPECIAL_ROOT_DEVICE_LIST:
    425         if self.HasRoot():
    426           self._cache['needs_su'] = False
    427           return False
    428         cmd = 'which which && which su'
    429       try:
    430         self.RunShellCommand(cmd, shell=True, check_return=True,
    431             timeout=self._default_timeout if timeout is DEFAULT else timeout,
    432             retries=self._default_retries if retries is DEFAULT else retries)
    433         self._cache['needs_su'] = True
    434       except device_errors.AdbCommandFailedError:
    435         self._cache['needs_su'] = False
    436     return self._cache['needs_su']
    437 
    438 
    439   def _Su(self, command):
    440     if self.build_version_sdk >= version_codes.MARSHMALLOW:
    441       return 'su 0 %s' % command
    442     return 'su -c %s' % command
    443 
    444   @decorators.WithTimeoutAndRetriesFromInstance()
    445   def EnableRoot(self, timeout=None, retries=None):
    446     """Restarts adbd with root privileges.
    447 
    448     Args:
    449       timeout: timeout in seconds
    450       retries: number of retries
    451 
    452     Raises:
    453       CommandFailedError if root could not be enabled.
    454       CommandTimeoutError on timeout.
    455     """
    456     if self.IsUserBuild():
    457       raise device_errors.CommandFailedError(
    458           'Cannot enable root in user builds.', str(self))
    459     if 'needs_su' in self._cache:
    460       del self._cache['needs_su']
    461     self.adb.Root()
    462     self.WaitUntilFullyBooted()
    463 
    464   @decorators.WithTimeoutAndRetriesFromInstance()
    465   def IsUserBuild(self, timeout=None, retries=None):
    466     """Checks whether or not the device is running a user build.
    467 
    468     Args:
    469       timeout: timeout in seconds
    470       retries: number of retries
    471 
    472     Returns:
    473       True if the device is running a user build, False otherwise (i.e. if
    474         it's running a userdebug build).
    475 
    476     Raises:
    477       CommandTimeoutError on timeout.
    478       DeviceUnreachableError on missing device.
    479     """
    480     return self.build_type == 'user'
    481 
    482   @decorators.WithTimeoutAndRetriesFromInstance()
    483   def GetExternalStoragePath(self, timeout=None, retries=None):
    484     """Get the device's path to its SD card.
    485 
    486     Args:
    487       timeout: timeout in seconds
    488       retries: number of retries
    489 
    490     Returns:
    491       The device's path to its SD card.
    492 
    493     Raises:
    494       CommandFailedError if the external storage path could not be determined.
    495       CommandTimeoutError on timeout.
    496       DeviceUnreachableError on missing device.
    497     """
    498     self._EnsureCacheInitialized()
    499     if not self._cache['external_storage']:
    500       raise device_errors.CommandFailedError('$EXTERNAL_STORAGE is not set',
    501                                              str(self))
    502     return self._cache['external_storage']
    503 
    504   @decorators.WithTimeoutAndRetriesFromInstance()
    505   def GetApplicationPaths(self, package, timeout=None, retries=None):
    506     """Get the paths of the installed apks on the device for the given package.
    507 
    508     Args:
    509       package: Name of the package.
    510 
    511     Returns:
    512       List of paths to the apks on the device for the given package.
    513     """
    514     return self._GetApplicationPathsInternal(package)
    515 
    516   def _GetApplicationPathsInternal(self, package, skip_cache=False):
    517     cached_result = self._cache['package_apk_paths'].get(package)
    518     if cached_result is not None and not skip_cache:
    519       if package in self._cache['package_apk_paths_to_verify']:
    520         self._cache['package_apk_paths_to_verify'].remove(package)
    521         # Don't verify an app that is not thought to be installed. We are
    522         # concerned only with apps we think are installed having been
    523         # uninstalled manually.
    524         if cached_result and not self.PathExists(cached_result):
    525           cached_result = None
    526           self._cache['package_apk_checksums'].pop(package, 0)
    527       if cached_result is not None:
    528         return list(cached_result)
    529     # 'pm path' is liable to incorrectly exit with a nonzero number starting
    530     # in Lollipop.
    531     # TODO(jbudorick): Check if this is fixed as new Android versions are
    532     # released to put an upper bound on this.
    533     should_check_return = (self.build_version_sdk < version_codes.LOLLIPOP)
    534     output = self.RunShellCommand(
    535         ['pm', 'path', package], check_return=should_check_return)
    536     apks = []
    537     for line in output:
    538       if not line.startswith('package:'):
    539         continue
    540       apks.append(line[len('package:'):])
    541     if not apks and output:
    542       raise device_errors.CommandFailedError(
    543           'pm path returned: %r' % '\n'.join(output), str(self))
    544     self._cache['package_apk_paths'][package] = list(apks)
    545     return apks
    546 
    547   @decorators.WithTimeoutAndRetriesFromInstance()
    548   def GetApplicationVersion(self, package, timeout=None, retries=None):
    549     """Get the version name of a package installed on the device.
    550 
    551     Args:
    552       package: Name of the package.
    553 
    554     Returns:
    555       A string with the version name or None if the package is not found
    556       on the device.
    557     """
    558     output = self.RunShellCommand(
    559         ['dumpsys', 'package', package], check_return=True)
    560     if not output:
    561       return None
    562     for line in output:
    563       line = line.strip()
    564       if line.startswith('versionName='):
    565         return line[len('versionName='):]
    566     raise device_errors.CommandFailedError(
    567         'Version name for %s not found on dumpsys output' % package, str(self))
    568 
    569   @decorators.WithTimeoutAndRetriesFromInstance()
    570   def GetApplicationDataDirectory(self, package, timeout=None, retries=None):
    571     """Get the data directory on the device for the given package.
    572 
    573     Args:
    574       package: Name of the package.
    575 
    576     Returns:
    577       The package's data directory.
    578     Raises:
    579       CommandFailedError if the package's data directory can't be found,
    580         whether because it's not installed or otherwise.
    581     """
    582     output = self._RunPipedShellCommand(
    583         'pm dump %s | grep dataDir=' % cmd_helper.SingleQuote(package))
    584     for line in output:
    585       _, _, dataDir = line.partition('dataDir=')
    586       if dataDir:
    587         return dataDir
    588     raise device_errors.CommandFailedError(
    589         'Could not find data directory for %s', package)
    590 
    591   @decorators.WithTimeoutAndRetriesFromInstance()
    592   def WaitUntilFullyBooted(self, wifi=False, timeout=None, retries=None):
    593     """Wait for the device to fully boot.
    594 
    595     This means waiting for the device to boot, the package manager to be
    596     available, and the SD card to be ready. It can optionally mean waiting
    597     for wifi to come up, too.
    598 
    599     Args:
    600       wifi: A boolean indicating if we should wait for wifi to come up or not.
    601       timeout: timeout in seconds
    602       retries: number of retries
    603 
    604     Raises:
    605       CommandFailedError on failure.
    606       CommandTimeoutError if one of the component waits times out.
    607       DeviceUnreachableError if the device becomes unresponsive.
    608     """
    609     def sd_card_ready():
    610       try:
    611         self.RunShellCommand(['test', '-d', self.GetExternalStoragePath()],
    612                              check_return=True)
    613         return True
    614       except device_errors.AdbCommandFailedError:
    615         return False
    616 
    617     def pm_ready():
    618       try:
    619         return self._GetApplicationPathsInternal('android', skip_cache=True)
    620       except device_errors.CommandFailedError:
    621         return False
    622 
    623     def boot_completed():
    624       try:
    625         return self.GetProp('sys.boot_completed', cache=False) == '1'
    626       except device_errors.CommandFailedError:
    627         return False
    628 
    629     def wifi_enabled():
    630       return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'],
    631                                                         check_return=False)
    632 
    633     self.adb.WaitForDevice()
    634     timeout_retry.WaitFor(sd_card_ready)
    635     timeout_retry.WaitFor(pm_ready)
    636     timeout_retry.WaitFor(boot_completed)
    637     if wifi:
    638       timeout_retry.WaitFor(wifi_enabled)
    639 
    640   REBOOT_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
    641 
    642   @decorators.WithTimeoutAndRetriesFromInstance(
    643       min_default_timeout=REBOOT_DEFAULT_TIMEOUT)
    644   def Reboot(self, block=True, wifi=False, timeout=None, retries=None):
    645     """Reboot the device.
    646 
    647     Args:
    648       block: A boolean indicating if we should wait for the reboot to complete.
    649       wifi: A boolean indicating if we should wait for wifi to be enabled after
    650         the reboot. The option has no effect unless |block| is also True.
    651       timeout: timeout in seconds
    652       retries: number of retries
    653 
    654     Raises:
    655       CommandTimeoutError on timeout.
    656       DeviceUnreachableError on missing device.
    657     """
    658     def device_offline():
    659       return not self.IsOnline()
    660 
    661     self.adb.Reboot()
    662     self._ClearCache()
    663     timeout_retry.WaitFor(device_offline, wait_period=1)
    664     if block:
    665       self.WaitUntilFullyBooted(wifi=wifi)
    666 
    667   INSTALL_DEFAULT_TIMEOUT = 4 * _DEFAULT_TIMEOUT
    668 
    669   @decorators.WithTimeoutAndRetriesFromInstance(
    670       min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
    671   def Install(self, apk, allow_downgrade=False, reinstall=False,
    672               permissions=None, timeout=None, retries=None):
    673     """Install an APK.
    674 
    675     Noop if an identical APK is already installed.
    676 
    677     Args:
    678       apk: An ApkHelper instance or string containing the path to the APK.
    679       allow_downgrade: A boolean indicating if we should allow downgrades.
    680       reinstall: A boolean indicating if we should keep any existing app data.
    681       permissions: Set of permissions to set. If not set, finds permissions with
    682           apk helper. To set no permissions, pass [].
    683       timeout: timeout in seconds
    684       retries: number of retries
    685 
    686     Raises:
    687       CommandFailedError if the installation fails.
    688       CommandTimeoutError if the installation times out.
    689       DeviceUnreachableError on missing device.
    690     """
    691     self._InstallInternal(apk, None, allow_downgrade=allow_downgrade,
    692                           reinstall=reinstall, permissions=permissions)
    693 
    694   @decorators.WithTimeoutAndRetriesFromInstance(
    695       min_default_timeout=INSTALL_DEFAULT_TIMEOUT)
    696   def InstallSplitApk(self, base_apk, split_apks, allow_downgrade=False,
    697                       reinstall=False, allow_cached_props=False,
    698                       permissions=None, timeout=None, retries=None):
    699     """Install a split APK.
    700 
    701     Noop if all of the APK splits are already installed.
    702 
    703     Args:
    704       base_apk: An ApkHelper instance or string containing the path to the base
    705           APK.
    706       split_apks: A list of strings of paths of all of the APK splits.
    707       allow_downgrade: A boolean indicating if we should allow downgrades.
    708       reinstall: A boolean indicating if we should keep any existing app data.
    709       allow_cached_props: Whether to use cached values for device properties.
    710       permissions: Set of permissions to set. If not set, finds permissions with
    711           apk helper. To set no permissions, pass [].
    712       timeout: timeout in seconds
    713       retries: number of retries
    714 
    715     Raises:
    716       CommandFailedError if the installation fails.
    717       CommandTimeoutError if the installation times out.
    718       DeviceUnreachableError on missing device.
    719       DeviceVersionError if device SDK is less than Android L.
    720     """
    721     self._InstallInternal(base_apk, split_apks, reinstall=reinstall,
    722                           allow_cached_props=allow_cached_props,
    723                           permissions=permissions,
    724                           allow_downgrade=allow_downgrade)
    725 
    726   def _InstallInternal(self, base_apk, split_apks, allow_downgrade=False,
    727                        reinstall=False, allow_cached_props=False,
    728                        permissions=None):
    729     if split_apks:
    730       self._CheckSdkLevel(version_codes.LOLLIPOP)
    731 
    732     base_apk = apk_helper.ToHelper(base_apk)
    733 
    734     all_apks = [base_apk.path]
    735     if split_apks:
    736       all_apks += split_select.SelectSplits(
    737         self, base_apk.path, split_apks, allow_cached_props=allow_cached_props)
    738       if len(all_apks) == 1:
    739         logger.warning('split-select did not select any from %s', split_apks)
    740 
    741     missing_apks = [apk for apk in all_apks if not os.path.exists(apk)]
    742     if missing_apks:
    743       raise device_errors.CommandFailedError(
    744           'Attempted to install non-existent apks: %s'
    745               % pprint.pformat(missing_apks))
    746 
    747     package_name = base_apk.GetPackageName()
    748     device_apk_paths = self._GetApplicationPathsInternal(package_name)
    749 
    750     apks_to_install = None
    751     host_checksums = None
    752     if not device_apk_paths:
    753       apks_to_install = all_apks
    754     elif len(device_apk_paths) > 1 and not split_apks:
    755       logger.warning(
    756           'Installing non-split APK when split APK was previously installed')
    757       apks_to_install = all_apks
    758     elif len(device_apk_paths) == 1 and split_apks:
    759       logger.warning(
    760           'Installing split APK when non-split APK was previously installed')
    761       apks_to_install = all_apks
    762     else:
    763       try:
    764         apks_to_install, host_checksums = (
    765             self._ComputeStaleApks(package_name, all_apks))
    766       except EnvironmentError as e:
    767         logger.warning('Error calculating md5: %s', e)
    768         apks_to_install, host_checksums = all_apks, None
    769       if apks_to_install and not reinstall:
    770         self.Uninstall(package_name)
    771         apks_to_install = all_apks
    772 
    773     if apks_to_install:
    774       # Assume that we won't know the resulting device state.
    775       self._cache['package_apk_paths'].pop(package_name, 0)
    776       self._cache['package_apk_checksums'].pop(package_name, 0)
    777       if split_apks:
    778         partial = package_name if len(apks_to_install) < len(all_apks) else None
    779         self.adb.InstallMultiple(
    780             apks_to_install, partial=partial, reinstall=reinstall,
    781             allow_downgrade=allow_downgrade)
    782       else:
    783         self.adb.Install(
    784             base_apk.path, reinstall=reinstall, allow_downgrade=allow_downgrade)
    785       if (permissions is None
    786           and self.build_version_sdk >= version_codes.MARSHMALLOW):
    787         permissions = base_apk.GetPermissions()
    788       self.GrantPermissions(package_name, permissions)
    789       # Upon success, we know the device checksums, but not their paths.
    790       if host_checksums is not None:
    791         self._cache['package_apk_checksums'][package_name] = host_checksums
    792     else:
    793       # Running adb install terminates running instances of the app, so to be
    794       # consistent, we explicitly terminate it when skipping the install.
    795       self.ForceStop(package_name)
    796 
    797   @decorators.WithTimeoutAndRetriesFromInstance()
    798   def Uninstall(self, package_name, keep_data=False, timeout=None,
    799                 retries=None):
    800     """Remove the app |package_name| from the device.
    801 
    802     This is a no-op if the app is not already installed.
    803 
    804     Args:
    805       package_name: The package to uninstall.
    806       keep_data: (optional) Whether to keep the data and cache directories.
    807       timeout: Timeout in seconds.
    808       retries: Number of retries.
    809 
    810     Raises:
    811       CommandFailedError if the uninstallation fails.
    812       CommandTimeoutError if the uninstallation times out.
    813       DeviceUnreachableError on missing device.
    814     """
    815     installed = self._GetApplicationPathsInternal(package_name)
    816     if not installed:
    817       return
    818     try:
    819       self.adb.Uninstall(package_name, keep_data)
    820       self._cache['package_apk_paths'][package_name] = []
    821       self._cache['package_apk_checksums'][package_name] = set()
    822     except:
    823       # Clear cache since we can't be sure of the state.
    824       self._cache['package_apk_paths'].pop(package_name, 0)
    825       self._cache['package_apk_checksums'].pop(package_name, 0)
    826       raise
    827 
    828   def _CheckSdkLevel(self, required_sdk_level):
    829     """Raises an exception if the device does not have the required SDK level.
    830     """
    831     if self.build_version_sdk < required_sdk_level:
    832       raise device_errors.DeviceVersionError(
    833           ('Requires SDK level %s, device is SDK level %s' %
    834            (required_sdk_level, self.build_version_sdk)),
    835            device_serial=self.serial)
    836 
    837   @decorators.WithTimeoutAndRetriesFromInstance()
    838   def RunShellCommand(self, cmd, shell=False, check_return=False, cwd=None,
    839                       env=None, run_as=None, as_root=False, single_line=False,
    840                       large_output=False, raw_output=False, timeout=None,
    841                       retries=None):
    842     """Run an ADB shell command.
    843 
    844     The command to run |cmd| should be a sequence of program arguments
    845     (preferred) or a single string with a shell script to run.
    846 
    847     When |cmd| is a sequence, it is assumed to contain the name of the command
    848     to run followed by its arguments. In this case, arguments are passed to the
    849     command exactly as given, preventing any further processing by the shell.
    850     This allows callers to easily pass arguments with spaces or special
    851     characters without having to worry about quoting rules. Whenever possible,
    852     it is recomended to pass |cmd| as a sequence.
    853 
    854     When |cmd| is passed as a single string, |shell| should be set to True.
    855     The command will be interpreted and run by the shell on the device,
    856     allowing the use of shell features such as pipes, wildcards, or variables.
    857     Failing to set shell=True will issue a warning, but this will be changed
    858     to a hard failure in the future (see: catapult:#3242).
    859 
    860     This behaviour is consistent with that of command runners in cmd_helper as
    861     well as Python's own subprocess.Popen.
    862 
    863     TODO(perezju) Change the default of |check_return| to True when callers
    864       have switched to the new behaviour.
    865 
    866     Args:
    867       cmd: A sequence containing the command to run and its arguments, or a
    868         string with a shell script to run (should also set shell=True).
    869       shell: A boolean indicating whether shell features may be used in |cmd|.
    870       check_return: A boolean indicating whether or not the return code should
    871         be checked.
    872       cwd: The device directory in which the command should be run.
    873       env: The environment variables with which the command should be run.
    874       run_as: A string containing the package as which the command should be
    875         run.
    876       as_root: A boolean indicating whether the shell command should be run
    877         with root privileges.
    878       single_line: A boolean indicating if only a single line of output is
    879         expected.
    880       large_output: Uses a work-around for large shell command output. Without
    881         this large output will be truncated.
    882       raw_output: Whether to only return the raw output
    883           (no splitting into lines).
    884       timeout: timeout in seconds
    885       retries: number of retries
    886 
    887     Returns:
    888       If single_line is False, the output of the command as a list of lines,
    889       otherwise, a string with the unique line of output emmited by the command
    890       (with the optional newline at the end stripped).
    891 
    892     Raises:
    893       AdbCommandFailedError if check_return is True and the exit code of
    894         the command run on the device is non-zero.
    895       CommandFailedError if single_line is True but the output contains two or
    896         more lines.
    897       CommandTimeoutError on timeout.
    898       DeviceUnreachableError on missing device.
    899     """
    900     def env_quote(key, value):
    901       if not DeviceUtils._VALID_SHELL_VARIABLE.match(key):
    902         raise KeyError('Invalid shell variable name %r' % key)
    903       # using double quotes here to allow interpolation of shell variables
    904       return '%s=%s' % (key, cmd_helper.DoubleQuote(value))
    905 
    906     def run(cmd):
    907       return self.adb.Shell(cmd)
    908 
    909     def handle_check_return(cmd):
    910       try:
    911         return run(cmd)
    912       except device_errors.AdbCommandFailedError as exc:
    913         if check_return:
    914           raise
    915         else:
    916           return exc.output
    917 
    918     def handle_large_command(cmd):
    919       if len(cmd) < self._MAX_ADB_COMMAND_LENGTH:
    920         return handle_check_return(cmd)
    921       else:
    922         with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
    923           self._WriteFileWithPush(script.name, cmd)
    924           logger.info('Large shell command will be run from file: %s ...',
    925                       cmd[:self._MAX_ADB_COMMAND_LENGTH])
    926           return handle_check_return('sh %s' % script.name_quoted)
    927 
    928     def handle_large_output(cmd, large_output_mode):
    929       if large_output_mode:
    930         with device_temp_file.DeviceTempFile(self.adb) as large_output_file:
    931           cmd = '( %s )>%s' % (cmd, large_output_file.name)
    932           logger.debug('Large output mode enabled. Will write output to '
    933                        'device and read results from file.')
    934           handle_large_command(cmd)
    935           return self.ReadFile(large_output_file.name, force_pull=True)
    936       else:
    937         try:
    938           return handle_large_command(cmd)
    939         except device_errors.AdbCommandFailedError as exc:
    940           if exc.status is None:
    941             logger.error(_FormatPartialOutputError(exc.output))
    942             logger.warning('Attempting to run in large_output mode.')
    943             logger.warning('Use RunShellCommand(..., large_output=True) for '
    944                            'shell commands that expect a lot of output.')
    945             return handle_large_output(cmd, True)
    946           else:
    947             raise
    948 
    949     if isinstance(cmd, basestring):
    950       if not shell:
    951         logging.warning(
    952             'The command to run should preferably be passed as a sequence of'
    953             ' args. If shell features are needed (pipes, wildcards, variables)'
    954             ' clients should explicitly set shell=True.')
    955     else:
    956       cmd = ' '.join(cmd_helper.SingleQuote(s) for s in cmd)
    957     if env:
    958       env = ' '.join(env_quote(k, v) for k, v in env.iteritems())
    959       cmd = '%s %s' % (env, cmd)
    960     if cwd:
    961       cmd = 'cd %s && %s' % (cmd_helper.SingleQuote(cwd), cmd)
    962     if run_as:
    963       cmd = 'run-as %s sh -c %s' % (cmd_helper.SingleQuote(run_as),
    964                                     cmd_helper.SingleQuote(cmd))
    965     if as_root and self.NeedsSU():
    966       # "su -c sh -c" allows using shell features in |cmd|
    967       cmd = self._Su('sh -c %s' % cmd_helper.SingleQuote(cmd))
    968 
    969     output = handle_large_output(cmd, large_output)
    970 
    971     if raw_output:
    972       return output
    973 
    974     output = output.splitlines()
    975     if single_line:
    976       if not output:
    977         return ''
    978       elif len(output) == 1:
    979         return output[0]
    980       else:
    981         msg = 'one line of output was expected, but got: %s'
    982         raise device_errors.CommandFailedError(msg % output, str(self))
    983     else:
    984       return output
    985 
    986   def _RunPipedShellCommand(self, script, **kwargs):
    987     PIPESTATUS_LEADER = 'PIPESTATUS: '
    988 
    989     script += '; echo "%s${PIPESTATUS[@]}"' % PIPESTATUS_LEADER
    990     kwargs.update(shell=True, check_return=True)
    991     output = self.RunShellCommand(script, **kwargs)
    992     pipestatus_line = output[-1]
    993 
    994     if not pipestatus_line.startswith(PIPESTATUS_LEADER):
    995       logger.error('Pipe exit statuses of shell script missing.')
    996       raise device_errors.AdbShellCommandFailedError(
    997           script, output, status=None,
    998           device_serial=self.serial)
    999 
   1000     output = output[:-1]
   1001     statuses = [
   1002         int(s) for s in pipestatus_line[len(PIPESTATUS_LEADER):].split()]
   1003     if any(statuses):
   1004       raise device_errors.AdbShellCommandFailedError(
   1005           script, output, status=statuses,
   1006           device_serial=self.serial)
   1007     return output
   1008 
   1009   @decorators.WithTimeoutAndRetriesFromInstance()
   1010   def KillAll(self, process_name, exact=False, signum=device_signal.SIGKILL,
   1011               as_root=False, blocking=False, quiet=False,
   1012               timeout=None, retries=None):
   1013     """Kill all processes with the given name on the device.
   1014 
   1015     Args:
   1016       process_name: A string containing the name of the process to kill.
   1017       exact: A boolean indicating whether to kill all processes matching
   1018              the string |process_name| exactly, or all of those which contain
   1019              |process_name| as a substring. Defaults to False.
   1020       signum: An integer containing the signal number to send to kill. Defaults
   1021               to SIGKILL (9).
   1022       as_root: A boolean indicating whether the kill should be executed with
   1023                root privileges.
   1024       blocking: A boolean indicating whether we should wait until all processes
   1025                 with the given |process_name| are dead.
   1026       quiet: A boolean indicating whether to ignore the fact that no processes
   1027              to kill were found.
   1028       timeout: timeout in seconds
   1029       retries: number of retries
   1030 
   1031     Returns:
   1032       The number of processes attempted to kill.
   1033 
   1034     Raises:
   1035       CommandFailedError if no process was killed and |quiet| is False.
   1036       CommandTimeoutError on timeout.
   1037       DeviceUnreachableError on missing device.
   1038     """
   1039     procs_pids = self.GetPids(process_name)
   1040     if exact:
   1041       procs_pids = {process_name: procs_pids.get(process_name, [])}
   1042     pids = set(itertools.chain(*procs_pids.values()))
   1043     if not pids:
   1044       if quiet:
   1045         return 0
   1046       else:
   1047         raise device_errors.CommandFailedError(
   1048             'No process "%s"' % process_name, str(self))
   1049 
   1050     logger.info(
   1051         'KillAll(%r, ...) attempting to kill the following:', process_name)
   1052     for name, ids in procs_pids.iteritems():
   1053       for i in ids:
   1054         logger.info('  %05s %s', str(i), name)
   1055 
   1056     cmd = ['kill', '-%d' % signum] + sorted(pids)
   1057     self.RunShellCommand(cmd, as_root=as_root, check_return=True)
   1058 
   1059     def all_pids_killed():
   1060       procs_pids_remain = self.GetPids(process_name)
   1061       return not pids.intersection(itertools.chain(*procs_pids_remain.values()))
   1062 
   1063     if blocking:
   1064       timeout_retry.WaitFor(all_pids_killed, wait_period=0.1)
   1065 
   1066     return len(pids)
   1067 
   1068   @decorators.WithTimeoutAndRetriesFromInstance()
   1069   def StartActivity(self, intent_obj, blocking=False, trace_file_name=None,
   1070                     force_stop=False, timeout=None, retries=None):
   1071     """Start package's activity on the device.
   1072 
   1073     Args:
   1074       intent_obj: An Intent object to send.
   1075       blocking: A boolean indicating whether we should wait for the activity to
   1076                 finish launching.
   1077       trace_file_name: If present, a string that both indicates that we want to
   1078                        profile the activity and contains the path to which the
   1079                        trace should be saved.
   1080       force_stop: A boolean indicating whether we should stop the activity
   1081                   before starting it.
   1082       timeout: timeout in seconds
   1083       retries: number of retries
   1084 
   1085     Raises:
   1086       CommandFailedError if the activity could not be started.
   1087       CommandTimeoutError on timeout.
   1088       DeviceUnreachableError on missing device.
   1089     """
   1090     cmd = ['am', 'start']
   1091     if blocking:
   1092       cmd.append('-W')
   1093     if trace_file_name:
   1094       cmd.extend(['--start-profiler', trace_file_name])
   1095     if force_stop:
   1096       cmd.append('-S')
   1097     cmd.extend(intent_obj.am_args)
   1098     for line in self.RunShellCommand(cmd, check_return=True):
   1099       if line.startswith('Error:'):
   1100         raise device_errors.CommandFailedError(line, str(self))
   1101 
   1102   @decorators.WithTimeoutAndRetriesFromInstance()
   1103   def StartInstrumentation(self, component, finish=True, raw=False,
   1104                            extras=None, timeout=None, retries=None):
   1105     if extras is None:
   1106       extras = {}
   1107 
   1108     cmd = ['am', 'instrument']
   1109     if finish:
   1110       cmd.append('-w')
   1111     if raw:
   1112       cmd.append('-r')
   1113     for k, v in extras.iteritems():
   1114       cmd.extend(['-e', str(k), str(v)])
   1115     cmd.append(component)
   1116 
   1117     # Store the package name in a shell variable to help the command stay under
   1118     # the _MAX_ADB_COMMAND_LENGTH limit.
   1119     package = component.split('/')[0]
   1120     shell_snippet = 'p=%s;%s' % (package,
   1121                                  cmd_helper.ShrinkToSnippet(cmd, 'p', package))
   1122     return self.RunShellCommand(shell_snippet, shell=True, check_return=True,
   1123                                 large_output=True)
   1124 
   1125   @decorators.WithTimeoutAndRetriesFromInstance()
   1126   def BroadcastIntent(self, intent_obj, timeout=None, retries=None):
   1127     """Send a broadcast intent.
   1128 
   1129     Args:
   1130       intent: An Intent to broadcast.
   1131       timeout: timeout in seconds
   1132       retries: number of retries
   1133 
   1134     Raises:
   1135       CommandTimeoutError on timeout.
   1136       DeviceUnreachableError on missing device.
   1137     """
   1138     cmd = ['am', 'broadcast'] + intent_obj.am_args
   1139     self.RunShellCommand(cmd, check_return=True)
   1140 
   1141   @decorators.WithTimeoutAndRetriesFromInstance()
   1142   def GoHome(self, timeout=None, retries=None):
   1143     """Return to the home screen and obtain launcher focus.
   1144 
   1145     This command launches the home screen and attempts to obtain
   1146     launcher focus until the timeout is reached.
   1147 
   1148     Args:
   1149       timeout: timeout in seconds
   1150       retries: number of retries
   1151 
   1152     Raises:
   1153       CommandTimeoutError on timeout.
   1154       DeviceUnreachableError on missing device.
   1155     """
   1156     def is_launcher_focused():
   1157       output = self.RunShellCommand(['dumpsys', 'window', 'windows'],
   1158                                     check_return=True, large_output=True)
   1159       return any(self._LAUNCHER_FOCUSED_RE.match(l) for l in output)
   1160 
   1161     def dismiss_popups():
   1162       # There is a dialog present; attempt to get rid of it.
   1163       # Not all dialogs can be dismissed with back.
   1164       self.SendKeyEvent(keyevent.KEYCODE_ENTER)
   1165       self.SendKeyEvent(keyevent.KEYCODE_BACK)
   1166       return is_launcher_focused()
   1167 
   1168     # If Home is already focused, return early to avoid unnecessary work.
   1169     if is_launcher_focused():
   1170       return
   1171 
   1172     self.StartActivity(
   1173         intent.Intent(action='android.intent.action.MAIN',
   1174                       category='android.intent.category.HOME'),
   1175         blocking=True)
   1176 
   1177     if not is_launcher_focused():
   1178       timeout_retry.WaitFor(dismiss_popups, wait_period=1)
   1179 
   1180   @decorators.WithTimeoutAndRetriesFromInstance()
   1181   def ForceStop(self, package, timeout=None, retries=None):
   1182     """Close the application.
   1183 
   1184     Args:
   1185       package: A string containing the name of the package to stop.
   1186       timeout: timeout in seconds
   1187       retries: number of retries
   1188 
   1189     Raises:
   1190       CommandTimeoutError on timeout.
   1191       DeviceUnreachableError on missing device.
   1192     """
   1193     cmd = 'p=%s;if [[ "$(ps)" = *$p* ]]; then am force-stop $p; fi'
   1194     self.RunShellCommand(cmd % package, shell=True, check_return=True)
   1195 
   1196   @decorators.WithTimeoutAndRetriesFromInstance()
   1197   def ClearApplicationState(
   1198       self, package, permissions=None, timeout=None, retries=None):
   1199     """Clear all state for the given package.
   1200 
   1201     Args:
   1202       package: A string containing the name of the package to stop.
   1203       permissions: List of permissions to set after clearing data.
   1204       timeout: timeout in seconds
   1205       retries: number of retries
   1206 
   1207     Raises:
   1208       CommandTimeoutError on timeout.
   1209       DeviceUnreachableError on missing device.
   1210     """
   1211     # Check that the package exists before clearing it for android builds below
   1212     # JB MR2. Necessary because calling pm clear on a package that doesn't exist
   1213     # may never return.
   1214     if ((self.build_version_sdk >= version_codes.JELLY_BEAN_MR2)
   1215         or self._GetApplicationPathsInternal(package)):
   1216       self.RunShellCommand(['pm', 'clear', package], check_return=True)
   1217       self.GrantPermissions(package, permissions)
   1218 
   1219   @decorators.WithTimeoutAndRetriesFromInstance()
   1220   def SendKeyEvent(self, keycode, timeout=None, retries=None):
   1221     """Sends a keycode to the device.
   1222 
   1223     See the devil.android.sdk.keyevent module for suitable keycode values.
   1224 
   1225     Args:
   1226       keycode: A integer keycode to send to the device.
   1227       timeout: timeout in seconds
   1228       retries: number of retries
   1229 
   1230     Raises:
   1231       CommandTimeoutError on timeout.
   1232       DeviceUnreachableError on missing device.
   1233     """
   1234     self.RunShellCommand(['input', 'keyevent', format(keycode, 'd')],
   1235                          check_return=True)
   1236 
   1237   PUSH_CHANGED_FILES_DEFAULT_TIMEOUT = 10 * _DEFAULT_TIMEOUT
   1238 
   1239   @decorators.WithTimeoutAndRetriesFromInstance(
   1240       min_default_timeout=PUSH_CHANGED_FILES_DEFAULT_TIMEOUT)
   1241   def PushChangedFiles(self, host_device_tuples, timeout=None,
   1242                        retries=None, delete_device_stale=False):
   1243     """Push files to the device, skipping files that don't need updating.
   1244 
   1245     When a directory is pushed, it is traversed recursively on the host and
   1246     all files in it are pushed to the device as needed.
   1247     Additionally, if delete_device_stale option is True,
   1248     files that exist on the device but don't exist on the host are deleted.
   1249 
   1250     Args:
   1251       host_device_tuples: A list of (host_path, device_path) tuples, where
   1252         |host_path| is an absolute path of a file or directory on the host
   1253         that should be minimially pushed to the device, and |device_path| is
   1254         an absolute path of the destination on the device.
   1255       timeout: timeout in seconds
   1256       retries: number of retries
   1257       delete_device_stale: option to delete stale files on device
   1258 
   1259     Raises:
   1260       CommandFailedError on failure.
   1261       CommandTimeoutError on timeout.
   1262       DeviceUnreachableError on missing device.
   1263     """
   1264 
   1265     all_changed_files = []
   1266     all_stale_files = []
   1267     missing_dirs = []
   1268     cache_commit_funcs = []
   1269     for h, d in host_device_tuples:
   1270       assert os.path.isabs(h) and posixpath.isabs(d)
   1271       h = os.path.realpath(h)
   1272       changed_files, up_to_date_files, stale_files, cache_commit_func = (
   1273           self._GetChangedAndStaleFiles(h, d, delete_device_stale))
   1274       all_changed_files += changed_files
   1275       all_stale_files += stale_files
   1276       cache_commit_funcs.append(cache_commit_func)
   1277       if changed_files and not up_to_date_files and not stale_files:
   1278         if os.path.isdir(h):
   1279           missing_dirs.append(d)
   1280         else:
   1281           missing_dirs.append(posixpath.dirname(d))
   1282 
   1283     if delete_device_stale and all_stale_files:
   1284       self.RunShellCommand(['rm', '-f'] + all_stale_files, check_return=True)
   1285 
   1286     if all_changed_files:
   1287       if missing_dirs:
   1288         self.RunShellCommand(['mkdir', '-p'] + missing_dirs, check_return=True)
   1289       self._PushFilesImpl(host_device_tuples, all_changed_files)
   1290     for func in cache_commit_funcs:
   1291       func()
   1292 
   1293   def _GetChangedAndStaleFiles(self, host_path, device_path, track_stale=False):
   1294     """Get files to push and delete
   1295 
   1296     Args:
   1297       host_path: an absolute path of a file or directory on the host
   1298       device_path: an absolute path of a file or directory on the device
   1299       track_stale: whether to bother looking for stale files (slower)
   1300 
   1301     Returns:
   1302       a four-element tuple
   1303       1st element: a list of (host_files_path, device_files_path) tuples to push
   1304       2nd element: a list of host_files_path that are up-to-date
   1305       3rd element: a list of stale files under device_path, or [] when
   1306         track_stale == False
   1307       4th element: a cache commit function.
   1308     """
   1309     try:
   1310       # Length calculations below assume no trailing /.
   1311       host_path = host_path.rstrip('/')
   1312       device_path = device_path.rstrip('/')
   1313 
   1314       specific_device_paths = [device_path]
   1315       ignore_other_files = not track_stale and os.path.isdir(host_path)
   1316       if ignore_other_files:
   1317         specific_device_paths = []
   1318         for root, _, filenames in os.walk(host_path):
   1319           relative_dir = root[len(host_path) + 1:]
   1320           specific_device_paths.extend(
   1321               posixpath.join(device_path, relative_dir, f) for f in filenames)
   1322 
   1323       def calculate_host_checksums():
   1324         return md5sum.CalculateHostMd5Sums([host_path])
   1325 
   1326       def calculate_device_checksums():
   1327         if self._enable_device_files_cache:
   1328           cache_entry = self._cache['device_path_checksums'].get(device_path)
   1329           if cache_entry and cache_entry[0] == ignore_other_files:
   1330             return dict(cache_entry[1])
   1331 
   1332         sums = md5sum.CalculateDeviceMd5Sums(specific_device_paths, self)
   1333 
   1334         cache_entry = [ignore_other_files, sums]
   1335         self._cache['device_path_checksums'][device_path] = cache_entry
   1336         return dict(sums)
   1337 
   1338       host_checksums, device_checksums = reraiser_thread.RunAsync((
   1339           calculate_host_checksums,
   1340           calculate_device_checksums))
   1341     except EnvironmentError as e:
   1342       logger.warning('Error calculating md5: %s', e)
   1343       return ([(host_path, device_path)], [], [], lambda: 0)
   1344 
   1345     to_push = []
   1346     up_to_date = []
   1347     to_delete = []
   1348     if os.path.isfile(host_path):
   1349       host_checksum = host_checksums.get(host_path)
   1350       device_checksum = device_checksums.get(device_path)
   1351       if host_checksum == device_checksum:
   1352         up_to_date.append(host_path)
   1353       else:
   1354         to_push.append((host_path, device_path))
   1355     else:
   1356       for host_abs_path, host_checksum in host_checksums.iteritems():
   1357         device_abs_path = posixpath.join(
   1358             device_path, os.path.relpath(host_abs_path, host_path))
   1359         device_checksum = device_checksums.pop(device_abs_path, None)
   1360         if device_checksum == host_checksum:
   1361           up_to_date.append(host_abs_path)
   1362         else:
   1363           to_push.append((host_abs_path, device_abs_path))
   1364       to_delete = device_checksums.keys()
   1365 
   1366     def cache_commit_func():
   1367       new_sums = {posixpath.join(device_path, path[len(host_path) + 1:]): val
   1368                   for path, val in host_checksums.iteritems()}
   1369       cache_entry = [ignore_other_files, new_sums]
   1370       self._cache['device_path_checksums'][device_path] = cache_entry
   1371 
   1372     return (to_push, up_to_date, to_delete, cache_commit_func)
   1373 
   1374   def _ComputeDeviceChecksumsForApks(self, package_name):
   1375     ret = self._cache['package_apk_checksums'].get(package_name)
   1376     if ret is None:
   1377       device_paths = self._GetApplicationPathsInternal(package_name)
   1378       file_to_checksums = md5sum.CalculateDeviceMd5Sums(device_paths, self)
   1379       ret = set(file_to_checksums.values())
   1380       self._cache['package_apk_checksums'][package_name] = ret
   1381     return ret
   1382 
   1383   def _ComputeStaleApks(self, package_name, host_apk_paths):
   1384     def calculate_host_checksums():
   1385       return md5sum.CalculateHostMd5Sums(host_apk_paths)
   1386 
   1387     def calculate_device_checksums():
   1388       return self._ComputeDeviceChecksumsForApks(package_name)
   1389 
   1390     host_checksums, device_checksums = reraiser_thread.RunAsync((
   1391         calculate_host_checksums, calculate_device_checksums))
   1392     stale_apks = [k for (k, v) in host_checksums.iteritems()
   1393                   if v not in device_checksums]
   1394     return stale_apks, set(host_checksums.values())
   1395 
   1396   def _PushFilesImpl(self, host_device_tuples, files):
   1397     if not files:
   1398       return
   1399 
   1400     size = sum(host_utils.GetRecursiveDiskUsage(h) for h, _ in files)
   1401     file_count = len(files)
   1402     dir_size = sum(host_utils.GetRecursiveDiskUsage(h)
   1403                    for h, _ in host_device_tuples)
   1404     dir_file_count = 0
   1405     for h, _ in host_device_tuples:
   1406       if os.path.isdir(h):
   1407         dir_file_count += sum(len(f) for _r, _d, f in os.walk(h))
   1408       else:
   1409         dir_file_count += 1
   1410 
   1411     push_duration = self._ApproximateDuration(
   1412         file_count, file_count, size, False)
   1413     dir_push_duration = self._ApproximateDuration(
   1414         len(host_device_tuples), dir_file_count, dir_size, False)
   1415     zip_duration = self._ApproximateDuration(1, 1, size, True)
   1416 
   1417     if (dir_push_duration < push_duration and dir_push_duration < zip_duration
   1418         # TODO(jbudorick): Resume directory pushing once clients have switched
   1419         # to 1.0.36-compatible syntax.
   1420         and False):
   1421       self._PushChangedFilesIndividually(host_device_tuples)
   1422     elif push_duration < zip_duration:
   1423       self._PushChangedFilesIndividually(files)
   1424     elif self._commands_installed is False:
   1425       # Already tried and failed to install unzip command.
   1426       self._PushChangedFilesIndividually(files)
   1427     elif not self._PushChangedFilesZipped(
   1428         files, [d for _, d in host_device_tuples]):
   1429       self._PushChangedFilesIndividually(files)
   1430 
   1431   def _MaybeInstallCommands(self):
   1432     if self._commands_installed is None:
   1433       try:
   1434         if not install_commands.Installed(self):
   1435           install_commands.InstallCommands(self)
   1436         self._commands_installed = True
   1437       except device_errors.CommandFailedError as e:
   1438         logger.warning('unzip not available: %s', str(e))
   1439         self._commands_installed = False
   1440     return self._commands_installed
   1441 
   1442   @staticmethod
   1443   def _ApproximateDuration(adb_calls, file_count, byte_count, is_zipping):
   1444     # We approximate the time to push a set of files to a device as:
   1445     #   t = c1 * a + c2 * f + c3 + b / c4 + b / (c5 * c6), where
   1446     #     t: total time (sec)
   1447     #     c1: adb call time delay (sec)
   1448     #     a: number of times adb is called (unitless)
   1449     #     c2: push time delay (sec)
   1450     #     f: number of files pushed via adb (unitless)
   1451     #     c3: zip time delay (sec)
   1452     #     c4: zip rate (bytes/sec)
   1453     #     b: total number of bytes (bytes)
   1454     #     c5: transfer rate (bytes/sec)
   1455     #     c6: compression ratio (unitless)
   1456 
   1457     # All of these are approximations.
   1458     ADB_CALL_PENALTY = 0.1  # seconds
   1459     ADB_PUSH_PENALTY = 0.01  # seconds
   1460     ZIP_PENALTY = 2.0  # seconds
   1461     ZIP_RATE = 10000000.0  # bytes / second
   1462     TRANSFER_RATE = 2000000.0  # bytes / second
   1463     COMPRESSION_RATIO = 2.0  # unitless
   1464 
   1465     adb_call_time = ADB_CALL_PENALTY * adb_calls
   1466     adb_push_setup_time = ADB_PUSH_PENALTY * file_count
   1467     if is_zipping:
   1468       zip_time = ZIP_PENALTY + byte_count / ZIP_RATE
   1469       transfer_time = byte_count / (TRANSFER_RATE * COMPRESSION_RATIO)
   1470     else:
   1471       zip_time = 0
   1472       transfer_time = byte_count / TRANSFER_RATE
   1473     return adb_call_time + adb_push_setup_time + zip_time + transfer_time
   1474 
   1475   def _PushChangedFilesIndividually(self, files):
   1476     for h, d in files:
   1477       self.adb.Push(h, d)
   1478 
   1479   def _PushChangedFilesZipped(self, files, dirs):
   1480     with tempfile.NamedTemporaryFile(suffix='.zip') as zip_file:
   1481       zip_proc = multiprocessing.Process(
   1482           target=DeviceUtils._CreateDeviceZip,
   1483           args=(zip_file.name, files))
   1484       zip_proc.start()
   1485       try:
   1486         # While it's zipping, ensure the unzip command exists on the device.
   1487         if not self._MaybeInstallCommands():
   1488           zip_proc.terminate()
   1489           return False
   1490 
   1491         # Warm up NeedsSU cache while we're still zipping.
   1492         self.NeedsSU()
   1493         with device_temp_file.DeviceTempFile(
   1494             self.adb, suffix='.zip') as device_temp:
   1495           zip_proc.join()
   1496           self.adb.Push(zip_file.name, device_temp.name)
   1497           quoted_dirs = ' '.join(cmd_helper.SingleQuote(d) for d in dirs)
   1498           self.RunShellCommand(
   1499               'unzip %s&&chmod -R 777 %s' % (device_temp.name, quoted_dirs),
   1500               shell=True, as_root=True,
   1501               env={'PATH': '%s:$PATH' % install_commands.BIN_DIR},
   1502               check_return=True)
   1503       finally:
   1504         if zip_proc.is_alive():
   1505           zip_proc.terminate()
   1506     return True
   1507 
   1508   @staticmethod
   1509   def _CreateDeviceZip(zip_path, host_device_tuples):
   1510     with zipfile.ZipFile(zip_path, 'w') as zip_file:
   1511       for host_path, device_path in host_device_tuples:
   1512         zip_utils.WriteToZipFile(zip_file, host_path, device_path)
   1513 
   1514   # TODO(nednguyen): remove this and migrate the callsite to PathExists().
   1515   @decorators.WithTimeoutAndRetriesFromInstance()
   1516   def FileExists(self, device_path, timeout=None, retries=None):
   1517     """Checks whether the given file exists on the device.
   1518 
   1519     Arguments are the same as PathExists.
   1520     """
   1521     return self.PathExists(device_path, timeout=timeout, retries=retries)
   1522 
   1523   @decorators.WithTimeoutAndRetriesFromInstance()
   1524   def PathExists(self, device_paths, as_root=False, timeout=None, retries=None):
   1525     """Checks whether the given path(s) exists on the device.
   1526 
   1527     Args:
   1528       device_path: A string containing the absolute path to the file on the
   1529                    device, or an iterable of paths to check.
   1530       as_root: Whether root permissions should be use to check for the existence
   1531                of the given path(s).
   1532       timeout: timeout in seconds
   1533       retries: number of retries
   1534 
   1535     Returns:
   1536       True if the all given paths exist on the device, False otherwise.
   1537 
   1538     Raises:
   1539       CommandTimeoutError on timeout.
   1540       DeviceUnreachableError on missing device.
   1541     """
   1542     paths = device_paths
   1543     if isinstance(paths, basestring):
   1544       paths = (paths,)
   1545     if not paths:
   1546       return True
   1547     cmd = ['test', '-e', paths[0]]
   1548     for p in paths[1:]:
   1549       cmd.extend(['-a', '-e', p])
   1550     try:
   1551       self.RunShellCommand(cmd, as_root=as_root, check_return=True,
   1552                            timeout=timeout, retries=retries)
   1553       return True
   1554     except device_errors.CommandFailedError:
   1555       return False
   1556 
   1557   @decorators.WithTimeoutAndRetriesFromInstance()
   1558   def RemovePath(self, device_path, force=False, recursive=False,
   1559                  as_root=False, timeout=None, retries=None):
   1560     """Removes the given path(s) from the device.
   1561 
   1562     Args:
   1563       device_path: A string containing the absolute path to the file on the
   1564                    device, or an iterable of paths to check.
   1565       force: Whether to remove the path(s) with force (-f).
   1566       recursive: Whether to remove any directories in the path(s) recursively.
   1567       as_root: Whether root permissions should be use to remove the given
   1568                path(s).
   1569       timeout: timeout in seconds
   1570       retries: number of retries
   1571     """
   1572     args = ['rm']
   1573     if force:
   1574       args.append('-f')
   1575     if recursive:
   1576       args.append('-r')
   1577     if isinstance(device_path, basestring):
   1578       args.append(device_path)
   1579     else:
   1580       args.extend(device_path)
   1581     self.RunShellCommand(args, as_root=as_root, check_return=True)
   1582 
   1583 
   1584   @decorators.WithTimeoutAndRetriesFromInstance()
   1585   def PullFile(self, device_path, host_path, timeout=None, retries=None):
   1586     """Pull a file from the device.
   1587 
   1588     Args:
   1589       device_path: A string containing the absolute path of the file to pull
   1590                    from the device.
   1591       host_path: A string containing the absolute path of the destination on
   1592                  the host.
   1593       timeout: timeout in seconds
   1594       retries: number of retries
   1595 
   1596     Raises:
   1597       CommandFailedError on failure.
   1598       CommandTimeoutError on timeout.
   1599     """
   1600     # Create the base dir if it doesn't exist already
   1601     dirname = os.path.dirname(host_path)
   1602     if dirname and not os.path.exists(dirname):
   1603       os.makedirs(dirname)
   1604     self.adb.Pull(device_path, host_path)
   1605 
   1606   def _ReadFileWithPull(self, device_path):
   1607     try:
   1608       d = tempfile.mkdtemp()
   1609       host_temp_path = os.path.join(d, 'tmp_ReadFileWithPull')
   1610       self.adb.Pull(device_path, host_temp_path)
   1611       with open(host_temp_path, 'r') as host_temp:
   1612         return host_temp.read()
   1613     finally:
   1614       if os.path.exists(d):
   1615         shutil.rmtree(d)
   1616 
   1617   @decorators.WithTimeoutAndRetriesFromInstance()
   1618   def ReadFile(self, device_path, as_root=False, force_pull=False,
   1619                timeout=None, retries=None):
   1620     """Reads the contents of a file from the device.
   1621 
   1622     Args:
   1623       device_path: A string containing the absolute path of the file to read
   1624                    from the device.
   1625       as_root: A boolean indicating whether the read should be executed with
   1626                root privileges.
   1627       force_pull: A boolean indicating whether to force the operation to be
   1628           performed by pulling a file from the device. The default is, when the
   1629           contents are short, to retrieve the contents using cat instead.
   1630       timeout: timeout in seconds
   1631       retries: number of retries
   1632 
   1633     Returns:
   1634       The contents of |device_path| as a string. Contents are intepreted using
   1635       universal newlines, so the caller will see them encoded as '\n'. Also,
   1636       all lines will be terminated.
   1637 
   1638     Raises:
   1639       AdbCommandFailedError if the file can't be read.
   1640       CommandTimeoutError on timeout.
   1641       DeviceUnreachableError on missing device.
   1642     """
   1643     def get_size(path):
   1644       return self.FileSize(path, as_root=as_root)
   1645 
   1646     if (not force_pull
   1647         and 0 < get_size(device_path) <= self._MAX_ADB_OUTPUT_LENGTH):
   1648       return _JoinLines(self.RunShellCommand(
   1649           ['cat', device_path], as_root=as_root, check_return=True))
   1650     elif as_root and self.NeedsSU():
   1651       with device_temp_file.DeviceTempFile(self.adb) as device_temp:
   1652         cmd = 'SRC=%s DEST=%s;cp "$SRC" "$DEST" && chmod 666 "$DEST"' % (
   1653             cmd_helper.SingleQuote(device_path),
   1654             cmd_helper.SingleQuote(device_temp.name))
   1655         self.RunShellCommand(cmd, shell=True, as_root=True, check_return=True)
   1656         return self._ReadFileWithPull(device_temp.name)
   1657     else:
   1658       return self._ReadFileWithPull(device_path)
   1659 
   1660   def _WriteFileWithPush(self, device_path, contents):
   1661     with tempfile.NamedTemporaryFile() as host_temp:
   1662       host_temp.write(contents)
   1663       host_temp.flush()
   1664       self.adb.Push(host_temp.name, device_path)
   1665 
   1666   @decorators.WithTimeoutAndRetriesFromInstance()
   1667   def WriteFile(self, device_path, contents, as_root=False, force_push=False,
   1668                 timeout=None, retries=None):
   1669     """Writes |contents| to a file on the device.
   1670 
   1671     Args:
   1672       device_path: A string containing the absolute path to the file to write
   1673           on the device.
   1674       contents: A string containing the data to write to the device.
   1675       as_root: A boolean indicating whether the write should be executed with
   1676           root privileges (if available).
   1677       force_push: A boolean indicating whether to force the operation to be
   1678           performed by pushing a file to the device. The default is, when the
   1679           contents are short, to pass the contents using a shell script instead.
   1680       timeout: timeout in seconds
   1681       retries: number of retries
   1682 
   1683     Raises:
   1684       CommandFailedError if the file could not be written on the device.
   1685       CommandTimeoutError on timeout.
   1686       DeviceUnreachableError on missing device.
   1687     """
   1688     if not force_push and len(contents) < self._MAX_ADB_COMMAND_LENGTH:
   1689       # If the contents are small, for efficieny we write the contents with
   1690       # a shell command rather than pushing a file.
   1691       cmd = 'echo -n %s > %s' % (cmd_helper.SingleQuote(contents),
   1692                                  cmd_helper.SingleQuote(device_path))
   1693       self.RunShellCommand(cmd, shell=True, as_root=as_root, check_return=True)
   1694     elif as_root and self.NeedsSU():
   1695       # Adb does not allow to "push with su", so we first push to a temp file
   1696       # on a safe location, and then copy it to the desired location with su.
   1697       with device_temp_file.DeviceTempFile(self.adb) as device_temp:
   1698         self._WriteFileWithPush(device_temp.name, contents)
   1699         # Here we need 'cp' rather than 'mv' because the temp and
   1700         # destination files might be on different file systems (e.g.
   1701         # on internal storage and an external sd card).
   1702         self.RunShellCommand(['cp', device_temp.name, device_path],
   1703                              as_root=True, check_return=True)
   1704     else:
   1705       # If root is not needed, we can push directly to the desired location.
   1706       self._WriteFileWithPush(device_path, contents)
   1707 
   1708   def _ParseLongLsOutput(self, device_path, as_root=False, **kwargs):
   1709     """Run and scrape the output of 'ls -a -l' on a device directory."""
   1710     device_path = posixpath.join(device_path, '')  # Force trailing '/'.
   1711     output = self.RunShellCommand(
   1712         ['ls', '-a', '-l', device_path], as_root=as_root,
   1713         check_return=True, env={'TZ': 'utc'}, **kwargs)
   1714     if output and output[0].startswith('total '):
   1715       output.pop(0) # pylint: disable=maybe-no-member
   1716 
   1717     entries = []
   1718     for line in output:
   1719       m = _LONG_LS_OUTPUT_RE.match(line)
   1720       if m:
   1721         if m.group('filename') not in ['.', '..']:
   1722           entries.append(m.groupdict())
   1723       else:
   1724         logger.info('Skipping: %s', line)
   1725 
   1726     return entries
   1727 
   1728   def ListDirectory(self, device_path, as_root=False, **kwargs):
   1729     """List all files on a device directory.
   1730 
   1731     Mirroring os.listdir (and most client expectations) the resulting list
   1732     does not include the special entries '.' and '..' even if they are present
   1733     in the directory.
   1734 
   1735     Args:
   1736       device_path: A string containing the path of the directory on the device
   1737                    to list.
   1738       as_root: A boolean indicating whether the to use root privileges to list
   1739                the directory contents.
   1740       timeout: timeout in seconds
   1741       retries: number of retries
   1742 
   1743     Returns:
   1744       A list of filenames for all entries contained in the directory.
   1745 
   1746     Raises:
   1747       AdbCommandFailedError if |device_path| does not specify a valid and
   1748           accessible directory in the device.
   1749       CommandTimeoutError on timeout.
   1750       DeviceUnreachableError on missing device.
   1751     """
   1752     entries = self._ParseLongLsOutput(device_path, as_root=as_root, **kwargs)
   1753     return [d['filename'] for d in entries]
   1754 
   1755   def StatDirectory(self, device_path, as_root=False, **kwargs):
   1756     """List file and stat info for all entries on a device directory.
   1757 
   1758     Implementation notes: this is currently implemented by parsing the output
   1759     of 'ls -a -l' on the device. Whether possible and convenient, we attempt to
   1760     make parsing strict and return values mirroring those of the standard |os|
   1761     and |stat| Python modules.
   1762 
   1763     Mirroring os.listdir (and most client expectations) the resulting list
   1764     does not include the special entries '.' and '..' even if they are present
   1765     in the directory.
   1766 
   1767     Args:
   1768       device_path: A string containing the path of the directory on the device
   1769                    to list.
   1770       as_root: A boolean indicating whether the to use root privileges to list
   1771                the directory contents.
   1772       timeout: timeout in seconds
   1773       retries: number of retries
   1774 
   1775     Returns:
   1776       A list of dictionaries, each containing the following keys:
   1777         filename: A string with the file name.
   1778         st_mode: File permissions, use the stat module to interpret these.
   1779         st_nlink: Number of hard links (may be missing).
   1780         st_owner: A string with the user name of the owner.
   1781         st_group: A string with the group name of the owner.
   1782         st_rdev_pair: Device type as (major, minior) (only if inode device).
   1783         st_size: Size of file, in bytes (may be missing for non-regular files).
   1784         st_mtime: Time of most recent modification, in seconds since epoch
   1785           (although resolution is in minutes).
   1786         symbolic_link_to: If entry is a symbolic link, path where it points to;
   1787           missing otherwise.
   1788 
   1789     Raises:
   1790       AdbCommandFailedError if |device_path| does not specify a valid and
   1791           accessible directory in the device.
   1792       CommandTimeoutError on timeout.
   1793       DeviceUnreachableError on missing device.
   1794     """
   1795     entries = self._ParseLongLsOutput(device_path, as_root=as_root, **kwargs)
   1796     for d in entries:
   1797       for key, value in d.items():
   1798         if value is None:
   1799           del d[key]  # Remove missing fields.
   1800       d['st_mode'] = _ParseModeString(d['st_mode'])
   1801       d['st_mtime'] = calendar.timegm(
   1802           time.strptime(d['st_mtime'], _LS_DATE_FORMAT))
   1803       for key in ['st_nlink', 'st_size', 'st_rdev_major', 'st_rdev_minor']:
   1804         if key in d:
   1805           d[key] = int(d[key])
   1806       if 'st_rdev_major' in d and 'st_rdev_minor' in d:
   1807         d['st_rdev_pair'] = (d.pop('st_rdev_major'), d.pop('st_rdev_minor'))
   1808     return entries
   1809 
   1810   def StatPath(self, device_path, as_root=False, **kwargs):
   1811     """Get the stat attributes of a file or directory on the device.
   1812 
   1813     Args:
   1814       device_path: A string containing the path of a file or directory from
   1815                    which to get attributes.
   1816       as_root: A boolean indicating whether the to use root privileges to
   1817                access the file information.
   1818       timeout: timeout in seconds
   1819       retries: number of retries
   1820 
   1821     Returns:
   1822       A dictionary with the stat info collected; see StatDirectory for details.
   1823 
   1824     Raises:
   1825       CommandFailedError if device_path cannot be found on the device.
   1826       CommandTimeoutError on timeout.
   1827       DeviceUnreachableError on missing device.
   1828     """
   1829     dirname, filename = posixpath.split(posixpath.normpath(device_path))
   1830     for entry in self.StatDirectory(dirname, as_root=as_root, **kwargs):
   1831       if entry['filename'] == filename:
   1832         return entry
   1833     raise device_errors.CommandFailedError(
   1834         'Cannot find file or directory: %r' % device_path, str(self))
   1835 
   1836   def FileSize(self, device_path, as_root=False, **kwargs):
   1837     """Get the size of a file on the device.
   1838 
   1839     Note: This is implemented by parsing the output of the 'ls' command on
   1840     the device. On some Android versions, when passing a directory or special
   1841     file, the size is *not* reported and this function will throw an exception.
   1842 
   1843     Args:
   1844       device_path: A string containing the path of a file on the device.
   1845       as_root: A boolean indicating whether the to use root privileges to
   1846                access the file information.
   1847       timeout: timeout in seconds
   1848       retries: number of retries
   1849 
   1850     Returns:
   1851       The size of the file in bytes.
   1852 
   1853     Raises:
   1854       CommandFailedError if device_path cannot be found on the device, or
   1855         its size cannot be determited for some reason.
   1856       CommandTimeoutError on timeout.
   1857       DeviceUnreachableError on missing device.
   1858     """
   1859     entry = self.StatPath(device_path, as_root=as_root, **kwargs)
   1860     try:
   1861       return entry['st_size']
   1862     except KeyError:
   1863       raise device_errors.CommandFailedError(
   1864           'Could not determine the size of: %s' % device_path, str(self))
   1865 
   1866   @decorators.WithTimeoutAndRetriesFromInstance()
   1867   def SetJavaAsserts(self, enabled, timeout=None, retries=None):
   1868     """Enables or disables Java asserts.
   1869 
   1870     Args:
   1871       enabled: A boolean indicating whether Java asserts should be enabled
   1872                or disabled.
   1873       timeout: timeout in seconds
   1874       retries: number of retries
   1875 
   1876     Returns:
   1877       True if the device-side property changed and a restart is required as a
   1878       result, False otherwise.
   1879 
   1880     Raises:
   1881       CommandTimeoutError on timeout.
   1882     """
   1883     def find_property(lines, property_name):
   1884       for index, line in enumerate(lines):
   1885         if line.strip() == '':
   1886           continue
   1887         key_value = tuple(s.strip() for s in line.split('=', 1))
   1888         if len(key_value) != 2:
   1889           continue
   1890         key, value = key_value
   1891         if key == property_name:
   1892           return index, value
   1893       return None, ''
   1894 
   1895     new_value = 'all' if enabled else ''
   1896 
   1897     # First ensure the desired property is persisted.
   1898     try:
   1899       properties = self.ReadFile(self.LOCAL_PROPERTIES_PATH).splitlines()
   1900     except device_errors.CommandFailedError:
   1901       properties = []
   1902     index, value = find_property(properties, self.JAVA_ASSERT_PROPERTY)
   1903     if new_value != value:
   1904       if new_value:
   1905         new_line = '%s=%s' % (self.JAVA_ASSERT_PROPERTY, new_value)
   1906         if index is None:
   1907           properties.append(new_line)
   1908         else:
   1909           properties[index] = new_line
   1910       else:
   1911         assert index is not None  # since new_value == '' and new_value != value
   1912         properties.pop(index)
   1913       self.WriteFile(self.LOCAL_PROPERTIES_PATH, _JoinLines(properties))
   1914 
   1915     # Next, check the current runtime value is what we need, and
   1916     # if not, set it and report that a reboot is required.
   1917     value = self.GetProp(self.JAVA_ASSERT_PROPERTY)
   1918     if new_value != value:
   1919       self.SetProp(self.JAVA_ASSERT_PROPERTY, new_value)
   1920       return True
   1921     else:
   1922       return False
   1923 
   1924   def GetLanguage(self, cache=False):
   1925     """Returns the language setting on the device.
   1926     Args:
   1927       cache: Whether to use cached properties when available.
   1928     """
   1929     return self.GetProp('persist.sys.language', cache=cache)
   1930 
   1931   def GetCountry(self, cache=False):
   1932     """Returns the country setting on the device.
   1933 
   1934     Args:
   1935       cache: Whether to use cached properties when available.
   1936     """
   1937     return self.GetProp('persist.sys.country', cache=cache)
   1938 
   1939   @property
   1940   def screen_density(self):
   1941     """Returns the screen density of the device."""
   1942     DPI_TO_DENSITY = {
   1943       120: 'ldpi',
   1944       160: 'mdpi',
   1945       240: 'hdpi',
   1946       320: 'xhdpi',
   1947       480: 'xxhdpi',
   1948       640: 'xxxhdpi',
   1949     }
   1950     return DPI_TO_DENSITY.get(self.pixel_density, 'tvdpi')
   1951 
   1952   @property
   1953   def pixel_density(self):
   1954     return int(self.GetProp('ro.sf.lcd_density', cache=True))
   1955 
   1956   @property
   1957   def build_description(self):
   1958     """Returns the build description of the system.
   1959 
   1960     For example:
   1961       nakasi-user 4.4.4 KTU84P 1227136 release-keys
   1962     """
   1963     return self.GetProp('ro.build.description', cache=True)
   1964 
   1965   @property
   1966   def build_fingerprint(self):
   1967     """Returns the build fingerprint of the system.
   1968 
   1969     For example:
   1970       google/nakasi/grouper:4.4.4/KTU84P/1227136:user/release-keys
   1971     """
   1972     return self.GetProp('ro.build.fingerprint', cache=True)
   1973 
   1974   @property
   1975   def build_id(self):
   1976     """Returns the build ID of the system (e.g. 'KTU84P')."""
   1977     return self.GetProp('ro.build.id', cache=True)
   1978 
   1979   @property
   1980   def build_product(self):
   1981     """Returns the build product of the system (e.g. 'grouper')."""
   1982     return self.GetProp('ro.build.product', cache=True)
   1983 
   1984   @property
   1985   def build_type(self):
   1986     """Returns the build type of the system (e.g. 'user')."""
   1987     return self.GetProp('ro.build.type', cache=True)
   1988 
   1989   @property
   1990   def build_version_sdk(self):
   1991     """Returns the build version sdk of the system as a number (e.g. 19).
   1992 
   1993     For version code numbers see:
   1994     http://developer.android.com/reference/android/os/Build.VERSION_CODES.html
   1995 
   1996     For named constants see devil.android.sdk.version_codes
   1997 
   1998     Raises:
   1999       CommandFailedError if the build version sdk is not a number.
   2000     """
   2001     value = self.GetProp('ro.build.version.sdk', cache=True)
   2002     try:
   2003       return int(value)
   2004     except ValueError:
   2005       raise device_errors.CommandFailedError(
   2006           'Invalid build version sdk: %r' % value)
   2007 
   2008   @property
   2009   def product_cpu_abi(self):
   2010     """Returns the product cpu abi of the device (e.g. 'armeabi-v7a')."""
   2011     return self.GetProp('ro.product.cpu.abi', cache=True)
   2012 
   2013   @property
   2014   def product_model(self):
   2015     """Returns the name of the product model (e.g. 'Nexus 7')."""
   2016     return self.GetProp('ro.product.model', cache=True)
   2017 
   2018   @property
   2019   def product_name(self):
   2020     """Returns the product name of the device (e.g. 'nakasi')."""
   2021     return self.GetProp('ro.product.name', cache=True)
   2022 
   2023   @property
   2024   def product_board(self):
   2025     """Returns the product board name of the device (e.g. 'shamu')."""
   2026     return self.GetProp('ro.product.board', cache=True)
   2027 
   2028   def _EnsureCacheInitialized(self):
   2029     """Populates cache token, runs getprop and fetches $EXTERNAL_STORAGE."""
   2030     if self._cache['token']:
   2031       return
   2032     with self._cache_lock:
   2033       if self._cache['token']:
   2034         return
   2035       # Change the token every time to ensure that it will match only the
   2036       # previously dumped cache.
   2037       token = str(uuid.uuid1())
   2038       cmd = (
   2039           'c=/data/local/tmp/cache_token;'
   2040           'echo $EXTERNAL_STORAGE;'
   2041           'cat $c 2>/dev/null||echo;'
   2042           'echo "%s">$c &&' % token +
   2043           'getprop'
   2044       )
   2045       output = self.RunShellCommand(
   2046           cmd, shell=True, check_return=True, large_output=True)
   2047       # Error-checking for this existing is done in GetExternalStoragePath().
   2048       self._cache['external_storage'] = output[0]
   2049       self._cache['prev_token'] = output[1]
   2050       output = output[2:]
   2051 
   2052       prop_cache = self._cache['getprop']
   2053       prop_cache.clear()
   2054       for key, value in _GETPROP_RE.findall(''.join(output)):
   2055         prop_cache[key] = value
   2056       self._cache['token'] = token
   2057 
   2058   @decorators.WithTimeoutAndRetriesFromInstance()
   2059   def GetProp(self, property_name, cache=False, timeout=None, retries=None):
   2060     """Gets a property from the device.
   2061 
   2062     Args:
   2063       property_name: A string containing the name of the property to get from
   2064                      the device.
   2065       cache: Whether to use cached properties when available.
   2066       timeout: timeout in seconds
   2067       retries: number of retries
   2068 
   2069     Returns:
   2070       The value of the device's |property_name| property.
   2071 
   2072     Raises:
   2073       CommandTimeoutError on timeout.
   2074     """
   2075     assert isinstance(property_name, basestring), (
   2076         "property_name is not a string: %r" % property_name)
   2077 
   2078     if cache:
   2079       # It takes ~120ms to query a single property, and ~130ms to query all
   2080       # properties. So, when caching we always query all properties.
   2081       self._EnsureCacheInitialized()
   2082     else:
   2083       # timeout and retries are handled down at run shell, because we don't
   2084       # want to apply them in the other branch when reading from the cache
   2085       value = self.RunShellCommand(
   2086           ['getprop', property_name], single_line=True, check_return=True,
   2087           timeout=timeout, retries=retries)
   2088       self._cache['getprop'][property_name] = value
   2089     # Non-existent properties are treated as empty strings by getprop.
   2090     return self._cache['getprop'].get(property_name, '')
   2091 
   2092   @decorators.WithTimeoutAndRetriesFromInstance()
   2093   def SetProp(self, property_name, value, check=False, timeout=None,
   2094               retries=None):
   2095     """Sets a property on the device.
   2096 
   2097     Args:
   2098       property_name: A string containing the name of the property to set on
   2099                      the device.
   2100       value: A string containing the value to set to the property on the
   2101              device.
   2102       check: A boolean indicating whether to check that the property was
   2103              successfully set on the device.
   2104       timeout: timeout in seconds
   2105       retries: number of retries
   2106 
   2107     Raises:
   2108       CommandFailedError if check is true and the property was not correctly
   2109         set on the device (e.g. because it is not rooted).
   2110       CommandTimeoutError on timeout.
   2111     """
   2112     assert isinstance(property_name, basestring), (
   2113         "property_name is not a string: %r" % property_name)
   2114     assert isinstance(value, basestring), "value is not a string: %r" % value
   2115 
   2116     self.RunShellCommand(['setprop', property_name, value], check_return=True)
   2117     prop_cache = self._cache['getprop']
   2118     if property_name in prop_cache:
   2119       del prop_cache[property_name]
   2120     # TODO(perezju) remove the option and make the check mandatory, but using a
   2121     # single shell script to both set- and getprop.
   2122     if check and value != self.GetProp(property_name, cache=False):
   2123       raise device_errors.CommandFailedError(
   2124           'Unable to set property %r on the device to %r'
   2125           % (property_name, value), str(self))
   2126 
   2127   @decorators.WithTimeoutAndRetriesFromInstance()
   2128   def GetABI(self, timeout=None, retries=None):
   2129     """Gets the device main ABI.
   2130 
   2131     Args:
   2132       timeout: timeout in seconds
   2133       retries: number of retries
   2134 
   2135     Returns:
   2136       The device's main ABI name.
   2137 
   2138     Raises:
   2139       CommandTimeoutError on timeout.
   2140     """
   2141     return self.GetProp('ro.product.cpu.abi', cache=True)
   2142 
   2143   @decorators.WithTimeoutAndRetriesFromInstance()
   2144   def GetPids(self, process_name=None, timeout=None, retries=None):
   2145     """Returns the PIDs of processes containing the given name as substring.
   2146 
   2147     Note that the |process_name| is often the package name.
   2148 
   2149     Args:
   2150       process_name: A string containing the process name to get the PIDs for.
   2151                     If missing returns PIDs for all processes.
   2152       timeout: timeout in seconds
   2153       retries: number of retries
   2154 
   2155     Returns:
   2156       A dict mapping process name to a list of PIDs for each process that
   2157       contained the provided |process_name|.
   2158 
   2159     Raises:
   2160       CommandTimeoutError on timeout.
   2161       DeviceUnreachableError on missing device.
   2162     """
   2163     procs_pids = collections.defaultdict(list)
   2164     try:
   2165       ps_cmd = 'ps'
   2166       # ps behavior was changed in Android above N, http://crbug.com/686716
   2167       if (self.build_version_sdk >= version_codes.NOUGAT_MR1
   2168           and self.build_id[0] > 'N'):
   2169         ps_cmd = 'ps -e'
   2170       if process_name:
   2171         ps_output = self._RunPipedShellCommand(
   2172             '%s | grep -F %s' % (ps_cmd, cmd_helper.SingleQuote(process_name)))
   2173       else:
   2174         ps_output = self.RunShellCommand(
   2175             ps_cmd.split(), check_return=True, large_output=True)
   2176     except device_errors.AdbShellCommandFailedError as e:
   2177       if e.status and isinstance(e.status, list) and not e.status[0]:
   2178         # If ps succeeded but grep failed, there were no processes with the
   2179         # given name.
   2180         return procs_pids
   2181       else:
   2182         raise
   2183 
   2184     process_name = process_name or ''
   2185     for line in ps_output:
   2186       try:
   2187         ps_data = line.split()
   2188         pid, process = ps_data[1], ps_data[-1]
   2189         if process_name in process and pid != 'PID':
   2190           procs_pids[process].append(pid)
   2191       except IndexError:
   2192         pass
   2193     return procs_pids
   2194 
   2195   def GetApplicationPids(self, process_name, at_most_one=False, **kwargs):
   2196     """Returns the PID or PIDs of a given process name.
   2197 
   2198     Note that the |process_name|, often the package name, must match exactly.
   2199 
   2200     Args:
   2201       process_name: A string containing the process name to get the PIDs for.
   2202       at_most_one: A boolean indicating that at most one PID is expected to
   2203                    be found.
   2204       timeout: timeout in seconds
   2205       retries: number of retries
   2206 
   2207     Returns:
   2208       A list of the PIDs for the named process. If at_most_one=True returns
   2209       the single PID found or None otherwise.
   2210 
   2211     Raises:
   2212       CommandFailedError if at_most_one=True and more than one PID is found
   2213           for the named process.
   2214       CommandTimeoutError on timeout.
   2215       DeviceUnreachableError on missing device.
   2216     """
   2217     pids = self.GetPids(process_name, **kwargs).get(process_name, [])
   2218     if at_most_one:
   2219       if len(pids) > 1:
   2220         raise device_errors.CommandFailedError(
   2221             'Expected a single process but found PIDs: %s.' % ', '.join(pids),
   2222             device_serial=str(self))
   2223       return pids[0] if pids else None
   2224     else:
   2225       return pids
   2226 
   2227   @decorators.WithTimeoutAndRetriesFromInstance()
   2228   def GetEnforce(self, timeout=None, retries=None):
   2229     """Get the current mode of SELinux.
   2230 
   2231     Args:
   2232       timeout: timeout in seconds
   2233       retries: number of retries
   2234 
   2235     Returns:
   2236       True (enforcing), False (permissive), or None (disabled).
   2237 
   2238     Raises:
   2239       CommandFailedError on failure.
   2240       CommandTimeoutError on timeout.
   2241       DeviceUnreachableError on missing device.
   2242     """
   2243     output = self.RunShellCommand(
   2244         ['getenforce'], check_return=True, single_line=True).lower()
   2245     if output not in _SELINUX_MODE:
   2246       raise device_errors.CommandFailedError(
   2247           'Unexpected getenforce output: %s' % output)
   2248     return _SELINUX_MODE[output]
   2249 
   2250   @decorators.WithTimeoutAndRetriesFromInstance()
   2251   def SetEnforce(self, enabled, timeout=None, retries=None):
   2252     """Modify the mode SELinux is running in.
   2253 
   2254     Args:
   2255       enabled: a boolean indicating whether to put SELinux in encorcing mode
   2256                (if True), or permissive mode (otherwise).
   2257       timeout: timeout in seconds
   2258       retries: number of retries
   2259 
   2260     Raises:
   2261       CommandFailedError on failure.
   2262       CommandTimeoutError on timeout.
   2263       DeviceUnreachableError on missing device.
   2264     """
   2265     self.RunShellCommand(
   2266         ['setenforce', '1' if int(enabled) else '0'], as_root=True,
   2267         check_return=True)
   2268 
   2269   @decorators.WithTimeoutAndRetriesFromInstance()
   2270   def TakeScreenshot(self, host_path=None, timeout=None, retries=None):
   2271     """Takes a screenshot of the device.
   2272 
   2273     Args:
   2274       host_path: A string containing the path on the host to save the
   2275                  screenshot to. If None, a file name in the current
   2276                  directory will be generated.
   2277       timeout: timeout in seconds
   2278       retries: number of retries
   2279 
   2280     Returns:
   2281       The name of the file on the host to which the screenshot was saved.
   2282 
   2283     Raises:
   2284       CommandFailedError on failure.
   2285       CommandTimeoutError on timeout.
   2286       DeviceUnreachableError on missing device.
   2287     """
   2288     if not host_path:
   2289       host_path = os.path.abspath('screenshot-%s-%s.png' % (
   2290           self.serial, _GetTimeStamp()))
   2291     with device_temp_file.DeviceTempFile(self.adb, suffix='.png') as device_tmp:
   2292       self.RunShellCommand(['/system/bin/screencap', '-p', device_tmp.name],
   2293                            check_return=True)
   2294       self.PullFile(device_tmp.name, host_path)
   2295     return host_path
   2296 
   2297   @decorators.WithTimeoutAndRetriesFromInstance()
   2298   def GetMemoryUsageForPid(self, pid, timeout=None, retries=None):
   2299     """Gets the memory usage for the given PID.
   2300 
   2301     Args:
   2302       pid: PID of the process.
   2303       timeout: timeout in seconds
   2304       retries: number of retries
   2305 
   2306     Returns:
   2307       A dict containing memory usage statistics for the PID. May include:
   2308         Size, Rss, Pss, Shared_Clean, Shared_Dirty, Private_Clean,
   2309         Private_Dirty, VmHWM
   2310 
   2311     Raises:
   2312       CommandTimeoutError on timeout.
   2313     """
   2314     result = collections.defaultdict(int)
   2315 
   2316     try:
   2317       result.update(self._GetMemoryUsageForPidFromSmaps(pid))
   2318     except device_errors.CommandFailedError:
   2319       logger.exception('Error getting memory usage from smaps')
   2320 
   2321     try:
   2322       result.update(self._GetMemoryUsageForPidFromStatus(pid))
   2323     except device_errors.CommandFailedError:
   2324       logger.exception('Error getting memory usage from status')
   2325 
   2326     return result
   2327 
   2328   @decorators.WithTimeoutAndRetriesFromInstance()
   2329   def DismissCrashDialogIfNeeded(self, timeout=None, retries=None):
   2330     """Dismiss the error/ANR dialog if present.
   2331 
   2332     Returns: Name of the crashed package if a dialog is focused,
   2333              None otherwise.
   2334     """
   2335     def _FindFocusedWindow():
   2336       match = None
   2337       # TODO(jbudorick): Try to grep the output on the device instead of using
   2338       # large_output if/when DeviceUtils exposes a public interface for piped
   2339       # shell command handling.
   2340       for line in self.RunShellCommand(['dumpsys', 'window', 'windows'],
   2341                                        check_return=True, large_output=True):
   2342         match = re.match(_CURRENT_FOCUS_CRASH_RE, line)
   2343         if match:
   2344           break
   2345       return match
   2346 
   2347     match = _FindFocusedWindow()
   2348     if not match:
   2349       return None
   2350     package = match.group(2)
   2351     logger.warning('Trying to dismiss %s dialog for %s', *match.groups())
   2352     self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
   2353     self.SendKeyEvent(keyevent.KEYCODE_DPAD_RIGHT)
   2354     self.SendKeyEvent(keyevent.KEYCODE_ENTER)
   2355     match = _FindFocusedWindow()
   2356     if match:
   2357       logger.error('Still showing a %s dialog for %s', *match.groups())
   2358     return package
   2359 
   2360   def _GetMemoryUsageForPidFromSmaps(self, pid):
   2361     SMAPS_COLUMNS = (
   2362         'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean',
   2363         'Private_Dirty')
   2364 
   2365     showmap_out = self._RunPipedShellCommand(
   2366         'showmap %d | grep TOTAL' % int(pid), as_root=True)
   2367 
   2368     split_totals = showmap_out[-1].split()
   2369     if (not split_totals
   2370         or len(split_totals) != 9
   2371         or split_totals[-1] != 'TOTAL'):
   2372       raise device_errors.CommandFailedError(
   2373           'Invalid output from showmap: %s' % '\n'.join(showmap_out))
   2374 
   2375     return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals)))
   2376 
   2377   def _GetMemoryUsageForPidFromStatus(self, pid):
   2378     for line in self.ReadFile(
   2379         '/proc/%s/status' % str(pid), as_root=True).splitlines():
   2380       if line.startswith('VmHWM:'):
   2381         return {'VmHWM': int(line.split()[1])}
   2382     raise device_errors.CommandFailedError(
   2383         'Could not find memory peak value for pid %s', str(pid))
   2384 
   2385   def GetLogcatMonitor(self, *args, **kwargs):
   2386     """Returns a new LogcatMonitor associated with this device.
   2387 
   2388     Parameters passed to this function are passed directly to
   2389     |logcat_monitor.LogcatMonitor| and are documented there.
   2390     """
   2391     return logcat_monitor.LogcatMonitor(self.adb, *args, **kwargs)
   2392 
   2393   def GetClientCache(self, client_name):
   2394     """Returns client cache."""
   2395     if client_name not in self._client_caches:
   2396       self._client_caches[client_name] = {}
   2397     return self._client_caches[client_name]
   2398 
   2399   def _ClearCache(self):
   2400     """Clears all caches."""
   2401     for client in self._client_caches:
   2402       self._client_caches[client].clear()
   2403     self._cache = {
   2404         # Map of packageId -> list of on-device .apk paths
   2405         'package_apk_paths': {},
   2406         # Set of packageId that were loaded from LoadCacheData and not yet
   2407         # verified.
   2408         'package_apk_paths_to_verify': set(),
   2409         # Map of packageId -> set of on-device .apk checksums
   2410         'package_apk_checksums': {},
   2411         # Map of property_name -> value
   2412         'getprop': {},
   2413         # Map of device_path -> [ignore_other_files, map of path->checksum]
   2414         'device_path_checksums': {},
   2415         # Location of sdcard ($EXTERNAL_STORAGE).
   2416         'external_storage': None,
   2417         # Token used to detect when LoadCacheData is stale.
   2418         'token': None,
   2419         'prev_token': None,
   2420     }
   2421 
   2422   @decorators.WithTimeoutAndRetriesFromInstance()
   2423   def LoadCacheData(self, data, timeout=None, retries=None):
   2424     """Initializes the cache from data created using DumpCacheData.
   2425 
   2426     The cache is used only if its token matches the one found on the device.
   2427     This prevents a stale cache from being used (which can happen when sharing
   2428     devices).
   2429 
   2430     Args:
   2431       data: A previously serialized cache (string).
   2432       timeout: timeout in seconds
   2433       retries: number of retries
   2434 
   2435     Returns:
   2436       Whether the cache was loaded.
   2437     """
   2438     obj = json.loads(data)
   2439     self._EnsureCacheInitialized()
   2440     given_token = obj.get('token')
   2441     if not given_token or self._cache['prev_token'] != given_token:
   2442       logger.warning('Stale cache detected. Not using it.')
   2443       return False
   2444 
   2445     self._cache['package_apk_paths'] = obj.get('package_apk_paths', {})
   2446     # When using a cache across script invokations, verify that apps have
   2447     # not been uninstalled.
   2448     self._cache['package_apk_paths_to_verify'] = set(
   2449         self._cache['package_apk_paths'].iterkeys())
   2450 
   2451     package_apk_checksums = obj.get('package_apk_checksums', {})
   2452     for k, v in package_apk_checksums.iteritems():
   2453       package_apk_checksums[k] = set(v)
   2454     self._cache['package_apk_checksums'] = package_apk_checksums
   2455     device_path_checksums = obj.get('device_path_checksums', {})
   2456     self._cache['device_path_checksums'] = device_path_checksums
   2457     return True
   2458 
   2459   @decorators.WithTimeoutAndRetriesFromInstance()
   2460   def DumpCacheData(self, timeout=None, retries=None):
   2461     """Dumps the current cache state to a string.
   2462 
   2463     Args:
   2464       timeout: timeout in seconds
   2465       retries: number of retries
   2466 
   2467     Returns:
   2468       A serialized cache as a string.
   2469     """
   2470     self._EnsureCacheInitialized()
   2471     obj = {}
   2472     obj['token'] = self._cache['token']
   2473     obj['package_apk_paths'] = self._cache['package_apk_paths']
   2474     obj['package_apk_checksums'] = self._cache['package_apk_checksums']
   2475     # JSON can't handle sets.
   2476     for k, v in obj['package_apk_checksums'].iteritems():
   2477       obj['package_apk_checksums'][k] = list(v)
   2478     obj['device_path_checksums'] = self._cache['device_path_checksums']
   2479     return json.dumps(obj, separators=(',', ':'))
   2480 
   2481   @classmethod
   2482   def parallel(cls, devices, async=False):
   2483     """Creates a Parallelizer to operate over the provided list of devices.
   2484 
   2485     Args:
   2486       devices: A list of either DeviceUtils instances or objects from
   2487                from which DeviceUtils instances can be constructed. If None,
   2488                all attached devices will be used.
   2489       async: If true, returns a Parallelizer that runs operations
   2490              asynchronously.
   2491 
   2492     Returns:
   2493       A Parallelizer operating over |devices|.
   2494     """
   2495     devices = [d if isinstance(d, cls) else cls(d) for d in devices]
   2496     if async:
   2497       return parallelizer.Parallelizer(devices)
   2498     else:
   2499       return parallelizer.SyncParallelizer(devices)
   2500 
   2501   @classmethod
   2502   def HealthyDevices(cls, blacklist=None, device_arg='default', **kwargs):
   2503     """Returns a list of DeviceUtils instances.
   2504 
   2505     Returns a list of DeviceUtils instances that are attached, not blacklisted,
   2506     and optionally filtered by --device flags or ANDROID_SERIAL environment
   2507     variable.
   2508 
   2509     Args:
   2510       blacklist: A DeviceBlacklist instance (optional). Device serials in this
   2511           blacklist will never be returned, but a warning will be logged if they
   2512           otherwise would have been.
   2513       device_arg: The value of the --device flag. This can be:
   2514           'default' -> Same as [], but returns an empty list rather than raise a
   2515               NoDevicesError.
   2516           [] -> Returns all devices, unless $ANDROID_SERIAL is set.
   2517           None -> Use $ANDROID_SERIAL if set, otherwise looks for a single
   2518               attached device. Raises an exception if multiple devices are
   2519               attached.
   2520           'serial' -> Returns an instance for the given serial, if not
   2521               blacklisted.
   2522           ['A', 'B', ...] -> Returns instances for the subset that is not
   2523               blacklisted.
   2524       A device serial, or a list of device serials (optional).
   2525 
   2526     Returns:
   2527       A list of DeviceUtils instances.
   2528 
   2529     Raises:
   2530       NoDevicesError: Raised when no non-blacklisted devices exist and
   2531           device_arg is passed.
   2532       MultipleDevicesError: Raise when multiple devices exist, but |device_arg|
   2533           is None.
   2534     """
   2535     allow_no_devices = False
   2536     if device_arg == 'default':
   2537       allow_no_devices = True
   2538       device_arg = ()
   2539 
   2540     select_multiple = True
   2541     if not (isinstance(device_arg, tuple) or isinstance(device_arg, list)):
   2542       select_multiple = False
   2543       if device_arg:
   2544         device_arg = (device_arg,)
   2545 
   2546     blacklisted_devices = blacklist.Read() if blacklist else []
   2547 
   2548     # adb looks for ANDROID_SERIAL, so support it as well.
   2549     android_serial = os.environ.get('ANDROID_SERIAL')
   2550     if not device_arg and android_serial:
   2551       device_arg = (android_serial,)
   2552 
   2553     def blacklisted(serial):
   2554       if serial in blacklisted_devices:
   2555         logger.warning('Device %s is blacklisted.', serial)
   2556         return True
   2557       return False
   2558 
   2559     if device_arg:
   2560       devices = [cls(x, **kwargs) for x in device_arg if not blacklisted(x)]
   2561     else:
   2562       devices = []
   2563       for adb in adb_wrapper.AdbWrapper.Devices():
   2564         if not blacklisted(adb.GetDeviceSerial()):
   2565           devices.append(cls(_CreateAdbWrapper(adb), **kwargs))
   2566 
   2567     if len(devices) == 0 and not allow_no_devices:
   2568       raise device_errors.NoDevicesError()
   2569     if len(devices) > 1 and not select_multiple:
   2570       raise device_errors.MultipleDevicesError(devices)
   2571     return sorted(devices)
   2572 
   2573   @decorators.WithTimeoutAndRetriesFromInstance()
   2574   def RestartAdbd(self, timeout=None, retries=None):
   2575     logger.info('Restarting adbd on device.')
   2576     with device_temp_file.DeviceTempFile(self.adb, suffix='.sh') as script:
   2577       self.WriteFile(script.name, _RESTART_ADBD_SCRIPT)
   2578       self.RunShellCommand(
   2579           ['source', script.name], check_return=True, as_root=True)
   2580       self.adb.WaitForDevice()
   2581 
   2582   @decorators.WithTimeoutAndRetriesFromInstance()
   2583   def GrantPermissions(self, package, permissions, timeout=None, retries=None):
   2584     # Permissions only need to be set on M and above because of the changes to
   2585     # the permission model.
   2586     if not permissions or self.build_version_sdk < version_codes.MARSHMALLOW:
   2587       return
   2588     logger.info('Setting permissions for %s.', package)
   2589     permissions = [p for p in permissions if p not in _PERMISSIONS_BLACKLIST]
   2590     if ('android.permission.WRITE_EXTERNAL_STORAGE' in permissions
   2591         and 'android.permission.READ_EXTERNAL_STORAGE' not in permissions):
   2592       permissions.append('android.permission.READ_EXTERNAL_STORAGE')
   2593     cmd = '&&'.join('pm grant %s %s' % (package, p) for p in permissions)
   2594     if cmd:
   2595       output = self.RunShellCommand(cmd, shell=True, check_return=True)
   2596       if output:
   2597         logger.warning('Possible problem when granting permissions. Blacklist '
   2598                        'may need to be updated.')
   2599         for line in output:
   2600           logger.warning('  %s', line)
   2601 
   2602   @decorators.WithTimeoutAndRetriesFromInstance()
   2603   def IsScreenOn(self, timeout=None, retries=None):
   2604     """Determines if screen is on.
   2605 
   2606     Dumpsys input_method exposes screen on/off state. Below is an explination of
   2607     the states.
   2608 
   2609     Pre-L:
   2610       On: mScreenOn=true
   2611       Off: mScreenOn=false
   2612     L+:
   2613       On: mInteractive=true
   2614       Off: mInteractive=false
   2615 
   2616     Returns:
   2617       True if screen is on, false if it is off.
   2618 
   2619     Raises:
   2620       device_errors.CommandFailedError: If screen state cannot be found.
   2621     """
   2622     if self.build_version_sdk < version_codes.LOLLIPOP:
   2623       input_check = 'mScreenOn'
   2624       check_value = 'mScreenOn=true'
   2625     else:
   2626       input_check = 'mInteractive'
   2627       check_value = 'mInteractive=true'
   2628     dumpsys_out = self._RunPipedShellCommand(
   2629         'dumpsys input_method | grep %s' % input_check)
   2630     if not dumpsys_out:
   2631       raise device_errors.CommandFailedError(
   2632           'Unable to detect screen state', str(self))
   2633     return check_value in dumpsys_out[0]
   2634 
   2635   @decorators.WithTimeoutAndRetriesFromInstance()
   2636   def SetScreen(self, on, timeout=None, retries=None):
   2637     """Turns screen on and off.
   2638 
   2639     Args:
   2640       on: bool to decide state to switch to. True = on False = off.
   2641     """
   2642     def screen_test():
   2643       return self.IsScreenOn() == on
   2644 
   2645     if screen_test():
   2646       logger.info('Screen already in expected state.')
   2647       return
   2648     self.SendKeyEvent(keyevent.KEYCODE_POWER)
   2649     timeout_retry.WaitFor(screen_test, wait_period=1)
   2650