| # Copyright 2014 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, re, time |
| |
| from autotest_lib.client.common_lib import error |
| from autotest_lib.server.cros import vboot_constants as vboot |
| from autotest_lib.server.cros.faft.firmware_test import FirmwareTest |
| from autotest_lib.server.cros.watchdog_tester import WatchdogTester |
| |
| POWER_DIR = '/var/lib/power_manager' |
| TMP_POWER_DIR = '/tmp/power_manager' |
| |
| class firmware_EventLog(FirmwareTest): |
| """ |
| Test to ensure eventlog is written on boot and suspend/resume. |
| """ |
| version = 1 |
| |
| _TIME_FORMAT = '%Y-%m-%d %H:%M:%S' |
| |
| def initialize(self, host, cmdline_args): |
| super(firmware_EventLog, self).initialize(host, cmdline_args) |
| self.host = host |
| self.switcher.setup_mode('normal') |
| self.setup_usbkey(usbkey=True, host=False) |
| |
| def _has_event(self, pattern): |
| return bool(filter(re.compile(pattern).search, self._events)) |
| |
| def _gather_events(self): |
| entries = self.faft_client.System.RunShellCommandGetOutput( |
| 'mosys eventlog list') |
| now = self._now() |
| self._events = [] |
| for line in reversed(entries): |
| _, time_string, event = line.split(' | ', 2) |
| timestamp = time.strptime(time_string, self._TIME_FORMAT) |
| if timestamp > now: |
| logging.error('Found prophecy: "%s"', line) |
| raise error.TestFail('Event timestamp lies in the future') |
| if timestamp < self._cutoff_time: |
| logging.debug('Event "%s" too early, stopping search', line) |
| break |
| logging.info('Found event: "%s"', line) |
| self._events.append(event) |
| |
| # This assumes that Linux and the firmware use the same RTC. mosys converts |
| # timestamps to localtime, and so do we (by calling date without --utc). |
| def _now(self): |
| time_string = self.faft_client.System.RunShellCommandGetOutput( |
| 'date +"%s"' % self._TIME_FORMAT)[0] |
| logging.debug('Current local system time on DUT is "%s"', time_string) |
| return time.strptime(time_string, self._TIME_FORMAT) |
| |
| def disable_suspend_to_idle(self): |
| """Disable the powerd preference for suspend_to_idle.""" |
| logging.info('Disabling suspend_to_idle') |
| # Make temporary directory to hold powerd preferences so we |
| # do not leave behind any state if the test is aborted. |
| self.host.run('mkdir -p %s' % TMP_POWER_DIR) |
| self.host.run('echo 0 > %s/suspend_to_idle' % TMP_POWER_DIR) |
| self.host.run('mount --bind %s %s' % (TMP_POWER_DIR, POWER_DIR)) |
| self.host.run('restart powerd') |
| |
| def teardown_powerd_prefs(self): |
| """Clean up custom powerd preference changes.""" |
| self.host.run('umount %s' % POWER_DIR) |
| self.host.run('restart powerd') |
| |
| def run_once(self): |
| """Runs a single iteration of the test.""" |
| if not self.faft_config.has_eventlog: |
| raise error.TestNAError('This board has no eventlog support.') |
| |
| logging.info('Verifying eventlog behavior on normal mode boot') |
| self._cutoff_time = self._now() |
| self.switcher.mode_aware_reboot() |
| self.check_state((self.checkers.crossystem_checker, { |
| 'devsw_boot': '0', |
| 'mainfw_type': 'normal', |
| })) |
| self._gather_events() |
| if not self._has_event(r'System boot'): |
| raise error.TestFail('No "System boot" event on normal boot.') |
| # ' Wake' to match 'FW Wake' and 'ACPI Wake' but not 'Wake Source' |
| if self._has_event(r'Developer Mode|Recovery Mode|Sleep| Wake'): |
| raise error.TestFail('Incorrect event logged on normal boot.') |
| |
| logging.debug('Transitioning to dev mode for next test') |
| self.switcher.reboot_to_mode(to_mode='dev') |
| |
| logging.info('Verifying eventlog behavior on developer mode boot') |
| self._cutoff_time = self._now() |
| self.switcher.mode_aware_reboot() |
| self.check_state((self.checkers.crossystem_checker, { |
| 'devsw_boot': '1', |
| 'mainfw_type': 'developer', |
| })) |
| self._gather_events() |
| if (not self._has_event(r'System boot') or |
| not self._has_event(r'Chrome OS Developer Mode')): |
| raise error.TestFail('Missing required event on dev mode boot.') |
| if self._has_event(r'Recovery Mode|Sleep| Wake'): |
| raise error.TestFail('Incorrect event logged on dev mode boot.') |
| |
| logging.debug('Transitioning back to normal mode for final tests') |
| self.switcher.reboot_to_mode(to_mode='normal') |
| |
| logging.info('Verifying eventlog behavior in recovery mode') |
| self._cutoff_time = self._now() |
| self.switcher.reboot_to_mode(to_mode='rec') |
| logging.debug('Check we booted into recovery') |
| self.check_state((self.checkers.crossystem_checker, { |
| 'mainfw_type': 'recovery', |
| 'recovery_reason' : vboot.RECOVERY_REASON['RO_MANUAL'], |
| })) |
| self.switcher.mode_aware_reboot() |
| self.check_state((self.checkers.crossystem_checker, { |
| 'devsw_boot': '0', |
| 'mainfw_type': 'normal', |
| })) |
| self._gather_events() |
| if (not self._has_event(r'System boot') or |
| not self._has_event(r'Chrome OS Recovery Mode \| Recovery Button')): |
| raise error.TestFail('Missing required event in recovery mode.') |
| if self._has_event(r'Developer Mode|Sleep|FW Wake|ACPI Wake \| S3'): |
| raise error.TestFail('Incorrect event logged in recovery mode.') |
| |
| logging.info('Verifying eventlog behavior on suspend/resume') |
| self._cutoff_time = self._now() |
| self.faft_client.System.RunShellCommand( |
| 'powerd_dbus_suspend -wakeup_timeout=10') |
| time.sleep(5) # a little slack time for powerd to write the 'Wake' |
| self._gather_events() |
| |
| # Ensure system did not log developer or recovery mode event |
| if self._has_event(r'System |Developer Mode|Recovery Mode'): |
| raise error.TestFail('Incorrect event logged on suspend/resume.') |
| |
| # Accept any set: Wake/Sleep, ACPI Enter/Wake S3, S0ix Enter/Exit |
| if ((not self._has_event(r'^Wake') or not self._has_event(r'Sleep')) and |
| (not self._has_event(r'ACPI Enter \| S3') or |
| not self._has_event(r'ACPI Wake \| S3')) and |
| (not self._has_event(r'S0ix Enter') or |
| not self._has_event(r'S0ix Exit'))): |
| # If previous attempt failed force S3 mode and try again |
| logging.info('Enabling S3 to retest suspend/resume') |
| self.disable_suspend_to_idle() |
| self._cutoff_time = self._now() |
| self.faft_client.System.RunShellCommand( |
| 'powerd_dbus_suspend -wakeup_timeout=10') |
| time.sleep(5) # a little slack time for powerd to write the 'Wake' |
| self.teardown_powerd_prefs() |
| self._gather_events() |
| if (not self._has_event(r'ACPI Enter \| S3') or |
| not self._has_event(r'ACPI Wake \| S3')): |
| raise error.TestFail('Missing required event on suspend/resume') |
| |
| watchdog = WatchdogTester(self.host) |
| if not watchdog.is_supported(): |
| logging.info('No hardware watchdog on this platform, skipping') |
| elif self.faft_client.System.RunShellCommandGetOutput( |
| 'crossystem arch')[0] != 'x86': # TODO: Implement event on x86 |
| logging.info('Verifying eventlog behavior with hardware watchdog') |
| self._cutoff_time = self._now() |
| with watchdog: |
| watchdog.trigger_watchdog() |
| self._gather_events() |
| if (not self._has_event(r'System boot') or |
| not self._has_event(r'Hardware watchdog reset')): |
| raise error.TestFail('Did not log hardware watchdog event') |