Home | History | Annotate | Download | only in desktopui_CrashyReboot
      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 
      5 import logging
      6 from autotest_lib.client.bin import test, utils
      7 from autotest_lib.client.common_lib import error
      8 from autotest_lib.client.cros import constants, cros_ui
      9 
     10 
     11 class UIStopped(Exception):
     12     """Raised when the UI seems to have stopped respawning."""
     13     pass
     14 
     15 
     16 class 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