• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
7import logging
8import subprocess
9import time
10
11from autotest_lib.client.bin import utils
12from 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.
17ARC_MODE_ENABLED = "enabled"
18# Similar to "enabled", except that it will not block.
19ARC_MODE_ENABLED_ASYNC = "enabled_async"
20# Ask Chrome to not start ARC instance.  This is the default.
21ARC_MODE_DISABLED = "disabled"
22# All available ARC options.
23ARC_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
32class 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
78def 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