Home | History | Annotate | Download | only in controllers
      1 #!/usr/bin/env python3.4
      2 #
      3 #   Copyright 2016 - The Android Open Source Project
      4 #
      5 #   Licensed under the Apache License, Version 2.0 (the "License");
      6 #   you may not use this file except in compliance with the License.
      7 #   You may obtain a copy of the License at
      8 #
      9 #       http://www.apache.org/licenses/LICENSE-2.0
     10 #
     11 #   Unless required by applicable law or agreed to in writing, software
     12 #   distributed under the License is distributed on an "AS IS" BASIS,
     13 #   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14 #   See the License for the specific language governing permissions and
     15 #   limitations under the License.
     16 
     17 from builtins import str
     18 from builtins import open
     19 from datetime import datetime
     20 
     21 import collections
     22 import logging
     23 import math
     24 import os
     25 import re
     26 import socket
     27 import time
     28 
     29 from acts import logger as acts_logger
     30 from acts import signals
     31 from acts import tracelogger
     32 from acts import utils
     33 from acts.controllers import adb
     34 from acts.controllers import fastboot
     35 from acts.controllers.sl4a_lib import sl4a_manager
     36 from acts.controllers.utils_lib.ssh import connection
     37 from acts.controllers.utils_lib.ssh import settings
     38 
     39 ACTS_CONTROLLER_CONFIG_NAME = "AndroidDevice"
     40 ACTS_CONTROLLER_REFERENCE_NAME = "android_devices"
     41 
     42 ANDROID_DEVICE_PICK_ALL_TOKEN = "*"
     43 # Key name for adb logcat extra params in config file.
     44 ANDROID_DEVICE_ADB_LOGCAT_PARAM_KEY = "adb_logcat_param"
     45 ANDROID_DEVICE_EMPTY_CONFIG_MSG = "Configuration is empty, abort!"
     46 ANDROID_DEVICE_NOT_LIST_CONFIG_MSG = "Configuration should be a list, abort!"
     47 CRASH_REPORT_PATHS = ("/data/tombstones/", "/data/vendor/ramdump/",
     48                       "/data/ramdump/", "/data/vendor/ssrdump",
     49                       "/data/vendor/ramdump/bluetooth")
     50 CRASH_REPORT_SKIPS = ("RAMDUMP_RESERVED", "RAMDUMP_STATUS", "RAMDUMP_OUTPUT",
     51                       "bluetooth")
     52 DEFAULT_QXDM_LOG_PATH = "/data/vendor/radio/diag_logs"
     53 BUG_REPORT_TIMEOUT = 1800
     54 PULL_TIMEOUT = 300
     55 PORT_RETRY_COUNT = 3
     56 IPERF_TIMEOUT = 60
     57 SL4A_APK_NAME = "com.googlecode.android_scripting"
     58 WAIT_FOR_DEVICE_TIMEOUT = 180
     59 ENCRYPTION_WINDOW = "CryptKeeper"
     60 DEFAULT_DEVICE_PASSWORD = "1111"
     61 RELEASE_ID_REGEXES = [re.compile(r'\w+\.\d+\.\d+'), re.compile(r'N\w+')]
     62 
     63 
     64 class AndroidDeviceError(signals.ControllerError):
     65     pass
     66 
     67 
     68 class DoesNotExistError(AndroidDeviceError):
     69     """Raised when something that does not exist is referenced.
     70     """
     71 
     72 
     73 def create(configs):
     74     """Creates AndroidDevice controller objects.
     75 
     76     Args:
     77         configs: A list of dicts, each representing a configuration for an
     78                  Android device.
     79 
     80     Returns:
     81         A list of AndroidDevice objects.
     82     """
     83     if not configs:
     84         raise AndroidDeviceError(ANDROID_DEVICE_EMPTY_CONFIG_MSG)
     85     elif configs == ANDROID_DEVICE_PICK_ALL_TOKEN:
     86         ads = get_all_instances()
     87     elif not isinstance(configs, list):
     88         raise AndroidDeviceError(ANDROID_DEVICE_NOT_LIST_CONFIG_MSG)
     89     elif isinstance(configs[0], str):
     90         # Configs is a list of serials.
     91         ads = get_instances(configs)
     92     else:
     93         # Configs is a list of dicts.
     94         ads = get_instances_with_configs(configs)
     95 
     96     ads[0].log.info('The primary device under test is "%s".' % ads[0].serial)
     97 
     98     for ad in ads:
     99         if not ad.is_connected():
    100             raise DoesNotExistError(("Android device %s is specified in config"
    101                                      " but is not attached.") % ad.serial)
    102     _start_services_on_ads(ads)
    103     return ads
    104 
    105 
    106 def destroy(ads):
    107     """Cleans up AndroidDevice objects.
    108 
    109     Args:
    110         ads: A list of AndroidDevice objects.
    111     """
    112     for ad in ads:
    113         try:
    114             ad.clean_up()
    115         except:
    116             ad.log.exception("Failed to clean up properly.")
    117 
    118 
    119 def get_info(ads):
    120     """Get information on a list of AndroidDevice objects.
    121 
    122     Args:
    123         ads: A list of AndroidDevice objects.
    124 
    125     Returns:
    126         A list of dict, each representing info for an AndroidDevice objects.
    127     """
    128     device_info = []
    129     for ad in ads:
    130         info = {"serial": ad.serial, "model": ad.model}
    131         info.update(ad.build_info)
    132         device_info.append(info)
    133     return device_info
    134 
    135 
    136 def get_post_job_info(ads):
    137     """Returns the tracked build id to test_run_summary.json
    138 
    139     Args:
    140         ads: A list of AndroidDevice objects.
    141 
    142     Returns:
    143         A dict consisting of {'build_id': ads[0].build_info}
    144     """
    145     return 'Build Info', ads[0].build_info
    146 
    147 
    148 def _start_services_on_ads(ads):
    149     """Starts long running services on multiple AndroidDevice objects.
    150 
    151     If any one AndroidDevice object fails to start services, cleans up all
    152     existing AndroidDevice objects and their services.
    153 
    154     Args:
    155         ads: A list of AndroidDevice objects whose services to start.
    156     """
    157     running_ads = []
    158     for ad in ads:
    159         running_ads.append(ad)
    160         if not ad.ensure_screen_on():
    161             ad.log.error("User window cannot come up")
    162             destroy(running_ads)
    163             raise AndroidDeviceError("User window cannot come up")
    164         if not ad.skip_sl4a and not ad.is_sl4a_installed():
    165             ad.log.error("sl4a.apk is not installed")
    166             destroy(running_ads)
    167             raise AndroidDeviceError("The required sl4a.apk is not installed")
    168         try:
    169             ad.start_services(skip_sl4a=ad.skip_sl4a)
    170         except:
    171             ad.log.exception("Failed to start some services, abort!")
    172             destroy(running_ads)
    173             raise
    174 
    175 
    176 def _parse_device_list(device_list_str, key):
    177     """Parses a byte string representing a list of devices. The string is
    178     generated by calling either adb or fastboot.
    179 
    180     Args:
    181         device_list_str: Output of adb or fastboot.
    182         key: The token that signifies a device in device_list_str.
    183 
    184     Returns:
    185         A list of android device serial numbers.
    186     """
    187     return re.findall(r"(\S+)\t%s" % key, device_list_str)
    188 
    189 
    190 def list_adb_devices():
    191     """List all android devices connected to the computer that are detected by
    192     adb.
    193 
    194     Returns:
    195         A list of android device serials. Empty if there's none.
    196     """
    197     out = adb.AdbProxy().devices()
    198     return _parse_device_list(out, "device")
    199 
    200 
    201 def list_fastboot_devices():
    202     """List all android devices connected to the computer that are in in
    203     fastboot mode. These are detected by fastboot.
    204 
    205     Returns:
    206         A list of android device serials. Empty if there's none.
    207     """
    208     out = fastboot.FastbootProxy().devices()
    209     return _parse_device_list(out, "fastboot")
    210 
    211 
    212 def get_instances(serials):
    213     """Create AndroidDevice instances from a list of serials.
    214 
    215     Args:
    216         serials: A list of android device serials.
    217 
    218     Returns:
    219         A list of AndroidDevice objects.
    220     """
    221     results = []
    222     for s in serials:
    223         results.append(AndroidDevice(s))
    224     return results
    225 
    226 
    227 def get_instances_with_configs(configs):
    228     """Create AndroidDevice instances from a list of json configs.
    229 
    230     Each config should have the required key-value pair "serial".
    231 
    232     Args:
    233         configs: A list of dicts each representing the configuration of one
    234             android device.
    235 
    236     Returns:
    237         A list of AndroidDevice objects.
    238     """
    239     results = []
    240     for c in configs:
    241         try:
    242             serial = c.pop("serial")
    243         except KeyError:
    244             raise AndroidDeviceError(
    245                 "Required value 'serial' is missing in AndroidDevice config %s."
    246                 % c)
    247         ssh_config = c.pop("ssh_config", None)
    248         ssh_connection = None
    249         if ssh_config is not None:
    250             ssh_settings = settings.from_config(ssh_config)
    251             ssh_connection = connection.SshConnection(ssh_settings)
    252         ad = AndroidDevice(serial, ssh_connection=ssh_connection)
    253         ad.load_config(c)
    254         results.append(ad)
    255     return results
    256 
    257 
    258 def get_all_instances(include_fastboot=False):
    259     """Create AndroidDevice instances for all attached android devices.
    260 
    261     Args:
    262         include_fastboot: Whether to include devices in bootloader mode or not.
    263 
    264     Returns:
    265         A list of AndroidDevice objects each representing an android device
    266         attached to the computer.
    267     """
    268     if include_fastboot:
    269         serial_list = list_adb_devices() + list_fastboot_devices()
    270         return get_instances(serial_list)
    271     return get_instances(list_adb_devices())
    272 
    273 
    274 def filter_devices(ads, func):
    275     """Finds the AndroidDevice instances from a list that match certain
    276     conditions.
    277 
    278     Args:
    279         ads: A list of AndroidDevice instances.
    280         func: A function that takes an AndroidDevice object and returns True
    281             if the device satisfies the filter condition.
    282 
    283     Returns:
    284         A list of AndroidDevice instances that satisfy the filter condition.
    285     """
    286     results = []
    287     for ad in ads:
    288         if func(ad):
    289             results.append(ad)
    290     return results
    291 
    292 
    293 def get_device(ads, **kwargs):
    294     """Finds a unique AndroidDevice instance from a list that has specific
    295     attributes of certain values.
    296 
    297     Example:
    298         get_device(android_devices, label="foo", phone_number="1234567890")
    299         get_device(android_devices, model="angler")
    300 
    301     Args:
    302         ads: A list of AndroidDevice instances.
    303         kwargs: keyword arguments used to filter AndroidDevice instances.
    304 
    305     Returns:
    306         The target AndroidDevice instance.
    307 
    308     Raises:
    309         AndroidDeviceError is raised if none or more than one device is
    310         matched.
    311     """
    312 
    313     def _get_device_filter(ad):
    314         for k, v in kwargs.items():
    315             if not hasattr(ad, k):
    316                 return False
    317             elif getattr(ad, k) != v:
    318                 return False
    319         return True
    320 
    321     filtered = filter_devices(ads, _get_device_filter)
    322     if not filtered:
    323         raise AndroidDeviceError(
    324             "Could not find a target device that matches condition: %s." %
    325             kwargs)
    326     elif len(filtered) == 1:
    327         return filtered[0]
    328     else:
    329         serials = [ad.serial for ad in filtered]
    330         raise AndroidDeviceError("More than one device matched: %s" % serials)
    331 
    332 
    333 def take_bug_reports(ads, test_name, begin_time):
    334     """Takes bug reports on a list of android devices.
    335 
    336     If you want to take a bug report, call this function with a list of
    337     android_device objects in on_fail. But reports will be taken on all the
    338     devices in the list concurrently. Bug report takes a relative long
    339     time to take, so use this cautiously.
    340 
    341     Args:
    342         ads: A list of AndroidDevice instances.
    343         test_name: Name of the test case that triggered this bug report.
    344         begin_time: Logline format timestamp taken when the test started.
    345     """
    346 
    347     def take_br(test_name, begin_time, ad):
    348         ad.take_bug_report(test_name, begin_time)
    349 
    350     args = [(test_name, begin_time, ad) for ad in ads]
    351     utils.concurrent_exec(take_br, args)
    352 
    353 
    354 class AndroidDevice:
    355     """Class representing an android device.
    356 
    357     Each object of this class represents one Android device in ACTS, including
    358     handles to adb, fastboot, and sl4a clients. In addition to direct adb
    359     commands, this object also uses adb port forwarding to talk to the Android
    360     device.
    361 
    362     Attributes:
    363         serial: A string that's the serial number of the Android device.
    364         log_path: A string that is the path where all logs collected on this
    365                   android device should be stored.
    366         log: A logger adapted from root logger with added token specific to an
    367              AndroidDevice instance.
    368         adb_logcat_process: A process that collects the adb logcat.
    369         adb_logcat_file_path: A string that's the full path to the adb logcat
    370                               file collected, if any.
    371         adb: An AdbProxy object used for interacting with the device via adb.
    372         fastboot: A FastbootProxy object used for interacting with the device
    373                   via fastboot.
    374     """
    375 
    376     def __init__(self, serial='', ssh_connection=None):
    377         self.serial = serial
    378         # logging.log_path only exists when this is used in an ACTS test run.
    379         log_path_base = getattr(logging, 'log_path', '/tmp/logs')
    380         self.log_path = os.path.join(log_path_base, 'AndroidDevice%s' % serial)
    381         self.log = tracelogger.TraceLogger(
    382             AndroidDeviceLoggerAdapter(logging.getLogger(), {
    383                 'serial': self.serial
    384             }))
    385         self._event_dispatchers = {}
    386         self.adb_logcat_process = None
    387         self.adb_logcat_file_path = None
    388         self.adb = adb.AdbProxy(serial, ssh_connection=ssh_connection)
    389         self.fastboot = fastboot.FastbootProxy(
    390             serial, ssh_connection=ssh_connection)
    391         if not self.is_bootloader:
    392             self.root_adb()
    393         self._ssh_connection = ssh_connection
    394         self.skip_sl4a = False
    395         self.crash_report = None
    396         self.data_accounting = collections.defaultdict(int)
    397         self._sl4a_manager = sl4a_manager.Sl4aManager(self.adb)
    398         self.last_logcat_timestamp = None
    399 
    400     def clean_up(self):
    401         """Cleans up the AndroidDevice object and releases any resources it
    402         claimed.
    403         """
    404         self.stop_services()
    405         if self._ssh_connection:
    406             self._ssh_connection.close()
    407 
    408     # TODO(angli): This function shall be refactored to accommodate all services
    409     # and not have hard coded switch for SL4A when b/29157104 is done.
    410     def start_services(self, skip_sl4a=False, skip_setup_wizard=True):
    411         """Starts long running services on the android device.
    412 
    413         1. Start adb logcat capture.
    414         2. Start SL4A if not skipped.
    415 
    416         Args:
    417             skip_sl4a: Does not attempt to start SL4A if True.
    418             skip_setup_wizard: Whether or not to skip the setup wizard.
    419         """
    420         if skip_setup_wizard:
    421             self.exit_setup_wizard()
    422         try:
    423             self.start_adb_logcat()
    424         except:
    425             self.log.exception("Failed to start adb logcat!")
    426             raise
    427         if not skip_sl4a:
    428             try:
    429                 droid, ed = self.get_droid()
    430                 ed.start()
    431             except:
    432                 self.log.exception("Failed to start sl4a!")
    433                 raise
    434 
    435     def stop_services(self):
    436         """Stops long running services on the android device.
    437 
    438         Stop adb logcat and terminate sl4a sessions if exist.
    439         """
    440         if self.is_adb_logcat_on:
    441             self.stop_adb_logcat()
    442         self.terminate_all_sessions()
    443         self.stop_sl4a()
    444 
    445     def is_connected(self):
    446         out = self.adb.devices()
    447         devices = _parse_device_list(out, "device")
    448         return self.serial in devices
    449 
    450     @property
    451     def build_info(self):
    452         """Get the build info of this Android device, including build id and
    453         build type.
    454 
    455         This is not available if the device is in bootloader mode.
    456 
    457         Returns:
    458             A dict with the build info of this Android device, or None if the
    459             device is in bootloader mode.
    460         """
    461         if self.is_bootloader:
    462             self.log.error("Device is in fastboot mode, could not get build "
    463                            "info.")
    464             return
    465 
    466         build_id = self.adb.getprop("ro.build.id")
    467         valid_build_id = False
    468         for regex in RELEASE_ID_REGEXES:
    469             if re.match(regex, build_id):
    470                 valid_build_id = True
    471                 break
    472         if not valid_build_id:
    473             build_id = self.adb.getprop("ro.build.version.incremental")
    474 
    475         info = {
    476             "build_id": build_id,
    477             "build_type": self.adb.getprop("ro.build.type")
    478         }
    479         return info
    480 
    481     @property
    482     def is_bootloader(self):
    483         """True if the device is in bootloader mode.
    484         """
    485         return self.serial in list_fastboot_devices()
    486 
    487     @property
    488     def is_adb_root(self):
    489         """True if adb is running as root for this device.
    490         """
    491         try:
    492             return "0" == self.adb.shell("id -u")
    493         except adb.AdbError:
    494             # Wait a bit and retry to work around adb flakiness for this cmd.
    495             time.sleep(0.2)
    496             return "0" == self.adb.shell("id -u")
    497 
    498     @property
    499     def model(self):
    500         """The Android code name for the device."""
    501         # If device is in bootloader mode, get mode name from fastboot.
    502         if self.is_bootloader:
    503             out = self.fastboot.getvar("product").strip()
    504             # "out" is never empty because of the "total time" message fastboot
    505             # writes to stderr.
    506             lines = out.split('\n', 1)
    507             if lines:
    508                 tokens = lines[0].split(' ')
    509                 if len(tokens) > 1:
    510                     return tokens[1].lower()
    511             return None
    512         model = self.adb.getprop("ro.build.product").lower()
    513         if model == "sprout":
    514             return model
    515         else:
    516             return self.adb.getprop("ro.product.name").lower()
    517 
    518     @property
    519     def droid(self):
    520         """Returns the RPC Service of the first Sl4aSession created."""
    521         if len(self._sl4a_manager.sessions) > 0:
    522             session_id = sorted(self._sl4a_manager.sessions.keys())[0]
    523             return self._sl4a_manager.sessions[session_id].rpc_client
    524         else:
    525             return None
    526 
    527     @property
    528     def ed(self):
    529         """Returns the event dispatcher of the first Sl4aSession created."""
    530         if len(self._sl4a_manager.sessions) > 0:
    531             session_id = sorted(self._sl4a_manager.sessions.keys())[0]
    532             return self._sl4a_manager.sessions[
    533                 session_id].get_event_dispatcher()
    534         else:
    535             return None
    536 
    537     @property
    538     def sl4a_sessions(self):
    539         """Returns a dictionary of session ids to sessions."""
    540         return list(self._sl4a_manager.sessions)
    541 
    542     @property
    543     def is_adb_logcat_on(self):
    544         """Whether there is an ongoing adb logcat collection.
    545         """
    546         if self.adb_logcat_process:
    547             try:
    548                 utils._assert_subprocess_running(self.adb_logcat_process)
    549                 return True
    550             except Exception:
    551                 # if skip_sl4a is true, there is no sl4a session
    552                 # if logcat died due to device reboot and sl4a session has
    553                 # not restarted there is no droid.
    554                 if self.droid:
    555                     self.droid.logI('Logcat died')
    556                 self.log.info("Logcat to %s died", self.adb_logcat_file_path)
    557                 return False
    558         return False
    559 
    560     def load_config(self, config):
    561         """Add attributes to the AndroidDevice object based on json config.
    562 
    563         Args:
    564             config: A dictionary representing the configs.
    565 
    566         Raises:
    567             AndroidDeviceError is raised if the config is trying to overwrite
    568             an existing attribute.
    569         """
    570         for k, v in config.items():
    571             # skip_sl4a value can be reset from config file
    572             if hasattr(self, k) and k != "skip_sl4a":
    573                 raise AndroidDeviceError(
    574                     "Attempting to set existing attribute %s on %s" %
    575                     (k, self.serial))
    576             setattr(self, k, v)
    577 
    578     def root_adb(self):
    579         """Change adb to root mode for this device if allowed.
    580 
    581         If executed on a production build, adb will not be switched to root
    582         mode per security restrictions.
    583         """
    584         self.adb.root()
    585         self.adb.wait_for_device()
    586 
    587     def get_droid(self, handle_event=True):
    588         """Create an sl4a connection to the device.
    589 
    590         Return the connection handler 'droid'. By default, another connection
    591         on the same session is made for EventDispatcher, and the dispatcher is
    592         returned to the caller as well.
    593         If sl4a server is not started on the device, try to start it.
    594 
    595         Args:
    596             handle_event: True if this droid session will need to handle
    597                 events.
    598 
    599         Returns:
    600             droid: Android object used to communicate with sl4a on the android
    601                 device.
    602             ed: An optional EventDispatcher to organize events for this droid.
    603 
    604         Examples:
    605             Don't need event handling:
    606             >>> ad = AndroidDevice()
    607             >>> droid = ad.get_droid(False)
    608 
    609             Need event handling:
    610             >>> ad = AndroidDevice()
    611             >>> droid, ed = ad.get_droid()
    612         """
    613         session = self._sl4a_manager.create_session()
    614         droid = session.rpc_client
    615         if handle_event:
    616             ed = session.get_event_dispatcher()
    617             return droid, ed
    618         return droid
    619 
    620     def get_package_pid(self, package_name):
    621         """Gets the pid for a given package. Returns None if not running.
    622         Args:
    623             package_name: The name of the package.
    624         Returns:
    625             The first pid found under a given package name. None if no process
    626             was found running the package.
    627         Raises:
    628             AndroidDeviceError if the output of the phone's process list was
    629             in an unexpected format.
    630         """
    631         for cmd in ("ps -A", "ps"):
    632             try:
    633                 out = self.adb.shell(
    634                     '%s | grep "S %s"' % (cmd, package_name),
    635                     ignore_status=True)
    636                 if package_name not in out:
    637                     continue
    638                 try:
    639                     pid = int(out.split()[1])
    640                     self.log.info('apk %s has pid %s.', package_name, pid)
    641                     return pid
    642                 except (IndexError, ValueError) as e:
    643                     # Possible ValueError from string to int cast.
    644                     # Possible IndexError from split.
    645                     self.log.warn('Command \"%s\" returned output line: '
    646                                   '\"%s\".\nError: %s', cmd, out, e)
    647             except Exception as e:
    648                 self.log.warn(
    649                     'Device fails to check if %s running with \"%s\"\n'
    650                     'Exception %s', package_name, cmd, e)
    651         self.log.debug("apk %s is not running", package_name)
    652         return None
    653 
    654     def get_dispatcher(self, droid):
    655         """Return an EventDispatcher for an sl4a session
    656 
    657         Args:
    658             droid: Session to create EventDispatcher for.
    659 
    660         Returns:
    661             ed: An EventDispatcher for specified session.
    662         """
    663         return self._sl4a_manager.sessions[droid.uid].get_event_dispatcher()
    664 
    665     def _is_timestamp_in_range(self, target, log_begin_time, log_end_time):
    666         low = acts_logger.logline_timestamp_comparator(log_begin_time,
    667                                                        target) <= 0
    668         high = acts_logger.logline_timestamp_comparator(log_end_time,
    669                                                         target) >= 0
    670         return low and high
    671 
    672     def cat_adb_log(self, tag, begin_time):
    673         """Takes an excerpt of the adb logcat log from a certain time point to
    674         current time.
    675 
    676         Args:
    677             tag: An identifier of the time period, usualy the name of a test.
    678             begin_time: Epoch time of the beginning of the time period.
    679         """
    680         log_begin_time = acts_logger.epoch_to_log_line_timestamp(begin_time)
    681         if not self.adb_logcat_file_path:
    682             raise AndroidDeviceError(
    683                 ("Attempting to cat adb log when none has"
    684                  " been collected on Android device %s.") % self.serial)
    685         log_end_time = acts_logger.get_log_line_timestamp()
    686         self.log.debug("Extracting adb log from logcat.")
    687         adb_excerpt_path = os.path.join(self.log_path, "AdbLogExcerpts")
    688         utils.create_dir(adb_excerpt_path)
    689         f_name = os.path.basename(self.adb_logcat_file_path)
    690         out_name = f_name.replace("adblog,", "").replace(".txt", "")
    691         out_name = ",{},{}.txt".format(log_begin_time, out_name)
    692         tag_len = utils.MAX_FILENAME_LEN - len(out_name)
    693         tag = tag[:tag_len]
    694         out_name = tag + out_name
    695         full_adblog_path = os.path.join(adb_excerpt_path, out_name)
    696         with open(full_adblog_path, 'w', encoding='utf-8') as out:
    697             in_file = self.adb_logcat_file_path
    698             with open(in_file, 'r', encoding='utf-8', errors='replace') as f:
    699                 in_range = False
    700                 while True:
    701                     line = None
    702                     try:
    703                         line = f.readline()
    704                         if not line:
    705                             break
    706                     except:
    707                         continue
    708                     line_time = line[:acts_logger.log_line_timestamp_len]
    709                     if not acts_logger.is_valid_logline_timestamp(line_time):
    710                         continue
    711                     if self._is_timestamp_in_range(line_time, log_begin_time,
    712                                                    log_end_time):
    713                         in_range = True
    714                         if not line.endswith('\n'):
    715                             line += '\n'
    716                         out.write(line)
    717                     else:
    718                         if in_range:
    719                             break
    720 
    721     def start_adb_logcat(self, cont_logcat_file=False):
    722         """Starts a standing adb logcat collection in separate subprocesses and
    723         save the logcat in a file.
    724 
    725         Args:
    726             cont_logcat_file: Specifies whether to continue the previous logcat
    727                               file.  This allows for start_adb_logcat to act
    728                               as a restart logcat function if it is noticed
    729                               logcat is no longer running.
    730         """
    731         if self.is_adb_logcat_on:
    732             raise AndroidDeviceError(("Android device {} already has an adb "
    733                                       "logcat thread going on. Cannot start "
    734                                       "another one.").format(self.serial))
    735         # Disable adb log spam filter. Have to stop and clear settings first
    736         # because 'start' doesn't support --clear option before Android N.
    737         self.adb.shell("logpersist.stop --clear")
    738         self.adb.shell("logpersist.start")
    739         if cont_logcat_file:
    740             if self.droid:
    741                 self.droid.logI('Restarting logcat')
    742             self.log.info(
    743                 'Restarting logcat on file %s' % self.adb_logcat_file_path)
    744             logcat_file_path = self.adb_logcat_file_path
    745         else:
    746             f_name = "adblog,{},{}.txt".format(self.model, self.serial)
    747             utils.create_dir(self.log_path)
    748             logcat_file_path = os.path.join(self.log_path, f_name)
    749         if hasattr(self, 'adb_logcat_param'):
    750             extra_params = self.adb_logcat_param
    751         else:
    752             extra_params = "-b all"
    753         if self.last_logcat_timestamp:
    754             begin_at = '-T "%s"' % self.last_logcat_timestamp
    755         else:
    756             begin_at = '-T 1'
    757         # TODO(markdr): Pull 'adb -s %SERIAL' from the AdbProxy object.
    758         cmd = "adb -s {} logcat {} -v year {} >> {}".format(
    759             self.serial, begin_at, extra_params, logcat_file_path)
    760         self.adb_logcat_process = utils.start_standing_subprocess(cmd)
    761         self.adb_logcat_file_path = logcat_file_path
    762 
    763     def stop_adb_logcat(self):
    764         """Stops the adb logcat collection subprocess.
    765         """
    766         if not self.is_adb_logcat_on:
    767             raise AndroidDeviceError(
    768                 "Android device %s does not have an ongoing adb logcat collection."
    769                 % self.serial)
    770         # Set the last timestamp to the current timestamp. This may cause
    771         # a race condition that allows the same line to be logged twice,
    772         # but it does not pose a problem for our logging purposes.
    773         logcat_output = self.adb.logcat('-t 1 -v year')
    774         next_line = logcat_output.find('\n')
    775         self.last_logcat_timestamp = logcat_output[next_line + 1:
    776                                                    next_line + 24]
    777         utils.stop_standing_subprocess(self.adb_logcat_process)
    778         self.adb_logcat_process = None
    779 
    780     def get_apk_uid(self, apk_name):
    781         """Get the uid of the given apk.
    782 
    783         Args:
    784         apk_name: Name of the package, e.g., com.android.phone.
    785 
    786         Returns:
    787         Linux UID for the apk.
    788         """
    789         output = self.adb.shell(
    790             "dumpsys package %s | grep userId=" % apk_name, ignore_status=True)
    791         result = re.search(r"userId=(\d+)", output)
    792         if result:
    793             return result.group(1)
    794         else:
    795             None
    796 
    797     def is_apk_installed(self, package_name):
    798         """Check if the given apk is already installed.
    799 
    800         Args:
    801         package_name: Name of the package, e.g., com.android.phone.
    802 
    803         Returns:
    804         True if package is installed. False otherwise.
    805         """
    806 
    807         try:
    808             return bool(
    809                 self.adb.shell(
    810                     'pm list packages | grep -w "package:%s"' % package_name))
    811 
    812         except Exception as err:
    813             self.log.error('Could not determine if %s is installed. '
    814                            'Received error:\n%s', package_name, err)
    815             return False
    816 
    817     def is_sl4a_installed(self):
    818         return self.is_apk_installed(SL4A_APK_NAME)
    819 
    820     def is_apk_running(self, package_name):
    821         """Check if the given apk is running.
    822 
    823         Args:
    824             package_name: Name of the package, e.g., com.android.phone.
    825 
    826         Returns:
    827         True if package is installed. False otherwise.
    828         """
    829         for cmd in ("ps -A", "ps"):
    830             try:
    831                 out = self.adb.shell(
    832                     '%s | grep "S %s"' % (cmd, package_name),
    833                     ignore_status=True)
    834                 if package_name in out:
    835                     self.log.info("apk %s is running", package_name)
    836                     return True
    837             except Exception as e:
    838                 self.log.warn("Device fails to check is %s running by %s "
    839                               "Exception %s", package_name, cmd, e)
    840                 continue
    841         self.log.debug("apk %s is not running", package_name)
    842         return False
    843 
    844     def is_sl4a_running(self):
    845         return self.is_apk_running(SL4A_APK_NAME)
    846 
    847     def force_stop_apk(self, package_name):
    848         """Force stop the given apk.
    849 
    850         Args:
    851         package_name: Name of the package, e.g., com.android.phone.
    852 
    853         Returns:
    854         True if package is installed. False otherwise.
    855         """
    856         try:
    857             self.adb.shell(
    858                 'am force-stop %s' % package_name, ignore_status=True)
    859         except Exception as e:
    860             self.log.warn("Fail to stop package %s: %s", package_name, e)
    861 
    862     def stop_sl4a(self):
    863         return self.force_stop_apk(SL4A_APK_NAME)
    864 
    865     def start_sl4a(self):
    866         self._sl4a_manager.start_sl4a_service()
    867 
    868     def take_bug_report(self, test_name, begin_time):
    869         """Takes a bug report on the device and stores it in a file.
    870 
    871         Args:
    872             test_name: Name of the test case that triggered this bug report.
    873             begin_time: Epoch time when the test started.
    874         """
    875         self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
    876         new_br = True
    877         try:
    878             stdout = self.adb.shell("bugreportz -v")
    879             # This check is necessary for builds before N, where adb shell's ret
    880             # code and stderr are not propagated properly.
    881             if "not found" in stdout:
    882                 new_br = False
    883         except adb.AdbError:
    884             new_br = False
    885         br_path = os.path.join(self.log_path, test_name)
    886         utils.create_dir(br_path)
    887         time_stamp = acts_logger.normalize_log_line_timestamp(
    888             acts_logger.epoch_to_log_line_timestamp(begin_time))
    889         out_name = "AndroidDevice%s_%s" % (
    890             self.serial, time_stamp.replace(" ", "_").replace(":", "-"))
    891         out_name = "%s.zip" % out_name if new_br else "%s.txt" % out_name
    892         full_out_path = os.path.join(br_path, out_name)
    893         # in case device restarted, wait for adb interface to return
    894         self.wait_for_boot_completion()
    895         self.log.info("Taking bugreport for %s.", test_name)
    896         if new_br:
    897             out = self.adb.shell("bugreportz", timeout=BUG_REPORT_TIMEOUT)
    898             if not out.startswith("OK"):
    899                 raise AndroidDeviceError("Failed to take bugreport on %s: %s" %
    900                                          (self.serial, out))
    901             br_out_path = out.split(':')[1].strip()
    902             self.adb.pull("%s %s" % (br_out_path, full_out_path))
    903         else:
    904             self.adb.bugreport(
    905                 " > {}".format(full_out_path), timeout=BUG_REPORT_TIMEOUT)
    906         self.log.info("Bugreport for %s taken at %s.", test_name,
    907                       full_out_path)
    908         self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
    909 
    910     def get_file_names(self,
    911                        directory,
    912                        begin_time=None,
    913                        skip_files=[],
    914                        match_string=None):
    915         """Get files names with provided directory."""
    916         cmd = "find %s -type f" % directory
    917         if begin_time:
    918             current_time = utils.get_current_epoch_time()
    919             seconds = int(math.ceil((current_time - begin_time) / 1000.0))
    920             cmd = "%s -mtime -%ss" % (cmd, seconds)
    921         if match_string:
    922             cmd = "%s -iname %s" % (cmd, match_string)
    923         for skip_file in skip_files:
    924             cmd = "%s ! -iname %s" % (cmd, skip_file)
    925         out = self.adb.shell(cmd, ignore_status=True)
    926         if not out or "No such" in out or "Permission denied" in out:
    927             return []
    928         files = out.split("\n")
    929         self.log.debug("Find files in directory %s: %s", directory, files)
    930         return files
    931 
    932     def pull_files(self, files, remote_path=None):
    933         """Pull files from devies."""
    934         if not remote_path:
    935             remote_path = self.log_path
    936         for file_name in files:
    937             self.adb.pull(
    938                 "%s %s" % (file_name, remote_path), timeout=PULL_TIMEOUT)
    939 
    940     def check_crash_report(self,
    941                            test_name=None,
    942                            begin_time=None,
    943                            log_crash_report=False):
    944         """check crash report on the device."""
    945         crash_reports = []
    946         for crash_path in CRASH_REPORT_PATHS:
    947             crashes = self.get_file_names(
    948                 crash_path,
    949                 skip_files=CRASH_REPORT_SKIPS,
    950                 begin_time=begin_time)
    951             if crash_path == "/data/tombstones/" and crashes:
    952                 tombstones = crashes[:]
    953                 for tombstone in tombstones:
    954                     if self.adb.shell(
    955                             'cat %s | grep "crash_dump failed to dump process"'
    956                             % tombstone):
    957                         crashes.remove(tombstone)
    958             if crashes:
    959                 crash_reports.extend(crashes)
    960         if crash_reports and log_crash_report:
    961             test_name = test_name or time.strftime("%Y-%m-%d-%Y-%H-%M-%S")
    962             crash_log_path = os.path.join(self.log_path, test_name,
    963                                           "Crashes_%s" % self.serial)
    964             utils.create_dir(crash_log_path)
    965             self.pull_files(crash_reports, crash_log_path)
    966         return crash_reports
    967 
    968     def get_qxdm_logs(self, test_name="", begin_time=None):
    969         """Get qxdm logs."""
    970         # Sleep 10 seconds for the buffered log to be written in qxdm log file
    971         time.sleep(10)
    972         log_path = getattr(self, "qxdm_log_path", DEFAULT_QXDM_LOG_PATH)
    973         qxdm_logs = self.get_file_names(
    974             log_path, begin_time=begin_time, match_string="*.qmdl")
    975         if qxdm_logs:
    976             qxdm_log_path = os.path.join(self.log_path, test_name,
    977                                          "QXDM_%s" % self.serial)
    978             utils.create_dir(qxdm_log_path)
    979             self.log.info("Pull QXDM Log %s to %s", qxdm_logs, qxdm_log_path)
    980             self.pull_files(qxdm_logs, qxdm_log_path)
    981         else:
    982             self.log.error("Didn't find QXDM logs in %s." % log_path)
    983         if "Verizon" in self.adb.getprop("gsm.sim.operator.alpha"):
    984             omadm_log_path = os.path.join(self.log_path, test_name,
    985                                           "OMADM_%s" % self.serial)
    986             utils.create_dir(omadm_log_path)
    987             self.log.info("Pull OMADM Log")
    988             self.adb.pull(
    989                 "/data/data/com.android.omadm.service/files/dm/log/ %s" %
    990                 omadm_log_path,
    991                 timeout=PULL_TIMEOUT,
    992                 ignore_status=True)
    993 
    994     def start_new_session(self, max_connections=None, server_port=None):
    995         """Start a new session in sl4a.
    996 
    997         Also caches the droid in a dict with its uid being the key.
    998 
    999         Returns:
   1000             An Android object used to communicate with sl4a on the android
   1001                 device.
   1002 
   1003         Raises:
   1004             Sl4aException: Something is wrong with sl4a and it returned an
   1005             existing uid to a new session.
   1006         """
   1007         session = self._sl4a_manager.create_session(
   1008             max_connections=max_connections, server_port=server_port)
   1009 
   1010         self._sl4a_manager.sessions[session.uid] = session
   1011         return session.rpc_client
   1012 
   1013     def terminate_all_sessions(self):
   1014         """Terminate all sl4a sessions on the AndroidDevice instance.
   1015 
   1016         Terminate all sessions and clear caches.
   1017         """
   1018         self._sl4a_manager.terminate_all_sessions()
   1019 
   1020     def run_iperf_client_nb(self,
   1021                             server_host,
   1022                             extra_args="",
   1023                             timeout=IPERF_TIMEOUT,
   1024                             log_file_path=None):
   1025         """Start iperf client on the device asynchronously.
   1026 
   1027         Return status as true if iperf client start successfully.
   1028         And data flow information as results.
   1029 
   1030         Args:
   1031             server_host: Address of the iperf server.
   1032             extra_args: A string representing extra arguments for iperf client,
   1033                 e.g. "-i 1 -t 30".
   1034             log_file_path: The complete file path to log the results.
   1035 
   1036         """
   1037         cmd = "iperf3 -c {} {}".format(server_host, extra_args)
   1038         if log_file_path:
   1039             cmd += " --logfile {} &".format(log_file_path)
   1040         self.adb.shell_nb(cmd)
   1041 
   1042     def run_iperf_client(self,
   1043                          server_host,
   1044                          extra_args="",
   1045                          timeout=IPERF_TIMEOUT):
   1046         """Start iperf client on the device.
   1047 
   1048         Return status as true if iperf client start successfully.
   1049         And data flow information as results.
   1050 
   1051         Args:
   1052             server_host: Address of the iperf server.
   1053             extra_args: A string representing extra arguments for iperf client,
   1054                 e.g. "-i 1 -t 30".
   1055 
   1056         Returns:
   1057             status: true if iperf client start successfully.
   1058             results: results have data flow information
   1059         """
   1060         out = self.adb.shell(
   1061             "iperf3 -c {} {}".format(server_host, extra_args), timeout=timeout)
   1062         clean_out = out.split('\n')
   1063         if "error" in clean_out[0].lower():
   1064             return False, clean_out
   1065         return True, clean_out
   1066 
   1067     def run_iperf_server(self, extra_args=""):
   1068         """Start iperf server on the device
   1069 
   1070         Return status as true if iperf server started successfully.
   1071 
   1072         Args:
   1073             extra_args: A string representing extra arguments for iperf server.
   1074 
   1075         Returns:
   1076             status: true if iperf server started successfully.
   1077             results: results have output of command
   1078         """
   1079         out = self.adb.shell("iperf3 -s {}".format(extra_args))
   1080         clean_out = out.split('\n')
   1081         if "error" in clean_out[0].lower():
   1082             return False, clean_out
   1083         return True, clean_out
   1084 
   1085     def wait_for_boot_completion(self):
   1086         """Waits for Android framework to broadcast ACTION_BOOT_COMPLETED.
   1087 
   1088         This function times out after 15 minutes.
   1089         """
   1090         timeout_start = time.time()
   1091         timeout = 15 * 60
   1092 
   1093         self.adb.wait_for_device(timeout=WAIT_FOR_DEVICE_TIMEOUT)
   1094         while time.time() < timeout_start + timeout:
   1095             try:
   1096                 completed = self.adb.getprop("sys.boot_completed")
   1097                 if completed == '1':
   1098                     return
   1099             except adb.AdbError:
   1100                 # adb shell calls may fail during certain period of booting
   1101                 # process, which is normal. Ignoring these errors.
   1102                 pass
   1103             time.sleep(5)
   1104         raise AndroidDeviceError(
   1105             "Device %s booting process timed out." % self.serial)
   1106 
   1107     def reboot(self, stop_at_lock_screen=False):
   1108         """Reboots the device.
   1109 
   1110         Terminate all sl4a sessions, reboot the device, wait for device to
   1111         complete booting, and restart an sl4a session if restart_sl4a is True.
   1112 
   1113         Args:
   1114             stop_at_lock_screen: whether to unlock after reboot. Set to False
   1115                 if want to bring the device to reboot up to password locking
   1116                 phase. Sl4a checking need the device unlocked after rebooting.
   1117 
   1118         Returns:
   1119             None, sl4a session and event_dispatcher.
   1120         """
   1121         if self.is_bootloader:
   1122             self.fastboot.reboot()
   1123             return
   1124         self.terminate_all_sessions()
   1125         self.log.info("Rebooting")
   1126         self.adb.reboot()
   1127         self.wait_for_boot_completion()
   1128         self.root_adb()
   1129         if stop_at_lock_screen:
   1130             return
   1131         if not self.ensure_screen_on():
   1132             self.log.error("User window cannot come up")
   1133             raise AndroidDeviceError("User window cannot come up")
   1134         self.start_services(self.skip_sl4a)
   1135 
   1136     def restart_runtime(self):
   1137         """Restarts android runtime.
   1138 
   1139         Terminate all sl4a sessions, restarts runtime, wait for framework
   1140         complete restart, and restart an sl4a session if restart_sl4a is True.
   1141         """
   1142         self.stop_services()
   1143         self.log.info("Restarting android runtime")
   1144         self.adb.shell("stop")
   1145         self.adb.shell("start")
   1146         self.wait_for_boot_completion()
   1147         self.root_adb()
   1148         if not self.ensure_screen_on():
   1149             self.log.error("User window cannot come up")
   1150             raise AndroidDeviceError("User window cannot come up")
   1151         self.start_services(self.skip_sl4a)
   1152 
   1153     def search_logcat(self, matching_string, begin_time=None):
   1154         """Search logcat message with given string.
   1155 
   1156         Args:
   1157             matching_string: matching_string to search.
   1158 
   1159         Returns:
   1160             A list of dictionaries with full log message, time stamp string
   1161             and time object. For example:
   1162             [{"log_message": "05-03 17:39:29.898   968  1001 D"
   1163                               "ActivityManager: Sending BOOT_COMPLETE user #0",
   1164               "time_stamp": "2017-05-03 17:39:29.898",
   1165               "datetime_obj": datetime object}]
   1166         """
   1167         cmd_option = '-b all -v year -d'
   1168         if begin_time:
   1169             log_begin_time = acts_logger.epoch_to_log_line_timestamp(
   1170                 begin_time)
   1171             cmd_option = '%s -t "%s"' % (cmd_option, log_begin_time)
   1172         out = self.adb.logcat(
   1173             '%s | grep "%s"' % (cmd_option, matching_string),
   1174             ignore_status=True)
   1175         if not out: return []
   1176         result = []
   1177         logs = re.findall(r'(\S+\s\S+)(.*%s.*)' % re.escape(matching_string),
   1178                           out)
   1179         for log in logs:
   1180             time_stamp = log[0]
   1181             time_obj = datetime.strptime(time_stamp, "%Y-%m-%d %H:%M:%S.%f")
   1182             result.append({
   1183                 "log_message": "".join(log),
   1184                 "time_stamp": time_stamp,
   1185                 "datetime_obj": time_obj
   1186             })
   1187         return result
   1188 
   1189     def get_ipv4_address(self, interface='wlan0', timeout=5):
   1190         for timer in range(0, timeout):
   1191             try:
   1192                 ip_string = self.adb.shell('ifconfig %s|grep inet' % interface)
   1193                 break
   1194             except adb.AdbError as e:
   1195                 if timer + 1 == timeout:
   1196                     self.log.warning(
   1197                         'Unable to find IP address for %s.' % interface)
   1198                     return None
   1199                 else:
   1200                     time.sleep(1)
   1201         result = re.search('addr:(.*) Bcast', ip_string)
   1202         if result != None:
   1203             ip_address = result.group(1)
   1204             try:
   1205                 socket.inet_aton(ip_address)
   1206                 return ip_address
   1207             except socket.error:
   1208                 return None
   1209         else:
   1210             return None
   1211 
   1212     def get_ipv4_gateway(self, timeout=5):
   1213         for timer in range(0, timeout):
   1214             try:
   1215                 gateway_string = self.adb.shell(
   1216                     'dumpsys wifi | grep mDhcpResults')
   1217                 break
   1218             except adb.AdbError as e:
   1219                 if timer + 1 == timeout:
   1220                     self.log.warning('Unable to find gateway')
   1221                     return None
   1222                 else:
   1223                     time.sleep(1)
   1224         result = re.search('Gateway (.*) DNS servers', gateway_string)
   1225         if result != None:
   1226             ipv4_gateway = result.group(1)
   1227             try:
   1228                 socket.inet_aton(ipv4_gateway)
   1229                 return ipv4_gateway
   1230             except socket.error:
   1231                 return None
   1232         else:
   1233             return None
   1234 
   1235     def send_keycode(self, keycode):
   1236         self.adb.shell("input keyevent KEYCODE_%s" % keycode)
   1237 
   1238     def get_my_current_focus_window(self):
   1239         """Get the current focus window on screen"""
   1240         output = self.adb.shell(
   1241             'dumpsys window windows | grep -E mCurrentFocus',
   1242             ignore_status=True)
   1243         if not output or "not found" in output or "Can't find" in output or (
   1244                 "mCurrentFocus=null" in output):
   1245             result = ''
   1246         else:
   1247             result = output.split(' ')[-1].strip("}")
   1248         self.log.debug("Current focus window is %s", result)
   1249         return result
   1250 
   1251     def get_my_current_focus_app(self):
   1252         """Get the current focus application"""
   1253         output = self.adb.shell(
   1254             'dumpsys window windows | grep -E mFocusedApp', ignore_status=True)
   1255         if not output or "not found" in output or "Can't find" in output or (
   1256                 "mFocusedApp=null" in output):
   1257             result = ''
   1258         else:
   1259             result = output.split(' ')[-2]
   1260         self.log.debug("Current focus app is %s", result)
   1261         return result
   1262 
   1263     def is_window_ready(self, window_name=None):
   1264         current_window = self.get_my_current_focus_window()
   1265         if window_name:
   1266             return window_name in current_window
   1267         return current_window and ENCRYPTION_WINDOW not in current_window
   1268 
   1269     def wait_for_window_ready(self,
   1270                               window_name=None,
   1271                               check_interval=5,
   1272                               check_duration=60):
   1273         elapsed_time = 0
   1274         while elapsed_time < check_duration:
   1275             if self.is_window_ready(window_name=window_name):
   1276                 return True
   1277             time.sleep(check_interval)
   1278             elapsed_time += check_interval
   1279         self.log.info("Current focus window is %s",
   1280                       self.get_my_current_focus_window())
   1281         return False
   1282 
   1283     def is_user_setup_complete(self):
   1284         return "1" in self.adb.shell("settings get secure user_setup_complete")
   1285 
   1286     def is_screen_awake(self):
   1287         """Check if device screen is in sleep mode"""
   1288         return "Awake" in self.adb.shell("dumpsys power | grep mWakefulness=")
   1289 
   1290     def is_screen_emergency_dialer(self):
   1291         """Check if device screen is in emergency dialer mode"""
   1292         return "EmergencyDialer" in self.get_my_current_focus_window()
   1293 
   1294     def is_screen_in_call_activity(self):
   1295         """Check if device screen is in in-call activity notification"""
   1296         return "InCallActivity" in self.get_my_current_focus_window()
   1297 
   1298     def is_setupwizard_on(self):
   1299         """Check if device screen is in emergency dialer mode"""
   1300         return "setupwizard" in self.get_my_current_focus_app()
   1301 
   1302     def is_screen_lock_enabled(self):
   1303         """Check if screen lock is enabled"""
   1304         cmd = ("sqlite3 /data/system/locksettings.db .dump"" | grep lockscreen.password_type | grep -v alternate")
   1305         out = self.adb.shell(cmd, ignore_status=True)
   1306         if "unable to open" in out:
   1307             self.root_adb()
   1308             out = self.adb.shell(cmd, ignore_status=True)
   1309         if ",0,'0'" not in out and out != "":
   1310             self.log.info("Screen lock is enabled")
   1311             return True
   1312         return False
   1313 
   1314     def is_waiting_for_unlock_pin(self):
   1315         """Check if device is waiting for unlock pin to boot up"""
   1316         current_window = self.get_my_current_focus_window()
   1317         current_app = self.get_my_current_focus_app()
   1318         if ENCRYPTION_WINDOW in current_window:
   1319             self.log.info("Device is in CrpytKeeper window")
   1320             return True
   1321         if "StatusBar" in current_window and (
   1322                 (not current_app) or "FallbackHome" in current_app):
   1323             self.log.info("Device is locked")
   1324             return True
   1325         return False
   1326 
   1327     def ensure_screen_on(self):
   1328         """Ensure device screen is powered on"""
   1329         if self.is_screen_lock_enabled():
   1330             for _ in range(2):
   1331                 self.unlock_screen()
   1332                 time.sleep(1)
   1333                 if self.is_waiting_for_unlock_pin():
   1334                     self.unlock_screen(password=DEFAULT_DEVICE_PASSWORD)
   1335                     time.sleep(1)
   1336                 if not self.is_waiting_for_unlock_pin(
   1337                 ) and self.wait_for_window_ready():
   1338                     return True
   1339             return False
   1340         else:
   1341             self.wakeup_screen()
   1342             return True
   1343 
   1344     def wakeup_screen(self):
   1345         if not self.is_screen_awake():
   1346             self.log.info("Screen is not awake, wake it up")
   1347             self.send_keycode("WAKEUP")
   1348 
   1349     def go_to_sleep(self):
   1350         if self.is_screen_awake():
   1351             self.send_keycode("SLEEP")
   1352 
   1353     def send_keycode_number_pad(self, number):
   1354         self.send_keycode("NUMPAD_%s" % number)
   1355 
   1356     def unlock_screen(self, password=None):
   1357         self.log.info("Unlocking with %s", password or "swipe up")
   1358         # Bring device to SLEEP so that unlock process can start fresh
   1359         self.send_keycode("SLEEP")
   1360         time.sleep(1)
   1361         self.send_keycode("WAKEUP")
   1362         if ENCRYPTION_WINDOW not in self.get_my_current_focus_app():
   1363             self.send_keycode("MENU")
   1364         if password:
   1365             self.send_keycode("DEL")
   1366             for number in password:
   1367                 self.send_keycode_number_pad(number)
   1368             self.send_keycode("ENTER")
   1369             self.send_keycode("BACK")
   1370 
   1371     def exit_setup_wizard(self):
   1372         if not self.is_user_setup_complete() or self.is_setupwizard_on():
   1373             self.adb.shell("pm disable %s" % self.get_setupwizard_package_name())
   1374         # Wait up to 5 seconds for user_setup_complete to be updated
   1375         for _ in range(5):
   1376             if self.is_user_setup_complete() or not self.is_setupwizard_on():
   1377                 return
   1378             time.sleep(1)
   1379 
   1380         # If fail to exit setup wizard, set local.prop and reboot
   1381         if not self.is_user_setup_complete() and self.is_setupwizard_on():
   1382             self.adb.shell("echo ro.test_harness=1 > /data/local.prop")
   1383             self.adb.shell("chmod 644 /data/local.prop")
   1384             self.reboot(stop_at_lock_screen=True)
   1385 
   1386     def get_setupwizard_package_name(self):
   1387         """Finds setupwizard package/.activity
   1388 
   1389          Returns:
   1390             packageName/.ActivityName
   1391          """
   1392         package = self.adb.shell("pm list packages -f | grep setupwizard | grep com.google.android")
   1393         wizard_package = re.split("=", package)[1]
   1394         activity = re.search("wizard/(.*?).apk", package, re.IGNORECASE).groups()[0]
   1395         self.log.info("%s/.%sActivity" % (wizard_package, activity))
   1396         return "%s/.%sActivity" % (wizard_package, activity)
   1397 
   1398 
   1399 class AndroidDeviceLoggerAdapter(logging.LoggerAdapter):
   1400     def process(self, msg, kwargs):
   1401         msg = "[AndroidDevice|%s] %s" % (self.extra["serial"], msg)
   1402         return (msg, kwargs)
   1403