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