1# Copyright 2020 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 6 7from autotest_lib.client.common_lib import error 8from autotest_lib.server.cros.faft.firmware_test import FirmwareTest 9 10 11class BaseMenuNavigator: 12 """Base class for menu navigator.""" 13 14 def __init__(self, test): 15 self.test = test 16 self.faft_config = self.test.faft_config 17 self.servo = self.test.servo 18 19 def menu_up(self): 20 """Navigate up in the menu.""" 21 if self.faft_config.is_detachable: 22 self.servo.set_nocheck('volume_up_hold', 100) 23 else: 24 self.servo.arrow_up() 25 26 def menu_down(self): 27 """Navigate down in the menu.""" 28 if self.faft_config.is_detachable: 29 self.servo.set_nocheck('volume_down_hold', 100) 30 else: 31 self.servo.arrow_down() 32 33 def menu_select(self, msg=None): 34 """Select a menu item.""" 35 if msg: 36 logging.info(msg) 37 if self.faft_config.is_detachable: 38 self.servo.power_short_press() 39 else: 40 self.servo.enter_key() 41 42 43class LegacyMenuNavigator(BaseMenuNavigator): 44 """Menu navigator for legacy menu UI. 45 46 The "legacy menu UI" is an old menu-based UI, which has been replaced 47 by the new one, called "menu UI". 48 """ 49 50 def trigger_rec_to_dev(self): 51 """Trigger to-dev transition.""" 52 self.test.switcher.trigger_rec_to_dev() 53 54 def dev_boot_from_internal(self): 55 """Boot from internal disk in developer mode. 56 57 Menu items in developer warning screen: 58 0. Developer Options 59 1. Show Debug Info 60 2. Enable OS Verification 61 *3. Power Off 62 4. Language 63 64 (*) is the default selection. 65 """ 66 self.test.wait_for('firmware_screen') 67 for _ in range(3, 0, -1): 68 self.menu_up() 69 self.test.wait_for('confirm_screen') 70 self.menu_select('Selecting "Developer Options"...') 71 self.test.wait_for('confirm_screen') 72 self.menu_select('Selecting "Boot From Internal Disk"...') 73 74 def trigger_dev_to_normal(self): 75 """Trigger dev-to-norm transition. 76 77 Menu items in developer warning screen: 78 0. Developer Options 79 1. Show Debug Info 80 2. Enable OS Verification 81 *3. Power Off 82 4. Language 83 84 Menu items in to-norm confirmation screen: 85 *0. Confirm Enabling OS Verification 86 1. Cancel 87 2. Power Off 88 3. Language 89 90 (*) is the default selection. 91 """ 92 self.test.wait_for('firmware_screen') 93 for _ in range(3, 2, -1): 94 self.menu_up() 95 self.test.wait_for('confirm_screen') 96 self.menu_select('Selecting "Enable OS Verification"...') 97 self.test.wait_for('confirm_screen') 98 self.menu_select('Selecing "Confirm Enabling OS Verification"...') 99 100 101class MenuNavigator(BaseMenuNavigator): 102 """Menu navigator for menu UI. 103 104 The "menu UI" aims to replace both "legacy clamshell UI" and "legacy 105 menu UI". See chromium:1033815 for the discussion about the naming. 106 """ 107 108 def _confirm_to_dev(self): 109 if self.faft_config.rec_button_dev_switch: 110 logging.info('Confirm to-dev by RECOVERY button') 111 self.servo.toggle_recovery_switch() 112 elif self.faft_config.power_button_dev_switch: 113 logging.info('Confirm to-dev by POWER button') 114 self.servo.power_normal_press() 115 else: 116 self.menu_select('Confirm to-dev by menu selection') 117 118 def trigger_rec_to_dev(self): 119 """Trigger to-dev transition. 120 121 Menu items in recovery select screen: 122 0. Language 123 1. Recovery using phone 124 2. Recovery using external disk 125 3. Launch diagnostics 126 4. Advanced options 127 5. Power off 128 129 Menu items in advanced options screen: 130 0. Language 131 *1. Enable developer mode 132 2. Back 133 3. Power off 134 135 Menu items in to-dev screen: 136 0. Language 137 *1. Confirm 138 2. Cancel 139 3. Power off 140 141 (*) is the default selection. 142 """ 143 self.test.wait_for('firmware_screen') 144 # Since the default selection is unknown, navigate to item 5 first 145 for _ in range(0, 5): 146 self.menu_down() 147 self.test.wait_for('confirm_screen') 148 # Navigate to "Advanced options" 149 self.menu_up() 150 self.test.wait_for('confirm_screen') 151 self.menu_select('Selecting "Advanced options"...') 152 self.test.wait_for('confirm_screen') 153 self.menu_select('Selecting "Enable developer mode"...') 154 self.test.wait_for('confirm_screen') 155 # Confirm to-dev transition 156 self._confirm_to_dev() 157 158 def dev_boot_from_internal(self): 159 """Boot from internal disk in developer mode. 160 161 Menu items in developer mode screen: 162 0. Language 163 1. Return to secure mode 164 2. Boot from internal disk 165 3. Boot from external disk 166 4. Advanced options 167 5. Power off 168 """ 169 self.test.wait_for('firmware_screen') 170 # Since the default selection is unknown, navigate to item 0 first 171 for _ in range(5, 0, -1): 172 self.menu_up() 173 self.test.wait_for('confirm_screen') 174 # Navigate to "Boot from internal disk" 175 for _ in range(0, 2): 176 self.menu_down() 177 self.test.wait_for('confirm_screen') 178 self.menu_select('Selecting "Boot from internal disk"...') 179 180 def trigger_dev_to_normal(self): 181 """Trigger dev-to-norm transition. 182 183 Menu items in developer mode screen: 184 0. Language 185 1. Return to secure mode 186 2. Boot from internal disk 187 3. Boot from external disk 188 4. Advanced options 189 5. Power off 190 191 Menu items in to-norm screen: 192 0. Language 193 *1. Confirm 194 2. Cancel 195 3. Power off 196 197 (*) is the default selection. 198 """ 199 self.test.wait_for('firmware_screen') 200 # Since the default selection is unknown, navigate to item 0 first 201 for _ in range(5, 0, -1): 202 self.menu_up() 203 self.test.wait_for('confirm_screen') 204 # Navigate to "Return to secure mode" 205 self.menu_down() 206 self.test.wait_for('confirm_screen') 207 self.menu_select('Selecting "Return to secure mode"...') 208 self.test.wait_for('confirm_screen') 209 self.menu_select('Selecing "Confirm"...') 210 211 212class firmware_MenuModeTransition(FirmwareTest): 213 """ 214 Servo based test for manual mode transitions through the UI menu. 215 """ 216 version = 1 217 218 def initialize(self, host, cmdline_args, ec_wp=None): 219 super(firmware_MenuModeTransition, self).initialize( 220 host, cmdline_args, ec_wp=ec_wp) 221 self.switcher.setup_mode('normal') 222 self.setup_usbkey(usbkey=False) 223 224 def run_once(self): 225 """Method which actually runs the test.""" 226 self.check_state((self.checkers.mode_checker, 'normal')) 227 228 if self.faft_config.mode_switcher_type == 'menu_switcher': 229 navigator = MenuNavigator(self) 230 elif (self.faft_config.mode_switcher_type == 231 'tablet_detachable_switcher'): 232 navigator = LegacyMenuNavigator(self) 233 else: 234 raise error.TestNAError('Test skipped for menuless UI') 235 236 # Trigger to-dev by menu navigation 237 logging.info('Trigger to-dev by menu navigation.') 238 self.switcher.enable_rec_mode_and_reboot(usb_state='host') 239 self.switcher.wait_for_client_offline() 240 navigator.trigger_rec_to_dev() 241 242 # Now the device should be in dev mode screen 243 navigator.dev_boot_from_internal() 244 self.switcher.wait_for_client() 245 246 logging.info('Expected dev mode boot.') 247 self.check_state((self.checkers.mode_checker, 'dev')) 248 249 # Trigger to-norm by menu navigation 250 logging.info('Trigger to-norm by menu navigation.') 251 self.switcher.disable_rec_mode_and_reboot() 252 self.switcher.wait_for_client_offline() 253 navigator.trigger_dev_to_normal() 254 self.switcher.wait_for_client() 255 256 logging.info('Expected normal mode boot, done.') 257 self.check_state((self.checkers.mode_checker, 'normal')) 258