Home | History | Annotate | Download | only in cros
      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 
      5 import common, logging, os, time
      6 
      7 from autotest_lib.client.bin import utils
      8 from autotest_lib.client.common_lib import error
      9 from autotest_lib.client.common_lib import utils
     10 from 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.
     14 UI_RESTART_ATTEMPT_MSG = 'cros_ui.py: Attempting StopSession...'
     15 UI_RESTART_COMPLETE_MSG = 'cros_ui.py: StopSession complete.'
     16 RESTART_UI_TIMEOUT = 90  # longer because we may be crash dumping now.
     17 
     18 
     19 def 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 
     40 def 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 
     68 def 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 
     95 def stop(allow_fail=False):
     96     return utils.stop_service("ui", ignore_status=allow_fail)
     97 
     98 
     99 def 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 
    110 def 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 
    140 def nuke():
    141     """Nuke the login manager, waiting for it to restart."""
    142     restart(lambda: utils.nuke_process_by_name(constants.SESSION_MANAGER))
    143 
    144 
    145 def is_up():
    146     """Return True if the UI is up, False if not."""
    147     return utils.get_service_pid('ui')!=0
    148 
    149 
    150 def 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