Home | History | Annotate | Download | only in cros
      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
      6 
      7 import constants, cros_logging, cros_ui, cryptohome
      8 from autotest_lib.client.bin import utils
      9 from autotest_lib.client.common_lib import error
     10 
     11 
     12 class CrashError(error.TestError):
     13     """Error raised when a pertinent process crashes while waiting on
     14     a condition.
     15     """
     16     pass
     17 
     18 
     19 class UnexpectedCondition(error.TestError):
     20     """Error raised when an expected precondition is not met."""
     21     pass
     22 
     23 
     24 def process_crashed(process, log_reader):
     25     """Checks the log watched by |log_reader| to see if a crash was reported
     26     for |process|.
     27 
     28     @param process: process name to look for.
     29     @param log_reader: LogReader object set up to watch appropriate log file.
     30 
     31     @return: True if so, False if not.
     32     """
     33     return log_reader.can_find('Received crash notification for %s' % process)
     34 
     35 
     36 def wait_for_condition(condition, timeout_msg, timeout, process, crash_msg):
     37     """Wait for callable |condition| to return true, while checking for crashes.
     38 
     39     Poll for |condition| to become true, for |timeout| seconds. If the timeout
     40     is reached, check to see if |process| crashed while we were polling.
     41     If so, raise CrashError(crash_msg). If not, raise TimeoutError(timeout_msg).
     42 
     43     @param condition: a callable to poll on.
     44     @param timeout_msg: message to put in TimeoutError before raising.
     45     @param timeout: float number of seconds to poll on |condition|.
     46     @param process: process name to watch for crashes while polling.
     47     @param crash_msg: message to put in CrashError if polling failed and
     48                       |process| crashed.
     49 
     50     @raise: TimeoutError if timeout is reached.
     51     @raise: CrashError if process crashed and the condition never fired.
     52     """
     53     # Mark /var/log/messages now; we'll run through all subsequent log
     54     # messages if we couldn't start chrome to see if the browser crashed.
     55     log_reader = cros_logging.LogReader()
     56     log_reader.set_start_by_current()
     57     try:
     58         utils.poll_for_condition(
     59             condition,
     60             utils.TimeoutError(timeout_msg),
     61             timeout=timeout)
     62     except utils.TimeoutError, e:
     63         # We could fail faster if necessary, but it'd be more complicated.
     64         if process_crashed(process, log_reader):
     65             logging.error(crash_msg)
     66             raise CrashError(crash_msg)
     67         else:
     68             raise e
     69 
     70 
     71 def wait_for_browser(timeout=cros_ui.RESTART_UI_TIMEOUT):
     72     """Wait until a Chrome process is running.
     73 
     74     @param timeout: float number of seconds to wait.
     75 
     76     @raise: TimeoutError: Chrome didn't start before timeout.
     77     """
     78     wait_for_condition(
     79         lambda: os.system('pgrep ^%s$ >/dev/null' % constants.BROWSER) == 0,
     80         timeout_msg='Timed out waiting for Chrome to start',
     81         timeout=timeout,
     82         process=constants.BROWSER,
     83         crash_msg='Chrome crashed while starting up.')
     84 
     85 
     86 def wait_for_browser_exit(crash_msg, timeout=cros_ui.RESTART_UI_TIMEOUT):
     87     """Wait for the Chrome process to exit.
     88 
     89     @param crash_msg: Error message to include if Chrome crashed.
     90     @param timeout: float number of seconds to wait.
     91 
     92     @return: True if Chrome exited; False otherwise.
     93 
     94     @raise: CrashError: Chrome crashed while we were waiting.
     95     """
     96     try:
     97       wait_for_condition(
     98           lambda: os.system('pgrep ^%s$ >/dev/null' % constants.BROWSER) != 0,
     99           timeout_msg='Timed out waiting for Chrome to exit',
    100           timeout=timeout,
    101           process=constants.BROWSER,
    102           crash_msg=crash_msg)
    103       return True
    104     except utils.TimeoutError, e:
    105       return False
    106 
    107 
    108 def wait_for_cryptohome(user, timeout=cros_ui.RESTART_UI_TIMEOUT):
    109     """Wait until cryptohome is mounted.
    110 
    111     @param user: the user whose cryptohome the caller wants to wait for.
    112     @param timeout: float number of seconds to wait.
    113 
    114     @raise: TimeoutError: cryptohome wasn't mounted before timeout
    115     """
    116     wait_for_condition(
    117         condition=lambda: cryptohome.is_vault_mounted(user),
    118         timeout_msg='Timed out waiting for cryptohome to be mounted',
    119         timeout=timeout,
    120         process='cryptohomed',
    121         crash_msg='cryptohomed crashed during mount attempt')
    122 
    123 
    124 def wait_for_ownership(timeout=constants.DEFAULT_OWNERSHIP_TIMEOUT):
    125     """Wait until device owner key file exists on disk.
    126 
    127     @param timeout: float number of seconds to wait.
    128 
    129     @raise: TimeoutError: file didn't appear before timeout.
    130     """
    131     if os.access(constants.OWNER_KEY_FILE, os.F_OK):
    132         raise error.TestError('Device is already owned!')
    133     wait_for_condition(
    134         condition=lambda: os.access(constants.OWNER_KEY_FILE, os.F_OK),
    135         timeout_msg='Timed out waiting for ownership',
    136         timeout=timeout,
    137         process=constants.BROWSER,
    138         crash_msg='Chrome crashed before ownership could be taken.')
    139