Home | History | Annotate | Download | only in cros
      1 # Copyright 2016 The Chromium OS Authors. All rights reserved.
      2 # Use of this source code is governed by a BSD-style license that can be
      3 # found in the LICENSE file.
      4 #
      5 # This file contains things that are shared by arc.py and arc_util.py.
      6 
      7 import logging
      8 import subprocess
      9 import time
     10 
     11 from autotest_lib.client.bin import utils
     12 from autotest_lib.client.common_lib import error
     13 
     14 
     15 # Ask Chrome to start ARC instance and the script will block until ARC's boot
     16 # completed event.
     17 ARC_MODE_ENABLED = "enabled"
     18 # Similar to "enabled", except that it will not block.
     19 ARC_MODE_ENABLED_ASYNC = "enabled_async"
     20 # Ask Chrome to not start ARC instance.  This is the default.
     21 ARC_MODE_DISABLED = "disabled"
     22 # All available ARC options.
     23 ARC_MODES = [ARC_MODE_ENABLED, ARC_MODE_ENABLED_ASYNC, ARC_MODE_DISABLED]
     24 
     25 _BOOT_CHECK_INTERVAL_SECONDS = 2
     26 _WAIT_FOR_ANDROID_BOOT_SECONDS = 120
     27 
     28 _VAR_LOGCAT_PATH = '/var/log/logcat'
     29 _VAR_LOGCAT_BOOT_PATH = '/var/log/logcat-boot'
     30 
     31 
     32 class Logcat(object):
     33     """Saves the output of logcat to a file."""
     34 
     35     def __init__(self, path=_VAR_LOGCAT_PATH):
     36         with open(path, 'w') as f:
     37             self._proc = subprocess.Popen(
     38                 ['android-sh', '-c', 'logcat'],
     39                 stdout=f,
     40                 stderr=subprocess.STDOUT,
     41                 close_fds=True)
     42 
     43     def __enter__(self):
     44         """Support for context manager."""
     45         return self
     46 
     47     def __exit__(self, *args):
     48         """Support for context manager.
     49 
     50         Calls close().
     51         """
     52         self.close()
     53 
     54     def close(self):
     55         """Stop the logcat process gracefully."""
     56         if not self._proc:
     57             return
     58         self._proc.terminate()
     59 
     60         class TimeoutException(Exception):
     61             """Termination timeout timed out."""
     62 
     63         try:
     64             utils.poll_for_condition(
     65                 condition=lambda: self._proc.poll() is not None,
     66                 exception=TimeoutException,
     67                 timeout=10,
     68                 sleep_interval=0.1,
     69                 desc='Waiting for logcat to terminate')
     70         except TimeoutException:
     71             logging.info('Killing logcat due to timeout')
     72             self._proc.kill()
     73             self._proc.wait()
     74         finally:
     75             self._proc = None
     76 
     77 
     78 def wait_for_android_boot(timeout=None):
     79     """Sleep until Android has completed booting or timeout occurs."""
     80     if timeout is None:
     81         timeout = _WAIT_FOR_ANDROID_BOOT_SECONDS
     82 
     83     def _is_container_started():
     84         return utils.system('android-sh -c true', ignore_status=True) == 0
     85 
     86     def _is_android_booted():
     87         output = utils.system_output(
     88             'android-sh -c "getprop sys.boot_completed"', ignore_status=True)
     89         return output.strip() == '1'
     90 
     91     logging.info('Waiting for Android to boot completely.')
     92 
     93     start_time = time.time()
     94     utils.poll_for_condition(condition=_is_container_started,
     95                              desc='Container has started',
     96                              timeout=timeout,
     97                              exception=error.TestFail('Android did not boot!'),
     98                              sleep_interval=_BOOT_CHECK_INTERVAL_SECONDS)
     99     with Logcat(_VAR_LOGCAT_BOOT_PATH):
    100         boot_timeout = timeout - (time.time() - start_time)
    101         utils.poll_for_condition(
    102             condition=_is_android_booted,
    103             desc='Android has booted',
    104             timeout=boot_timeout,
    105             exception=error.TestFail('Android did not boot!'),
    106             sleep_interval=_BOOT_CHECK_INTERVAL_SECONDS)
    107     logging.info('Android has booted completely.')
    108