You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
5.5 KiB
157 lines
5.5 KiB
# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
|
|
# Use of this source code is governed by a BSD-style license that can be
|
|
# found in the LICENSE file.
|
|
|
|
import common, logging, os, time
|
|
|
|
from autotest_lib.client.common_lib import error
|
|
from autotest_lib.client.common_lib import utils
|
|
from autotest_lib.client.cros import constants
|
|
|
|
# Log messages used to signal when we're restarting UI. Used to detect
|
|
# crashes by cros_ui_test.UITest.
|
|
UI_RESTART_ATTEMPT_MSG = 'cros_ui.py: Attempting StopSession...'
|
|
UI_RESTART_COMPLETE_MSG = 'cros_ui.py: StopSession complete.'
|
|
RESTART_UI_TIMEOUT = 90 # longer because we may be crash dumping now.
|
|
|
|
|
|
def get_chrome_session_ident(host=None):
|
|
"""Return an identifier that changes whenever Chrome restarts.
|
|
|
|
This function returns a value that is unique to the most
|
|
recently started Chrome process; the returned value changes
|
|
each time Chrome restarts and displays the login screen. The
|
|
change in the value can be used to detect a successful Chrome
|
|
restart.
|
|
|
|
Note that uniqueness is only guaranteed until the host reboots.
|
|
|
|
Args:
|
|
host: If not None, a host object on which to test Chrome
|
|
state, rather than running commands on the local host.
|
|
|
|
"""
|
|
if host:
|
|
return host.run(constants.LOGIN_PROMPT_STATUS_COMMAND).stdout
|
|
return utils.run(constants.LOGIN_PROMPT_STATUS_COMMAND).stdout
|
|
|
|
|
|
def wait_for_chrome_ready(old_session, host=None,
|
|
timeout=RESTART_UI_TIMEOUT):
|
|
"""Wait until a new Chrome login prompt is on screen and ready.
|
|
|
|
The standard formula to check whether the prompt has appeared yet
|
|
is with a pattern like the following:
|
|
|
|
session = get_chrome_session_ident()
|
|
logout()
|
|
wait_for_chrome_ready(session)
|
|
|
|
Args:
|
|
old_session: identifier for the login prompt prior to
|
|
restarting Chrome.
|
|
host: If not None, a host object on which to test Chrome
|
|
state, rather than running commands on the local host.
|
|
timeout: float number of seconds to wait
|
|
|
|
Raises:
|
|
TimeoutError: Login prompt didn't get up before timeout
|
|
|
|
"""
|
|
utils.poll_for_condition(
|
|
condition=lambda: old_session != get_chrome_session_ident(host),
|
|
exception=utils.TimeoutError('Timed out waiting for login prompt'),
|
|
timeout=timeout, sleep_interval=1.0)
|
|
|
|
|
|
def stop_and_wait_for_chrome_to_exit(timeout_secs=40):
|
|
"""Stops the UI and waits for chrome to exit.
|
|
|
|
Stops the UI and waits for all chrome processes to exit or until
|
|
timeout_secs is reached.
|
|
|
|
Args:
|
|
timeout_secs: float number of seconds to wait.
|
|
|
|
Returns:
|
|
True upon successfully stopping the UI and all chrome processes exiting.
|
|
False otherwise.
|
|
"""
|
|
status = stop(allow_fail=True)
|
|
if status:
|
|
logging.error('stop ui returned non-zero status: %s', status)
|
|
return False
|
|
start_time = time.time()
|
|
while time.time() - start_time < timeout_secs:
|
|
status = utils.system('pgrep chrome', ignore_status=True)
|
|
if status == 1: return True
|
|
time.sleep(1)
|
|
logging.error('stop ui failed to stop chrome within %s seconds',
|
|
timeout_secs)
|
|
return False
|
|
|
|
|
|
def stop(allow_fail=False):
|
|
return utils.stop_service("ui", ignore_status=allow_fail)
|
|
|
|
|
|
def start(allow_fail=False, wait_for_login_prompt=True):
|
|
"""Start the login manager and wait for the prompt to show up."""
|
|
session = get_chrome_session_ident()
|
|
result = utils.start_service("ui", ignore_status=allow_fail)
|
|
# If allow_fail is set, the caller might be calling us when the UI job
|
|
# is already running. In that case, the above command fails.
|
|
if result == 0 and wait_for_login_prompt:
|
|
wait_for_chrome_ready(session)
|
|
return result
|
|
|
|
|
|
def restart(report_stop_failure=False):
|
|
"""Restart the session manager.
|
|
|
|
- If the user is logged in, the session will be terminated.
|
|
- If the UI is currently down, just go ahead and bring it up unless the
|
|
caller has requested that a failure to stop be reported.
|
|
- To ensure all processes are up and ready, this function will wait
|
|
for the login prompt to show up and be marked as visible.
|
|
|
|
@param report_stop_failure: False by default, set to True if you care about
|
|
the UI being up at the time of call and
|
|
successfully torn down by this call.
|
|
"""
|
|
session = get_chrome_session_ident()
|
|
|
|
# Log what we're about to do to /var/log/messages. Used to log crashes later
|
|
# in cleanup by cros_ui_test.UITest.
|
|
utils.system('logger "%s"' % UI_RESTART_ATTEMPT_MSG)
|
|
|
|
try:
|
|
if stop(allow_fail=not report_stop_failure) != 0:
|
|
raise error.TestError('Could not stop session')
|
|
start(wait_for_login_prompt=False)
|
|
# Wait for login prompt to appear to indicate that all processes are
|
|
# up and running again.
|
|
wait_for_chrome_ready(session)
|
|
finally:
|
|
utils.system('logger "%s"' % UI_RESTART_COMPLETE_MSG)
|
|
|
|
|
|
def nuke():
|
|
"""Nuke the login manager, waiting for it to restart."""
|
|
restart(lambda: utils.nuke_process_by_name(constants.SESSION_MANAGER))
|
|
|
|
|
|
def is_up():
|
|
"""Return True if the UI is up, False if not."""
|
|
return utils.get_service_pid('ui')!=0
|
|
|
|
|
|
def clear_respawn_state():
|
|
"""Removes bookkeeping related to respawning crashed UI."""
|
|
for filename in [constants.UI_RESPAWN_TIMESTAMPS_FILE,
|
|
constants.UI_TOO_CRASHY_TIMESTAMPS_FILE]:
|
|
try:
|
|
os.unlink(filename)
|
|
except OSError:
|
|
pass # It's already gone.
|