普通文本  |  81行  |  2.94 KB

# Copyright (c) 2013 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 logging
from autotest_lib.client.bin import test, utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.cros import constants, cros_ui


class UIStopped(Exception):
    """Raised when the UI seems to have stopped respawning."""
    pass


class desktopui_CrashyReboot(test.test):
    """Drive device to handle a too-crashy UI.

    Run by desktopui_CrashyRebootServer.
    """
    version = 1

    UNREASONABLY_HIGH_RESPAWN_COUNT=90


    def _nuke_browser_with_prejudice_and_check_for_ui_stop(self):
        """Nuke the browser with prejudice, check to see if the UI is down."""
        try:
            utils.nuke_process_by_name(constants.BROWSER, with_prejudice=True)
        except error.AutoservPidAlreadyDeadError:
            pass
        return not cros_ui.is_up()


    def _nuke_browser_until_ui_goes_down(self):
        """Nuke the browser continuously until it stops respawning.

        @raises utils.TimeoutError if the ui doesn't stop respawning.
        """
        utils.poll_for_condition(
            condition=self._nuke_browser_with_prejudice_and_check_for_ui_stop,
            timeout=60,
            desc='ui to stop respawning, or the device to reboot')


    def run_once(self, expect_reboot=False):
        # Ensure the UI is running.
        logging.debug('Restarting UI to ensure that it\'s running.')
        cros_ui.stop(allow_fail=True)
        cros_ui.start(wait_for_login_prompt=True)

        # Since there is no 100% reliable way to determine that the
        # browser process we're interested in is gone, we need to use
        # a polling interval to continuously send KILL signals. This
        # puts the test code in an unavoidable race with the UI
        # respawning logic being tested. If the UI is down at the
        # instant we check, it could mean that the UI is done
        # respawning, the UI is about to respawn, or the device could
        # already be rebooting. In all likelihood, the UI is coming
        # back and we'll need to kill it all over again. This is why
        # the code below polls the UI status for a number of seconds:
        # to be more confident that the UI went down and is staying down.
        try:
            while True:
                utils.poll_for_condition(condition=cros_ui.is_up,
                                         timeout=5,
                                         exception=UIStopped('As expected'))
                self._nuke_browser_until_ui_goes_down()
        except UIStopped:
            pass
        except utils.TimeoutError as te:
            raise error.TestFail(te)

        if expect_reboot:
            raise error.TestFail('UI stopped respawning instead of rebooting.')


    def cleanup(self):
        # If the UI is already up, we want to tolerate that.
        cros_ui.start(allow_fail=True)