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_DevScreenTimeout(FirmwareTest): 13 """ 14 Servo based developer firmware screen timeout test. 15 16 When booting in developer mode, the firmware shows a screen to warn user 17 the disk image is not secured. If a user press Ctrl-D or a timeout reaches, 18 it will boot to developer mode. This test is to verify the timeout period. 19 20 This test tries to boot the system in developer mode twice. 21 The first one will repeatedly press Ctrl-D on booting in order to reduce 22 the time on developer warning screen. The second one will do nothing and 23 wait the developer screen timeout. The time difference of these two boots 24 is close to the developer screen timeout. 25 """ 26 version = 1 27 28 # We accept 5s timeout margin as we need 5s to ensure client is offline. 29 # If the margin is too small and firmware initialization is too fast, 30 # the test will fail incorrectly. 31 TIMEOUT_MARGIN = 5 32 RUN_SHELL_READY_TIME_MARGIN = 5 33 34 fw_time_record = {} 35 36 def record_dev_screen_timestamp(self): 37 """Record timestamp when developer screen appears""" 38 39 timestamps_file = '/var/log/bios_times.txt' 40 timestamp_name = 'vboot select&load kernel' 41 sed_expression = 's/[0-9]*:%s[[:blank:]]*\([0-9,]*\).*/\\1/p' % ( 42 timestamp_name) 43 cmd = 'sed -n \'%s\' %s | sed \'s/,//g\'' % ( 44 sed_expression, timestamps_file) 45 time.sleep(self.RUN_SHELL_READY_TIME_MARGIN) 46 result = self.faft_client.system.run_shell_command_get_output( 47 cmd) 48 if result: 49 [dev_screen_ts] = result 50 self.fw_time_record['dev_screen_appear_ts'] = ( 51 (float(dev_screen_ts) / 1000000) + 0.7) 52 logging.info("Developer screen timestamp is %.2f", 53 self.fw_time_record['dev_screen_appear_ts']) 54 else: 55 logging.info("Failed to get developer screen appear timestamp, fallback to 0") 56 self.fw_time_record['dev_screen_appear_ts'] = 0 57 58 def record_fw_boot_time(self, tag): 59 """Record the current firmware boot time with the tag. 60 61 @param tag: A tag about this boot. 62 @raise TestError: If the firmware-boot-time file does not exist. 63 """ 64 time.sleep(self.RUN_SHELL_READY_TIME_MARGIN) 65 [fw_time] = self.faft_client.system.run_shell_command_get_output( 66 'cat /tmp/firmware-boot-time') 67 logging.info('Got firmware boot time [%s]: %s', tag, fw_time) 68 if fw_time: 69 self.fw_time_record[tag] = float(fw_time) 70 else: 71 raise error.TestError('Failed to get the firmware boot time.') 72 73 def check_timeout_period(self): 74 """Check the firmware screen timeout period matches our spec. 75 76 @raise TestFail: If the timeout period does not match our spec. 77 """ 78 # On tablets/detachables, eliminate the time taken for pressing volume 79 # down button (HOLD_VOL_DOWN_BUTTON_BYPASS + 0.1) to calculate the 80 # firmware boot time of quick dev boot. 81 if self.faft_config.mode_switcher_type == 'tablet_detachable_switcher': 82 self.fw_time_record['quick_bypass_boot'] -= \ 83 (self.switcher.HOLD_VOL_DOWN_BUTTON_BYPASS + 0.1) 84 logging.info( 85 "Firmware boot time [quick_bypass_boot] after " 86 "eliminating the volume down button press time " 87 "(%.1f seconds): %s", 88 self.switcher.HOLD_VOL_DOWN_BUTTON_BYPASS + 0.1, 89 self.fw_time_record['quick_bypass_boot']) 90 got_timeout = (self.fw_time_record['timeout_boot'] - 91 self.fw_time_record['quick_bypass_boot']) 92 logging.info('Estimated developer firmware timeout: %s', got_timeout) 93 94 if (abs(got_timeout - self.faft_config.dev_screen_timeout) > 95 self.TIMEOUT_MARGIN): 96 raise error.TestFail( 97 'The developer firmware timeout does not match our spec: ' 98 'expected %.2f +/- %.2f but got %.2f.' % 99 (self.faft_config.dev_screen_timeout, self.TIMEOUT_MARGIN, 100 got_timeout)) 101 102 def initialize(self, host, cmdline_args): 103 super(firmware_DevScreenTimeout, self).initialize(host, cmdline_args) 104 # NA error check point for this test 105 if self.faft_config.mode_switcher_type not in ( 106 'keyboard_dev_switcher', 'tablet_detachable_switcher', 107 'menu_switcher'): 108 raise error.TestNAError("This test is only valid on devices with " 109 "screens.") 110 # This test is run on developer mode only. 111 self.switcher.setup_mode('dev') 112 self.setup_usbkey(usbkey=False) 113 114 def run_once(self): 115 """Runs a single iteration of the test.""" 116 logging.info("Always expected developer mode firmware A boot.") 117 self.check_state((self.checkers.crossystem_checker, { 118 'devsw_boot': '1', 119 'mainfw_act': 'A', 120 'mainfw_type': 'developer', 121 })) 122 123 # To add an extra reboot before the measurement 124 # to avoid TPM reset too long 125 self.switcher.simple_reboot() 126 self.switcher.wait_for_client() 127 128 logging.info("Reboot the device, do nothing and wait for screen " 129 "timeout. And then record the firmware boot time and " 130 "developer screen timestamp.") 131 self.switcher.simple_reboot() 132 self.switcher.wait_for_client() 133 134 # Record developer screen timestamp 135 self.record_dev_screen_timestamp() 136 # Record the boot time of firmware screen timeout. 137 self.record_fw_boot_time('timeout_boot') 138 139 # Measure firmware boot time with developer screen bypass 140 logging.info("Reboot and bypass the Developer warning screen " 141 "immediately.") 142 self.switcher.simple_reboot() 143 time.sleep(self.fw_time_record['dev_screen_appear_ts']) 144 self.switcher.bypass_dev_mode() 145 self.switcher.wait_for_client() 146 logging.info("Record the firmware boot time without waiting for " 147 "firmware screen.") 148 self.record_fw_boot_time('quick_bypass_boot') 149 150 logging.info("Check the firmware screen timeout matches our spec.") 151 self.check_timeout_period() 152