• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2012 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
5import common, logging, os, time
6
7from autotest_lib.client.bin import utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.common_lib import utils
10from autotest_lib.client.cros import constants
11
12# Log messages used to signal when we're restarting UI. Used to detect
13# crashes by cros_ui_test.UITest.
14UI_RESTART_ATTEMPT_MSG = 'cros_ui.py: Attempting StopSession...'
15UI_RESTART_COMPLETE_MSG = 'cros_ui.py: StopSession complete.'
16RESTART_UI_TIMEOUT = 90  # longer because we may be crash dumping now.
17
18
19def get_chrome_session_ident(host=None):
20    """Return an identifier that changes whenever Chrome restarts.
21
22    This function returns a value that is unique to the most
23    recently started Chrome process; the returned value changes
24    each time Chrome restarts and displays the login screen.  The
25    change in the value can be used to detect a successful Chrome
26    restart.
27
28    Note that uniqueness is only guaranteed until the host reboots.
29
30    Args:
31        host:  If not None, a host object on which to test Chrome
32            state, rather than running commands on the local host.
33
34    """
35    if host:
36        return host.run(constants.LOGIN_PROMPT_STATUS_COMMAND).stdout
37    return utils.run(constants.LOGIN_PROMPT_STATUS_COMMAND).stdout
38
39
40def wait_for_chrome_ready(old_session, host=None,
41                          timeout=RESTART_UI_TIMEOUT):
42    """Wait until a new Chrome login prompt is on screen and ready.
43
44    The standard formula to check whether the prompt has appeared yet
45    is with a pattern like the following:
46
47       session = get_chrome_session_ident()
48       logout()
49       wait_for_chrome_ready(session)
50
51    Args:
52        old_session:  identifier for the login prompt prior to
53            restarting Chrome.
54        host:  If not None, a host object on which to test Chrome
55            state, rather than running commands on the local host.
56        timeout: float number of seconds to wait
57
58    Raises:
59        TimeoutError: Login prompt didn't get up before timeout
60
61    """
62    utils.poll_for_condition(
63        condition=lambda: old_session != get_chrome_session_ident(host),
64        exception=utils.TimeoutError('Timed out waiting for login prompt'),
65        timeout=timeout, sleep_interval=1.0)
66
67
68def stop_and_wait_for_chrome_to_exit(timeout_secs=40):
69    """Stops the UI and waits for chrome to exit.
70
71    Stops the UI and waits for all chrome processes to exit or until
72    timeout_secs is reached.
73
74    Args:
75        timeout_secs: float number of seconds to wait.
76
77    Returns:
78        True upon successfully stopping the UI and all chrome processes exiting.
79        False otherwise.
80    """
81    status = stop(allow_fail=True)
82    if status:
83        logging.error('stop ui returned non-zero status: %s', status)
84        return False
85    start_time = time.time()
86    while time.time() - start_time < timeout_secs:
87        status = utils.system('pgrep chrome', ignore_status=True)
88        if status == 1: return True
89        time.sleep(1)
90    logging.error('stop ui failed to stop chrome within %s seconds',
91                  timeout_secs)
92    return False
93
94
95def stop(allow_fail=False):
96    return utils.stop_service("ui", ignore_status=allow_fail)
97
98
99def start(allow_fail=False, wait_for_login_prompt=True):
100    """Start the login manager and wait for the prompt to show up."""
101    session = get_chrome_session_ident()
102    result = utils.start_service("ui", ignore_status=allow_fail)
103    # If allow_fail is set, the caller might be calling us when the UI job
104    # is already running. In that case, the above command fails.
105    if result == 0 and wait_for_login_prompt:
106        wait_for_chrome_ready(session)
107    return result
108
109
110def restart(report_stop_failure=False):
111    """Restart the session manager.
112
113    - If the user is logged in, the session will be terminated.
114    - If the UI is currently down, just go ahead and bring it up unless the
115      caller has requested that a failure to stop be reported.
116    - To ensure all processes are up and ready, this function will wait
117      for the login prompt to show up and be marked as visible.
118
119    @param report_stop_failure: False by default, set to True if you care about
120                                the UI being up at the time of call and
121                                successfully torn down by this call.
122    """
123    session = get_chrome_session_ident()
124
125    # Log what we're about to do to /var/log/messages. Used to log crashes later
126    # in cleanup by cros_ui_test.UITest.
127    utils.system('logger "%s"' % UI_RESTART_ATTEMPT_MSG)
128
129    try:
130        if stop(allow_fail=not report_stop_failure) != 0:
131            raise error.TestError('Could not stop session')
132        start(wait_for_login_prompt=False)
133        # Wait for login prompt to appear to indicate that all processes are
134        # up and running again.
135        wait_for_chrome_ready(session)
136    finally:
137        utils.system('logger "%s"' % UI_RESTART_COMPLETE_MSG)
138
139
140def nuke():
141    """Nuke the login manager, waiting for it to restart."""
142    restart(lambda: utils.nuke_process_by_name(constants.SESSION_MANAGER))
143
144
145def is_up():
146    """Return True if the UI is up, False if not."""
147    return utils.get_service_pid('ui')!=0
148
149
150def clear_respawn_state():
151    """Removes bookkeeping related to respawning crashed UI."""
152    for filename in [constants.UI_RESPAWN_TIMESTAMPS_FILE,
153                     constants.UI_TOO_CRASHY_TIMESTAMPS_FILE]:
154        try:
155            os.unlink(filename)
156        except OSError:
157            pass  # It's already gone.
158