1# Copyright (c) 2011 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 5import logging 6import time 7 8from autotest_lib.client.common_lib import error 9from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 10 11 12class firmware_FwScreenPressPower(FirmwareTest): 13 """ 14 Servo based power button triggered shutdown test during firmware screens. 15 16 This test requires a USB disk plugged-in, which contains a ChromeOS test 17 image (built by "build_image --test"). On runtime, this test triggers 18 firmware screens (developer, remove, insert, yuck, and to_norm screens), 19 and then presses the power button in order to power the machine down. 20 """ 21 version = 1 22 NEEDS_SERVO_USB = True 23 24 SHORT_SHUTDOWN_CONFIRMATION_PERIOD = 0.1 25 26 def wait_fw_screen_and_press_power(self): 27 """Wait for firmware warning screen and press power button.""" 28 time.sleep(self.faft_config.firmware_screen) 29 # While the firmware screen, the power button probing loop sleeps 30 # 0.25 second on every scan. Use the normal delay (1.2 second) for 31 # power press. 32 33 if self.faft_config.is_detachable and self.faft_config.mode_switcher_type == 'menu_switcher': 34 # Since power button has been overridden as a select button in the 35 # fw screens for detachables, we can just skip this part of the test 36 # and shut down the DUT using the power state controller instead. 37 logging.info("Setting Power Off") 38 self.servo.get_power_state_controller().power_off() 39 else: 40 # Otherwise use the power button 41 logging.info("Pressing Power Button") 42 self.servo.power_normal_press() 43 44 def wait_longer_fw_screen_and_press_power(self): 45 """Wait for firmware screen without timeout and press power button.""" 46 time.sleep(self.faft_config.dev_screen_timeout) 47 self.wait_fw_screen_and_press_power() 48 49 def wait_second_screen_and_press_power(self): 50 """Wait and trigger a second screen and press power button.""" 51 self.switcher.trigger_dev_to_rec() 52 self.wait_fw_screen_and_press_power() 53 54 def wait_yuck_screen_and_press_power(self): 55 """Insert corrupted USB for yuck screen and press power button.""" 56 # This USB stick will be removed in cleanup phase. 57 self.servo.switch_usbkey('dut') 58 time.sleep(self.faft_config.usb_plug) 59 self.wait_longer_fw_screen_and_press_power() 60 61 def initialize(self, host, cmdline_args): 62 """Initialize the test""" 63 super(firmware_FwScreenPressPower, self).initialize(host, cmdline_args) 64 self.switcher.setup_mode('dev') 65 self.setup_usbkey(True, host=True) 66 usb_dev = self.servo.probe_host_usb_dev() 67 # Corrupt the kernel of USB stick. It is needed for triggering a 68 # yuck screen later. 69 self.corrupt_usb_kernel(usb_dev) 70 71 def cleanup(self): 72 """Cleanup the test""" 73 try: 74 self.servo.switch_usbkey('host') 75 usb_dev = self.servo.probe_host_usb_dev() 76 # Restore the kernel of USB stick which is corrupted on setup phase. 77 self.restore_usb_kernel(usb_dev) 78 except Exception as e: 79 logging.error("Caught exception: %s", str(e)) 80 super(firmware_FwScreenPressPower, self).cleanup() 81 82 def run_once(self): 83 """Main test logic""" 84 if self.faft_config.mode_switcher_type not in ( 85 'keyboard_dev_switcher', 'tablet_detachable_switcher', 86 'menu_switcher'): 87 raise error.TestNAError("This test is only valid on devices with " 88 "screens.") 89 if not self.faft_config.has_powerbutton: 90 raise error.TestNAError("This test is only valid on devices with " 91 "power button.") 92 93 logging.info( 94 "Expected dev mode and reboot. " 95 "When the next DEVELOPER SCREEN shown, press power button " 96 "to make DUT shutdown.") 97 self.check_state((self.checkers.crossystem_checker, { 98 'devsw_boot': '1', 99 'mainfw_type': 'developer', 100 })) 101 self.switcher.simple_reboot() 102 self.run_shutdown_process( 103 self.wait_fw_screen_and_press_power, 104 post_power_action=self.switcher.bypass_dev_mode) 105 self.switcher.wait_for_client() 106 107 if self.faft_config.power_button_dev_switch: 108 logging.info("Skipping TO_NORM screen test. The power button is " 109 "used to confirm DEV mode to NORM mode.") 110 else: 111 logging.info( 112 "Reboot. When the developer screen shown, press " 113 "enter key to trigger either TO_NORM screen (new) or " 114 "RECOVERY INSERT screen (old). Then press power button " 115 "to make DUT shutdown.") 116 self.check_state((self.checkers.crossystem_checker, { 117 'devsw_boot': '1', 118 'mainfw_type': 'developer', 119 })) 120 self.switcher.simple_reboot() 121 self.run_shutdown_process( 122 self.wait_second_screen_and_press_power, 123 post_power_action=self.switcher.bypass_dev_mode, 124 shutdown_timeout=self.SHORT_SHUTDOWN_CONFIRMATION_PERIOD) 125 self.switcher.wait_for_client() 126 127 logging.info("Request recovery boot. When the RECOVERY INSERT " 128 "screen shows, press power button to make DUT shutdown.") 129 self.check_state((self.checkers.crossystem_checker, { 130 'devsw_boot': '1', 131 'mainfw_type': 'developer', 132 })) 133 self.servo.set_nocheck('power_state', 'rec') 134 self.run_shutdown_process( 135 self.wait_longer_fw_screen_and_press_power, 136 post_power_action=self.switcher.bypass_dev_mode, 137 shutdown_timeout=self.SHORT_SHUTDOWN_CONFIRMATION_PERIOD) 138 self.switcher.wait_for_client() 139 140 logging.info("Request recovery boot again. When the recovery " 141 "insert screen shows, insert a corrupted USB and trigger " 142 "a YUCK SCREEN. Then press power button to " 143 "make DUT shutdown.") 144 self.check_state((self.checkers.crossystem_checker, { 145 'devsw_boot': '1', 146 'mainfw_type': 'developer', 147 })) 148 self.servo.set_nocheck('power_state', 'rec') 149 self.run_shutdown_process( 150 self.wait_yuck_screen_and_press_power, 151 post_power_action=self.switcher.bypass_dev_mode, 152 shutdown_timeout=self.SHORT_SHUTDOWN_CONFIRMATION_PERIOD) 153 self.switcher.wait_for_client() 154 155 logging.info("Switch back to normal mode.") 156 self.check_state((self.checkers.crossystem_checker, { 157 'devsw_boot': '1', 158 'mainfw_type': 'developer', 159 })) 160 self.switcher.reboot_to_mode(to_mode='normal') 161 162 logging.info("Expected normal mode and request recovery boot. " 163 "Because an USB stick is inserted, a RECOVERY REMOVE " 164 "screen shows. Press power button to make DUT shutdown.") 165 self.check_state((self.checkers.crossystem_checker, { 166 'devsw_boot': '0', 167 'mainfw_type': 'normal', 168 })) 169 self.servo.set_nocheck('power_state', 'rec') 170 self.run_shutdown_process( 171 self.wait_longer_fw_screen_and_press_power, 172 shutdown_timeout=self.SHORT_SHUTDOWN_CONFIRMATION_PERIOD) 173 self.switcher.wait_for_client() 174 175 logging.info("Check and done.") 176 self.check_state((self.checkers.crossystem_checker, { 177 'devsw_boot': '0', 178 'mainfw_type': 'normal', 179 })) 180