1# Copyright (c) 2013 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 logging 6from autotest_lib.client.bin import test, utils 7from autotest_lib.client.common_lib import error 8from autotest_lib.client.cros import constants, cros_ui 9 10 11class UIStopped(Exception): 12 """Raised when the UI seems to have stopped respawning.""" 13 pass 14 15 16class desktopui_CrashyReboot(test.test): 17 """Drive device to handle a too-crashy UI. 18 19 Run by desktopui_CrashyRebootServer. 20 """ 21 version = 1 22 23 UNREASONABLY_HIGH_RESPAWN_COUNT=90 24 25 26 def _nuke_browser_with_prejudice_and_check_for_ui_stop(self): 27 """Nuke the browser with prejudice, check to see if the UI is down.""" 28 try: 29 utils.nuke_process_by_name(constants.BROWSER, with_prejudice=True) 30 except error.AutoservPidAlreadyDeadError: 31 pass 32 return not cros_ui.is_up() 33 34 35 def _nuke_browser_until_ui_goes_down(self): 36 """Nuke the browser continuously until it stops respawning. 37 38 @raises utils.TimeoutError if the ui doesn't stop respawning. 39 """ 40 utils.poll_for_condition( 41 condition=self._nuke_browser_with_prejudice_and_check_for_ui_stop, 42 timeout=60, 43 desc='ui to stop respawning, or the device to reboot') 44 45 46 def run_once(self, expect_reboot=False): 47 # Ensure the UI is running. 48 logging.debug('Restarting UI to ensure that it\'s running.') 49 cros_ui.stop(allow_fail=True) 50 cros_ui.start(wait_for_login_prompt=True) 51 52 # Since there is no 100% reliable way to determine that the 53 # browser process we're interested in is gone, we need to use 54 # a polling interval to continuously send KILL signals. This 55 # puts the test code in an unavoidable race with the UI 56 # respawning logic being tested. If the UI is down at the 57 # instant we check, it could mean that the UI is done 58 # respawning, the UI is about to respawn, or the device could 59 # already be rebooting. In all likelihood, the UI is coming 60 # back and we'll need to kill it all over again. This is why 61 # the code below polls the UI status for a number of seconds: 62 # to be more confident that the UI went down and is staying down. 63 try: 64 while True: 65 utils.poll_for_condition(condition=cros_ui.is_up, 66 timeout=5, 67 exception=UIStopped('As expected')) 68 self._nuke_browser_until_ui_goes_down() 69 except UIStopped: 70 pass 71 except utils.TimeoutError as te: 72 raise error.TestFail(te) 73 74 if expect_reboot: 75 raise error.TestFail('UI stopped respawning instead of rebooting.') 76 77 78 def cleanup(self): 79 # If the UI is already up, we want to tolerate that. 80 cros_ui.start(allow_fail=True) 81