# Copyright (c) 2015 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 import 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 class firmware_ECLidShutdown(FirmwareTest): """ Exercises the GBB_FLAG_DISABLE_LID_SHUTDOWN flag: confirms that when the flag is enabled, a closed lid will not prevent booting. """ version = 1 # Delay to allow for a power state change after closing or opening the lid. # This value is determined experimentally. LID_POWER_STATE_DELAY = 5 POWER_STATE_CHECK_TRIES = 3 POWER_STATE_CHECK_DELAY = 10 IGNORE_LID_IN_USERSPACE_CMD = 'echo 0 > /var/lib/power_manager/use_lid' CHECK_POWER_MANAGER_CFG_DEFAULT = '[ ! -f /var/lib/power_manager/use_lid ]' def initialize(self, host, cmdline_args): super(firmware_ECLidShutdown, self).initialize(host, cmdline_args) self.setup_usbkey(usbkey=False) def cleanup(self): """Reopens the lid, boots the DUT to normal mode, and clears the GBB flag manipulated in this test. """ try: self._reset_ec_regexp() logging.info('The screen should turn back on now, during cleanup.') self.servo.set_nocheck('lid_open', 'yes') time.sleep(self.LID_POWER_STATE_DELAY) if self.servo.get('lid_open') != 'yes': raise error.TestFail('The device did not stay in a mechanical' 'on state after a lid open.') self.switcher.simple_reboot(sync_before_boot=False) self.switcher.wait_for_client() self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN, 0) self.faft_client.system.run_shell_command( self.CHECK_POWER_MANAGER_CFG_DEFAULT) except Exception as exc: logging.debug( 'Exception during cleanup considered non-fatal. ' 'Traceback:', exc_info=True) super(firmware_ECLidShutdown, self).cleanup() def _reset_ec_regexp(self): """Resets ec_uart_regexp field. Needs to be done for the ec_uart_regexp otherwise dut-control command will time out due to no match. """ self.servo.set('ec_uart_regexp', 'None') def _check_lid_shutdown(self): """ Checks behavior with GBB_FLAG_DISABLE_LID_SHUTDOWN disabled. Clears the flag that disables listening to the lid for shutdown (when the lid is closed at boot), boots into recovery mode and confirms that the device stays in a mechanical off state. Reopens the lid and restores the device. """ self.clear_set_gbb_flags(vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN, 0) # TODO(kmshelton): Simplify to not use recovery mode. self.faft_client.system.request_recovery_boot() self.servo.set('lid_open', 'no') time.sleep(self.LID_POWER_STATE_DELAY) self.switcher.simple_reboot(sync_before_boot=False) # Some boards may reset the lid_open state when AP reboot, # check b/137612865 time.sleep(self.faft_config.ec_boot_to_console) if self.servo.get('lid_open') != 'no': self.servo.set('lid_open', 'no') time.sleep(self.LID_POWER_STATE_DELAY) time.sleep(self.faft_config.firmware_screen) if not self.wait_power_state('G3', self.POWER_STATE_CHECK_TRIES, self.POWER_STATE_CHECK_DELAY): raise error.TestFail('The device did not stay in a mechanical off ' 'state after a lid close and a warm reboot.') # kukui resets EC on opening the lid in some cases, so # using servo.set('lid_open', 'yes') would verify the set result # immediately by getting the control back, and this results a failure of # console-no-response due to EC reset. We should use set_nocheck # instead. self.servo.set_nocheck('lid_open', 'yes') time.sleep(self.LID_POWER_STATE_DELAY) if self.servo.get('lid_open') != 'yes': raise error.TestFail('The device did not stay in a mechanical on ' 'state after a lid open.') time.sleep(self.faft_config.firmware_screen) self.switcher.simple_reboot(sync_before_boot=False) self._reset_ec_regexp() self.switcher.wait_for_client() return True def _check_lid_shutdown_disabled(self): """ Checks behavior with GBB_FLAG_DISABLE_LID_SHUTDOWN enabled. Sets the flag that disables listening to the lid for shutdown (when the lid is closed at boot), disables the power daemon, closes the lid, boots to a firmware screen. """ self.clear_set_gbb_flags(0, vboot.GBB_FLAG_DISABLE_LID_SHUTDOWN) self.faft_client.system.request_recovery_boot() self.faft_client.system.run_shell_command( self.IGNORE_LID_IN_USERSPACE_CMD) self.servo.set('lid_open', 'no') if not self.wait_power_state('S0', self.POWER_STATE_CHECK_TRIES): raise error.TestError( 'The device did not stay in S0 when the lid was closed ' 'with powerd ignoring lid state. Maybe userspace power ' 'management behaviors have changed.') self.switcher.simple_reboot(sync_before_boot=False) time.sleep(self.faft_config.ec_boot_to_console) if self.servo.get('lid_open') != 'no': self.servo.set('lid_open', 'no') time.sleep(self.LID_POWER_STATE_DELAY) logging.info('The screen will remain black, even though we are at a ' 'recovery screen.') time.sleep(self.faft_config.firmware_screen) if not self.wait_power_state('S0', self.POWER_STATE_CHECK_TRIES): raise error.TestFail( 'The device did get to an active state when warm reset ' 'with the lid off and GBB_FLAG_DISABLE_LID_SHUTDOWN ' 'enabled.') return True def run_once(self): """Runs a single iteration of the test.""" if not self.check_ec_capability(['lid']): raise error.TestNAError('This device needs a lid to run this test') logging.info('Verify the device does shutdown when verified boot ' 'starts while the lid is closed and ' 'GBB_FLAG_DISABLE_LID_SHUTDOWN disabled.') self.check_state(self._check_lid_shutdown) logging.info('Verify the device does not shutdown when verified boot ' 'starts while the lid is closed with ' 'GBB_FLAG_DISABLE_LID_SHUTDOWN enabled.') self.check_state(self._check_lid_shutdown_disabled)