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 logging, os, signal, time 6 7 import common 8 from autotest_lib.client.bin import test, utils 9 from autotest_lib.client.common_lib import error 10 from autotest_lib.client.cros import constants, cros_logging, cros_ui, login 11 12 class desktopui_HangDetector(test.test): 13 """ 14 This class enables browser process hang detection, simulates a hang 15 by sending a SIGSTOP to the browser, and then checks to see that it 16 got killed and restarted successfully -- without the UI getting bounced. 17 """ 18 version = 1 19 20 21 def initialize(self): 22 self._pauser = cros_logging.LogRotationPauser() 23 self._pauser.begin() 24 25 26 def _get_oldest_pid_by_name(self, name): 27 try: 28 pid = utils.get_oldest_pid_by_name(name) 29 logging.debug('Found %d for %s', pid, name) 30 except error.CmdError as e: 31 raise error.TestError('Could not find pid of %s: %r' % (name, e)) 32 except ValueError as e: 33 raise error.TestError('Got bad pid looking up %s: %r' % (name, e)) 34 if not pid: 35 raise error.TestError('Got no pid looking up %s' % name) 36 return pid 37 38 39 def run_once(self): 40 # Create magic file to enable browser liveness checking and 41 # bounce the session manager to pick up the flag file. 42 cros_ui.stop() 43 os.mknod(constants.ENABLE_BROWSER_HANG_DETECTION_FILE) 44 cros_ui.start() 45 46 browser_pid = self._get_oldest_pid_by_name(constants.BROWSER) 47 sm_pid = self._get_oldest_pid_by_name(constants.SESSION_MANAGER) 48 49 # Reading the log is the best way to watch for the hang detector. 50 reader = cros_logging.LogReader() 51 reader.set_start_by_current() 52 53 # To simulate a hang, STOP the browser and wait for it to get 54 # hit by the session manager. It won't actually exit until it gets 55 # a SIGCONT, though. 56 try: 57 os.kill(browser_pid, signal.SIGSTOP) # Simulate hang. 58 except OSError as e: 59 raise error.TestError('Cannot STOP browser: %r' % e) 60 61 # Watch for hang detection. 62 utils.poll_for_condition( 63 condition=lambda: reader.can_find('Aborting browser process.'), 64 exception=utils.TimeoutError('Waiting for hang detector.'), 65 sleep_interval=5, 66 timeout=60) 67 68 try: 69 os.kill(browser_pid, signal.SIGCONT) # Allow browser to die. 70 except OSError as e: 71 raise error.TestError('Cannot CONT browser: %r' % e) 72 73 # Wait for old browser process to be gone. 74 utils.poll_for_condition( 75 condition= lambda: utils.pid_is_alive(browser_pid), 76 exception=utils.TimeoutError( 77 'Browser does not seem to have restarted!'), 78 timeout=60) 79 80 # Wait for new browser to come up. 81 login.wait_for_browser() 82 if sm_pid != self._get_oldest_pid_by_name(constants.SESSION_MANAGER): 83 raise error.TestFail('session_manager seems to have restarted') 84 85 86 def cleanup(self): 87 if os.path.exists(constants.ENABLE_BROWSER_HANG_DETECTION_FILE): 88 os.remove(constants.ENABLE_BROWSER_HANG_DETECTION_FILE) 89 self._pauser.end() 90