firmware_test.py revision 18c4e1643b3ac6f6a201e2008020cdae8c590a7d
1086aeeaae12517475c22695a200be45495516549Ben Murdoch# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
2b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch# Use of this source code is governed by a BSD-style license that can be
3b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch# found in the LICENSE file.
4b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
5b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport ast
6b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport ctypes
7b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport logging
8b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport os
9b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport re
10b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport time
11b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochimport uuid
12b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
13b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.client.bin import utils
14b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.client.common_lib import error
15b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server import test
16b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server.cros import vboot_constants as vboot
17b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server.cros.faft.config.config import Config as FAFTConfig
18b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server.cros.faft.rpc_proxy import RPCProxy
19b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server.cros.faft.utils import mode_switcher
20b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server.cros.faft.utils.faft_checkers import FAFTCheckers
21b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochfrom autotest_lib.server.cros.servo import chrome_ec
22b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
23b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
24b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochclass ConnectionError(Exception):
25b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    """Raised on an error of connecting DUT."""
26b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    pass
27b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
28b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
29b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochclass FAFTBase(test.test):
30b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    """The base class of FAFT classes.
31b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
32b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    It launches the FAFTClient on DUT, such that the test can access its
33086aeeaae12517475c22695a200be45495516549Ben Murdoch    firmware functions and interfaces. It also provides some methods to
34b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    handle the reboot mechanism, in order to ensure FAFTClient is still
35b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    connected after reboot.
36b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    """
37b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def initialize(self, host):
38b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Create a FAFTClient object and install the dependency."""
39b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo = host.servo
40b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo.initialize_dut()
41b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._client = host
42b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client = RPCProxy(host)
43b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.lockfile = '/var/tmp/faft/lock'
44b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
45b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def wait_for_client(self, timeout=100):
46b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Wait for the client to come back online.
47b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
48b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        New remote processes will be launched if their used flags are enabled.
49b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
50b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param timeout: Time in seconds to wait for the client SSH daemon to
51b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        come up.
52b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise ConnectionError: Failed to connect DUT.
53b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
54b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if not self._client.wait_up(timeout):
55b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise ConnectionError()
56b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Check the FAFT client is avaiable.
57b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.is_available()
58b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
59b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def wait_for_client_offline(self, timeout=60, orig_boot_id=None):
60b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Wait for the client to come offline.
61b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
62b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param timeout: Time in seconds to wait the client to come offline.
63b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param orig_boot_id: A string containing the original boot id.
64b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise ConnectionError: Failed to connect DUT.
65b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
66b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # When running against panther, we see that sometimes
67b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # ping_wait_down() does not work correctly. There needs to
68b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # be some investigation to the root cause.
69b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # If we sleep for 120s before running get_boot_id(), it
70b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # does succeed. But if we change this to ping_wait_down()
71b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # there are implications on the wait time when running
72b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # commands at the fw screens.
7344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if not self._client.ping_wait_down(timeout):
74b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if orig_boot_id and self._client.get_boot_id() != orig_boot_id:
75b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                logging.warn('Reboot done very quickly.')
761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                return
771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            raise ConnectionError()
78b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
79b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
80b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdochclass FirmwareTest(FAFTBase):
81b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    """
82b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    Base class that sets up helper objects/functions for firmware tests.
83b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
84b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    TODO: add documentaion as the FAFT rework progresses.
85b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    """
86b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    version = 1
87b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    # Mapping of partition number of kernel and rootfs.
89b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
90b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
91b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
92b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
9344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    CHROMEOS_MAGIC = "CHROMEOS"
95b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    CORRUPTED_MAGIC = "CORRUPTD"
96b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
97e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    _SERVOD_LOG = '/var/log/servod.log'
98b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
99b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    _ROOTFS_PARTITION_NUMBER = 3
100b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    _backup_firmware_sha = ()
1021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    _backup_kernel_sha = dict()
1031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    _backup_cgpt_attr = dict()
1041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    _backup_gbb_flags = None
105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    _backup_dev_mode = None
106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
107086aeeaae12517475c22695a200be45495516549Ben Murdoch    # Class level variable, keep track the states of one time setup.
108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    # This variable is preserved across tests which inherit this class.
109b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    _global_setup_done = {
110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        'gbb_flags': False,
111b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        'reimage': False,
112b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        'usb_check': False,
113b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    }
114b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    @classmethod
1161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def check_setup_done(cls, label):
1179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        """Check if the given setup is done.
118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param label: The label of the setup.
120b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
121b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        return cls._global_setup_done[label]
12244f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    @classmethod
124b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def mark_setup_done(cls, label):
125b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Mark the given setup done.
126b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
12744f0eee88ff00398ff7f715fab053374d808c90dSteve Block        @param label: The label of the setup.
128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
12944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        cls._global_setup_done[label] = True
130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    @classmethod
132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def unmark_setup_done(cls, label):
133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Mark the given setup not done.
134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param label: The label of the setup.
136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        cls._global_setup_done[label] = False
1381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
139b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def initialize(self, host, cmdline_args, ec_wp=None):
140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        super(FirmwareTest, self).initialize(host)
141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.run_id = str(uuid.uuid4())
142b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('FirmwareTest initialize begin (id=%s)', self.run_id)
143b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Parse arguments from command line
144b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        args = {}
145b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.power_control = host.POWER_CONTROL_RPM
146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        for arg in cmdline_args:
147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            match = re.search("^(\w+)=(.+)", arg)
1481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            if match:
149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                args[match.group(1)] = match.group(2)
150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if 'power_control' in args:
151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.power_control = args['power_control']
15244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            if self.power_control not in host.POWER_CONTROL_VALID_ARGS:
153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                raise error.TestError('Valid values for --args=power_control '
154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                      'are %s. But you entered wrong argument '
1551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                      'as "%s".'
15644f0eee88ff00398ff7f715fab053374d808c90dSteve Block                                       % (host.POWER_CONTROL_VALID_ARGS,
1571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                       self.power_control))
158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
159b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_config = FAFTConfig(
160b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.faft_client.system.get_platform_name())
16144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        self.checkers = FAFTCheckers(self)
162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher = mode_switcher.create_mode_switcher(self)
163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.faft_config.chrome_ec:
165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.ec = chrome_ec.ChromeEC(self.servo)
166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
167b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._setup_uart_capture()
168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._setup_servo_log()
169b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._record_system_info()
170b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.fw_vboot2 = self.faft_client.system.get_fw_vboot2()
171b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('vboot version: %d', 2 if self.fw_vboot2 else 1)
172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.fw_vboot2:
173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.faft_client.system.set_fw_try_next('A')
174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if self.faft_client.system.get_crossystem_value('mainfw_act') == 'B':
175b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                logging.info('mainfw_act is B. rebooting to set it A')
176b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.switcher.mode_aware_reboot()
177b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._setup_gbb_flags()
178b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._stop_service('update-engine')
179b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._create_faft_lockfile()
180b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._setup_ec_write_protect(ec_wp)
181b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # See chromium:239034 regarding needing this sync.
182b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.blocking_sync()
183b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('FirmwareTest initialize done (id=%s)', self.run_id)
184b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
185b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def cleanup(self):
186b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Autotest cleanup function."""
187b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Unset state checker in case it's set by subclass
188b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('FirmwareTest cleaning up (id=%s)', self.run_id)
189b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        try:
190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.faft_client.system.is_available()
191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        except:
192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            # Remote is not responding. Revive DUT so that subsequent tests
1931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            # don't fail.
1941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            self._restore_routine_from_timeout()
1951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.switcher.restore_mode()
1961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self._restore_ec_write_protect()
197b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._restore_gbb_flags()
198b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._start_service('update-engine')
199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._remove_faft_lockfile()
200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._record_servo_log()
201b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._record_faft_client_log()
202b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._cleanup_uart_capture()
203b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        super(FirmwareTest, self).cleanup()
204b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('FirmwareTest cleanup done (id=%s)', self.run_id)
205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _record_system_info(self):
207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Record some critical system info to the attr keyval.
208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
209b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        This info is used by generate_test_report later.
210b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
211b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.write_attr_keyval({
212b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            'fw_version': self.faft_client.ec.get_version(),
2131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            'hwid': self.faft_client.system.get_crossystem_value('hwid'),
2141e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            'fwid': self.faft_client.system.get_crossystem_value('fwid'),
2151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        })
216b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
217b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def invalidate_firmware_setup(self):
218b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Invalidate all firmware related setup state.
219b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
220b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        This method is called when the firmware is re-flashed. It resets all
221b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        firmware related setup states so that the next test setup properly
222b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        again.
223b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.unmark_setup_done('gbb_flags')
225b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
226b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _retrieve_recovery_reason_from_trap(self):
227b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Try to retrieve the recovery reason from a trapped recovery screen.
228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @return: The recovery_reason, 0 if any error.
230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        recovery_reason = 0
232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Try to retrieve recovery reason...')
233b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.servo.get_usbkey_direction() == 'dut':
234b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.switcher.bypass_rec_mode()
2351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        else:
2361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            self.servo.switch_usbkey('dut')
2371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        try:
2391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            self.wait_for_client()
2401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            lines = self.faft_client.system.run_shell_command_get_output(
2411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                        'crossystem recovery_reason')
2421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            recovery_reason = int(lines[0])
2431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            logging.info('Got the recovery reason %d.', recovery_reason)
2441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        except ConnectionError:
2451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            logging.error('Failed to get the recovery reason due to connection '
2461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                          'error.')
2471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        return recovery_reason
2481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2491e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def _reset_client(self):
2501e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """Reset client to a workable state.
2511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        This method is called when the client is not responsive. It may be
2531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        caused by the following cases:
2541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
2551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          - corrupted firmware;
2561e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block          - corrutped OS image.
257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
2581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # DUT may halt on a firmware screen. Try cold reboot.
259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Try cold reboot...')
260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher.mode_aware_reboot(reboot_type='cold',
261b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                        sync_before_boot=False,
2621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                        wait_for_dut_up=False)
2631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.wait_for_client_offline()
264b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher.bypass_dev_mode()
265b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        try:
266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.wait_for_client()
2671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            return
268b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        except ConnectionError:
269b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.warn('Cold reboot doesn\'t help, still connection error.')
270b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
2711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # DUT may be broken by a corrupted firmware. Restore firmware.
272b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # We assume the recovery boot still works fine. Since the recovery
2731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # code is in RO region and all FAFT tests don't change the RO region
2741e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # except GBB.
275b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if self.is_firmware_saved():
276b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._ensure_client_in_recovery()
277b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.info('Try restore the original firmware...')
278b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if self.is_firmware_changed():
279b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                try:
280b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    self.restore_firmware()
2811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                    return
282b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                except ConnectionError:
283b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    logging.warn('Restoring firmware doesn\'t help, still '
284b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 'connection error.')
2851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
2861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # Perhaps it's kernel that's broken. Let's try restoring it.
287b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if self.is_kernel_saved():
288b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._ensure_client_in_recovery()
289b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.info('Try restore the original kernel...')
2901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            if self.is_kernel_changed():
2911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                try:
2921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                    self.restore_kernel()
2931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                    return
2941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                except ConnectionError:
295b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    logging.warn('Restoring kernel doesn\'t help, still '
296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 'connection error.')
297b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
2981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # DUT may be broken by a corrupted OS image. Restore OS image.
2991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self._ensure_client_in_recovery()
3001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info('Try restore the OS image...')
3011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.faft_client.system.run_shell_command('chromeos-install --yes')
302b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.switcher.mode_aware_reboot(wait_for_dut_up=False)
303b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.wait_for_client_offline()
304b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.switcher.bypass_dev_mode()
305b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        try:
306b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.wait_for_client()
307b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.info('Successfully restore OS image.')
308b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return
309b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        except ConnectionError:
310b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.warn('Restoring OS image doesn\'t help, still connection '
311b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                         'error.')
312b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
313b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def _ensure_client_in_recovery(self):
314b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Ensure client in recovery boot; reboot into it if necessary.
315b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
316b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @raise TestError: if failed to boot the USB image.
317b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
318b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        logging.info('Try boot into USB image...')
319b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.switcher.reboot_to_mode(to_mode='rec', sync_before_boot=False,
320b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                     wait_for_dut_up=False)
321b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.servo.switch_usbkey('host')
322b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.switcher.bypass_rec_mode()
323b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        try:
324b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.wait_for_client()
325b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        except ConnectionError:
326b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            raise error.TestError('Failed to boot the USB image.')
327b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
328b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _restore_routine_from_timeout(self):
329b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """A routine to try to restore the system from a timeout error.
330b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
331b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        This method is called when FAFT failed to connect DUT after reboot.
332b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
333b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise TestFail: This exception is already raised, with a decription
334b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                         why it failed.
335b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
336b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # DUT is disconnected. Capture the UART output for debug.
337b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._record_uart_capture()
338b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
339b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # TODO(waihong@chromium.org): Implement replugging the Ethernet to
340b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # identify if it is a network flaky.
341b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
342b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        recovery_reason = self._retrieve_recovery_reason_from_trap()
343b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
344b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Reset client to a workable state.
345b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._reset_client()
346b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
347b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Raise the proper TestFail exception.
348b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if recovery_reason:
349b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise error.TestFail('Trapped in the recovery screen (reason: %d) '
350b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 'and timed out' % recovery_reason)
351b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        else:
352b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise error.TestFail('Timed out waiting for DUT reboot')
353b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
354b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def assert_test_image_in_usb_disk(self, usb_dev=None):
355b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Assert an USB disk plugged-in on servo and a test image inside.
356b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
357b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
358b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        If None, it is detected automatically.
359b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise TestError: if USB disk not detected or not a test image.
360b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
361b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.check_setup_done('usb_check'):
362b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return
363b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if usb_dev:
364b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            assert self.servo.get_usbkey_direction() == 'host'
365b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        else:
366b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo.switch_usbkey('host')
367b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            usb_dev = self.servo.probe_host_usb_dev()
368b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if not usb_dev:
369b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                raise error.TestError(
370b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        'An USB disk should be plugged in the servo board.')
371b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
372b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        rootfs = '%s%s' % (usb_dev, self._ROOTFS_PARTITION_NUMBER)
373b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        logging.info('usb dev is %s', usb_dev)
374b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        tmpd = self.servo.system_output('mktemp -d -t usbcheck.XXXX')
375b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo.system('mount -o ro %s %s' % (rootfs, tmpd))
376b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
377b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        try:
378b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            usb_lsb = self.servo.system_output('cat %s' %
379b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                os.path.join(tmpd, 'etc/lsb-release'))
380b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.debug('Dumping lsb-release on USB stick:\n%s', usb_lsb)
381b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            dut_lsb = '\n'.join(self.faft_client.system.
382b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                run_shell_command_get_output('cat /etc/lsb-release'))
383b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.debug('Dumping lsb-release on DUT:\n%s', dut_lsb)
384b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if not re.search(r'RELEASE_DESCRIPTION=.*(T|t)est', usb_lsb):
385b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                raise error.TestError('USB stick in servo is no test image')
386b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            usb_board = re.search(r'BOARD=(.*)', usb_lsb).group(1)
387b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            dut_board = re.search(r'BOARD=(.*)', dut_lsb).group(1)
388b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if usb_board != dut_board:
389b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                raise error.TestError('USB stick in servo contains a %s '
390b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    'image, but DUT is a %s' % (usb_board, dut_board))
391b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        finally:
392b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            for cmd in ('umount %s' % rootfs, 'sync', 'rm -rf %s' % tmpd):
393b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.servo.system(cmd)
394b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
395b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.mark_setup_done('usb_check')
396b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
397b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def setup_usbkey(self, usbkey, host=None):
398b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Setup the USB disk for the test.
399b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
400b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        It checks the setup of USB disk and a valid ChromeOS test image inside.
401b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        It also muxes the USB disk to either the host or DUT by request.
402b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
403b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param usbkey: True if the USB disk is required for the test, False if
404b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                       not required.
405b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param host: Optional, True to mux the USB disk to host, False to mux it
406b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    to DUT, default to do nothing.
407b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
408b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if usbkey:
409b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.assert_test_image_in_usb_disk()
410b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        elif host is None:
411b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            # USB disk is not required for the test. Better to mux it to host.
412b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            host = True
413b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
414b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if host is True:
415b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo.switch_usbkey('host')
416b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        elif host is False:
417b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo.switch_usbkey('dut')
418b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
419b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def get_usbdisk_path_on_dut(self):
420b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Get the path of the USB disk device plugged-in the servo on DUT.
421b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
422b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Returns:
423b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          A string representing USB disk path, like '/dev/sdb', or None if
424b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch          no USB disk is found.
425b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
426b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        cmd = 'ls -d /dev/s*[a-z]'
427b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        original_value = self.servo.get_usbkey_direction()
428b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
429b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # Make the dut unable to see the USB disk.
430b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo.switch_usbkey('off')
431b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        no_usb_set = set(
432b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.faft_client.system.run_shell_command_get_output(cmd))
433b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
434b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Make the dut able to see the USB disk.
4351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.servo.switch_usbkey('dut')
436b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        time.sleep(self.faft_config.usb_plug)
4371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        has_usb_set = set(
4381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            self.faft_client.system.run_shell_command_get_output(cmd))
4391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
4401e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # Back to its original value.
441b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if original_value != self.servo.get_usbkey_direction():
442b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo.switch_usbkey(original_value)
443b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
4441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        diff_set = has_usb_set - no_usb_set
4451e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if len(diff_set) == 1:
446b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return diff_set.pop()
447b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        else:
448b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return None
449b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
450b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _create_faft_lockfile(self):
451b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Creates the FAFT lockfile."""
452b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        logging.info('Creating FAFT lockfile...')
453b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        command = 'touch %s' % (self.lockfile)
454b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command(command)
455b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
456b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _remove_faft_lockfile(self):
457b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Removes the FAFT lockfile."""
4581e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info('Removing FAFT lockfile...')
459b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        command = 'rm -f %s' % (self.lockfile)
460b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command(command)
461b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
462b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def _stop_service(self, service):
463b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Stops a upstart service on the client.
464b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
465b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param service: The name of the upstart service.
466b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
467b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        logging.info('Stopping %s...', service)
468b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        command = 'status %s | grep stop || stop %s' % (service, service)
469b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.faft_client.system.run_shell_command(command)
470b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
471b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _start_service(self, service):
472b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Starts a upstart service on the client.
473b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
474b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param service: The name of the upstart service.
475b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
476b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Starting %s...', service)
4771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        command = 'status %s | grep start || start %s' % (service, service)
478b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command(command)
479b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
480b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _write_gbb_flags(self, new_flags):
481b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Write the GBB flags to the current firmware.
4821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
4831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @param new_flags: The flags to write.
484b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
485b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        gbb_flags = self.faft_client.bios.get_gbb_flags()
486b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if gbb_flags == new_flags:
487b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return
4881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info('Changing GBB flags from 0x%x to 0x%x.',
489b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                     gbb_flags, new_flags)
490b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command(
491b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                '/usr/share/vboot/bin/set_gbb_flags.sh 0x%x' % new_flags)
492b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.bios.reload()
493b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
494b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
495b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.switcher.mode_aware_reboot()
496b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
497b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def clear_set_gbb_flags(self, clear_mask, set_mask):
498b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Clear and set the GBB flags in the current flashrom.
499b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
500b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param clear_mask: A mask of flags to be cleared.
501b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param set_mask: A mask of flags to be set.
502b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
503b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        gbb_flags = self.faft_client.bios.get_gbb_flags()
504b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
505b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._write_gbb_flags(new_flags)
506b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
507b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def check_ec_capability(self, required_cap=None, suppress_warning=False):
508b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Check if current platform has required EC capabilities.
509b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
510b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param required_cap: A list containing required EC capabilities. Pass in
511b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             None to only check for presence of Chrome EC.
512b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param suppress_warning: True to suppress any warning messages.
513b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @return: True if requirements are met. Otherwise, False.
514b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
515b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if not self.faft_config.chrome_ec:
516b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if not suppress_warning:
517b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                logging.warn('Requires Chrome EC to run this test.')
5181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            return False
519b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
520b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if not required_cap:
521b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return True
522b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
523b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        for cap in required_cap:
524b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if cap not in self.faft_config.ec_capability:
525b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                if not suppress_warning:
526b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    logging.warn('Requires EC capability "%s" to run this '
527b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 'test.', cap)
528b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                return False
529b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
530b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        return True
531b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
532b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def check_root_part_on_non_recovery(self, part):
533b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Check the partition number of root device and on normal/dev boot.
534b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
535b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param part: A string of partition number, e.g.'3'.
536b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @return: True if the root device matched and on normal/dev boot;
537b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                 otherwise, False.
538b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
539b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        return self.checkers.root_part_checker(part) and \
540b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                self.checkers.crossystem_checker({
541b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    'mainfw_type': ('normal', 'developer'),
542b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                })
543b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
544b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _join_part(self, dev, part):
545b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Return a concatenated string of device and partition number.
546b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
547b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param dev: A string of device, e.g.'/dev/sda'.
548b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param part: A string of partition number, e.g.'3'.
549b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @return: A concatenated string of device and partition number,
550b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                 e.g.'/dev/sda3'.
551b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
552b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        >>> seq = FirmwareTest()
553b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        >>> seq._join_part('/dev/sda', '3')
554b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        '/dev/sda3'
555b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        >>> seq._join_part('/dev/mmcblk0', '2')
556b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        '/dev/mmcblk0p2'
557b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
558b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if 'mmcblk' in dev:
559b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return dev + 'p' + part
560b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        else:
561b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return dev + part
562b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
563b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def copy_kernel_and_rootfs(self, from_part, to_part):
564b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Copy kernel and rootfs from from_part to to_part.
565b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
566b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param from_part: A string of partition number to be copied from.
567b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param to_part: A string of partition number to be copied to.
568b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
569b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        root_dev = self.faft_client.system.get_root_dev()
570b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Copying kernel from %s to %s. Please wait...',
571b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                     from_part, to_part)
572b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
573b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
574b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
5751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info('Copying rootfs from %s to %s. Please wait...',
576b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                     from_part, to_part)
577b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
578b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
579b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
580b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
581b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def ensure_kernel_boot(self, part):
582b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Ensure the request kernel boot.
583b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
584b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        If not, it duplicates the current kernel to the requested kernel
585b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        and sets the requested higher priority to ensure it boot.
586b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
587b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param part: A string of kernel partition number or 'a'/'b'.
588b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
589b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if not self.checkers.root_part_checker(part):
590b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if self.faft_client.kernel.diff_a_b():
591b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.copy_kernel_and_rootfs(
5921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                        from_part=self.OTHER_KERNEL_MAP[part],
593b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        to_part=part)
594b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.reset_and_prioritize_kernel(part)
595b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
596b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def set_hardware_write_protect(self, enable):
597b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Set hardware write protect pin.
598b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
599b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param enable: True if asserting write protect pin. Otherwise, False.
600b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
601b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo.set('fw_wp_vref', self.faft_config.wp_voltage)
602b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.servo.set('fw_wp_en', 'on')
603b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.servo.set('fw_wp', 'on' if enable else 'off')
604b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
605b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def set_ec_write_protect_and_reboot(self, enable):
606b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Set EC write protect status and reboot to take effect.
607b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
608b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        The write protect state is only activated if both hardware write
609b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        protect pin is asserted and software write protect flag is set.
610b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        This method asserts/deasserts hardware write protect pin first, and
6111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        set corresponding EC software write protect flag.
612b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
613b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        If the device uses non-Chrome EC, set the software write protect via
614b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        flashrom.
615b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
616b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        If the device uses Chrome EC, a reboot is required for write protect
617b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        to take effect. Since the software write protect flag cannot be unset
618b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if hardware write protect pin is asserted, we need to deasserted the
619b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        pin first if we are deactivating write protect. Similarly, a reboot
620b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        is required before we can modify the software flag.
621b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
622b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param enable: True if activating EC write protect. Otherwise, False.
623b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
624b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.set_hardware_write_protect(enable)
6251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if self.faft_config.chrome_ec:
626b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.set_chrome_ec_write_protect_and_reboot(enable)
627b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        else:
628b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.faft_client.ec.set_write_protect(enable)
629b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.switcher.mode_aware_reboot()
630b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
631b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def set_chrome_ec_write_protect_and_reboot(self, enable):
632b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Set Chrome EC write protect status and reboot to take effect.
633b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
634b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param enable: True if activating EC write protect. Otherwise, False.
635b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
6361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if enable:
637b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            # Set write protect flag and reboot to take effect.
638b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.ec.set_flash_write_protect(enable)
639b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.sync_and_ec_reboot()
640b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        else:
641b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            # Reboot after deasserting hardware write protect pin to deactivate
642b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            # write protect. And then remove software write protect flag.
643b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.sync_and_ec_reboot()
644b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.ec.set_flash_write_protect(enable)
645b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
646b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _setup_ec_write_protect(self, ec_wp):
647b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Setup for EC write-protection.
6481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
649b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        It makes sure the EC in the requested write-protection state. If not, it
650b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        flips the state. Flipping the write-protection requires DUT reboot.
651b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
652b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param ec_wp: True to request EC write-protected; False to request EC
653b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                      not write-protected; None to do nothing.
654b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
655b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if ec_wp is None:
656b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self._old_ec_wp = None
657b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return
658b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
659b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if ec_wp != self._old_ec_wp:
660b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info('The test required EC is %swrite-protected. Reboot '
661b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                         'and flip the state.', '' if ec_wp else 'not ')
662b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.switcher.mode_aware_reboot(
663b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    'custom',
664b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                     lambda:self.set_ec_write_protect_and_reboot(ec_wp))
665b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
666b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def _restore_ec_write_protect(self):
667b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Restore the original EC write-protection."""
668b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if (not hasattr(self, '_old_ec_wp')) or (self._old_ec_wp is None):
669b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return
670b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if not self.checkers.crossystem_checker(
671b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
672b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info('Restore original EC write protection and reboot.')
673b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.switcher.mode_aware_reboot(
674b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    'custom',
675b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    lambda:self.set_ec_write_protect_and_reboot(
676b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                            self._old_ec_wp))
677b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
678b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _setup_uart_capture(self):
679b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Setup the CPU/EC/PD UART capture."""
680b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.cpu_uart_file = os.path.join(self.resultsdir, 'cpu_uart.txt')
681b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.servo.set('cpu_uart_capture', 'on')
682b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.ec_uart_file = None
683b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.usbpd_uart_file = None
684b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.faft_config.chrome_ec:
685b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            try:
686b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.servo.set('ec_uart_capture', 'on')
687b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.ec_uart_file = os.path.join(self.resultsdir, 'ec_uart.txt')
688b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            except error.TestFail as e:
689b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                if 'No control named' in str(e):
690b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    logging.warn('The servod is too old that ec_uart_capture '
691b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                 'not supported.')
692b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            # Log separate PD console if supported
693b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if self.check_ec_capability(['usbpd_uart'], suppress_warning=True):
694b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                try:
695b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    self.servo.set('usbpd_uart_capture', 'on')
696b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    self.usbpd_uart_file = os.path.join(self.resultsdir,
697b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                                        'usbpd_uart.txt')
698b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                except error.TestFail as e:
699b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    if 'No control named' in str(e):
700b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                        logging.warn('The servod is too old that '
701b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                     'usbpd_uart_capture is not supported.')
7021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        else:
703b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info('Not a Google EC, cannot capture ec console output.')
704b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
705b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def _record_uart_capture(self):
706b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Record the CPU/EC/PD UART output stream to files."""
707b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.cpu_uart_file:
708b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            with open(self.cpu_uart_file, 'a') as f:
709b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                f.write(ast.literal_eval(self.servo.get('cpu_uart_stream')))
710b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.ec_uart_file and self.faft_config.chrome_ec:
711b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            with open(self.ec_uart_file, 'a') as f:
712b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                f.write(ast.literal_eval(self.servo.get('ec_uart_stream')))
7131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if (self.usbpd_uart_file and self.faft_config.chrome_ec and
714b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.check_ec_capability(['usbpd_uart'], suppress_warning=True)):
715b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            with open(self.usbpd_uart_file, 'a') as f:
716b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                f.write(ast.literal_eval(self.servo.get('usbpd_uart_stream')))
717b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
718b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _cleanup_uart_capture(self):
719b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Cleanup the CPU/EC/PD UART capture."""
720b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Flush the remaining UART output.
721b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._record_uart_capture()
722b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo.set('cpu_uart_capture', 'off')
723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.ec_uart_file and self.faft_config.chrome_ec:
724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo.set('ec_uart_capture', 'off')
7251e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if (self.usbpd_uart_file and self.faft_config.chrome_ec and
726b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.check_ec_capability(['usbpd_uart'], suppress_warning=True)):
727b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.servo.set('usbpd_uart_capture', 'off')
728b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
729b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def _fetch_servo_log(self):
730b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Fetch the servo log."""
731b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        cmd = '[ -e %s ] && cat %s || echo NOTFOUND' % ((self._SERVOD_LOG,) * 2)
732b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        servo_log = self.servo.system_output(cmd)
733b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        return None if servo_log == 'NOTFOUND' else servo_log
734b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
735b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _setup_servo_log(self):
736b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Setup the servo log capturing."""
737b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo_log_original_len = -1
738b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if self.servo.is_localhost():
739b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            # No servo log recorded when servod runs locally.
740b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return
741b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
742b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        servo_log = self._fetch_servo_log()
743b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if servo_log:
744b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo_log_original_len = len(servo_log)
745b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        else:
746b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.warn('Servo log file not found.')
747b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
748b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _record_servo_log(self):
749b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Record the servo log to the results directory."""
750b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.servo_log_original_len != -1:
751e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch            servo_log = self._fetch_servo_log()
752e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch            servo_log_file = os.path.join(self.resultsdir, 'servod.log')
753e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch            with open(servo_log_file, 'a') as f:
754e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch                f.write(servo_log[self.servo_log_original_len:])
755e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch
756e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch    def _record_faft_client_log(self):
757e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        """Record the faft client log to the results directory."""
758e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        client_log = self.faft_client.system.dump_log(True)
759e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        client_log_file = os.path.join(self.resultsdir, 'faft_client.log')
760e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch        with open(client_log_file, 'w') as f:
761e0cee9b3ed82e2391fd85d118aeaa4ea361c687dBen Murdoch            f.write(client_log)
7621e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
763b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _setup_gbb_flags(self):
764b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Setup the GBB flags for FAFT test."""
765b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if self.faft_config.gbb_version < 1.1:
766b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.info('Skip modifying GBB on versions older than 1.1.')
767b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return
768b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
769b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.check_setup_done('gbb_flags'):
770b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return
771b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
772b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._backup_gbb_flags = self.faft_client.bios.get_gbb_flags()
7731e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
774b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Set proper GBB flags for test.')
775b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
776b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
777b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
778b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK,
779b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
780b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
781b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.mark_setup_done('gbb_flags')
782b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
783b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def drop_backup_gbb_flags(self):
784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Drops the backup GBB flags.
7851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
7861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        This can be used when a test intends to permanently change GBB flags.
7871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
7881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self._backup_gbb_flags = None
7891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
7901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def _restore_gbb_flags(self):
7911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """Restore GBB flags to their original state."""
7921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if not self._backup_gbb_flags:
7931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            return
7941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self._write_gbb_flags(self._backup_gbb_flags)
7951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.unmark_setup_done('gbb_flags')
7961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
7971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def setup_tried_fwb(self, tried_fwb):
7981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """Setup for fw B tried state.
7991e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8001e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        It makes sure the system in the requested fw B tried state. If not, it
8011e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        tries to do so.
8021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
803b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param tried_fwb: True if requested in tried_fwb=1;
804b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                          False if tried_fwb=0.
805b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
806b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if tried_fwb:
807b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
808b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                logging.info(
809b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    'Firmware is not booted with tried_fwb. Reboot into it.')
810b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self.faft_client.system.set_try_fw_b()
811b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        else:
812b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
813b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                logging.info(
814b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    'Firmware is booted with tried_fwb. Reboot to clear.')
815b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
816b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def power_on(self):
817b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Switch DUT AC power on."""
818b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._client.power_on(self.power_control)
819b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
820b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def power_off(self):
821b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Switch DUT AC power off."""
822b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._client.power_off(self.power_control)
823b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
824b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def power_cycle(self):
825b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Power cycle DUT AC power."""
826b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._client.power_cycle(self.power_control)
827b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
828b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def setup_rw_boot(self, section='a'):
829b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Make sure firmware is in RW-boot mode.
830b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
831b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        If the given firmware section is in RO-boot mode, turn off the RO-boot
832b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        flag and reboot DUT into RW-boot mode.
8331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
834b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param section: A firmware section, either 'a' or 'b'.
835b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
836b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        flags = self.faft_client.bios.get_preamble_flags(section)
837b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if flags & vboot.PREAMBLE_USE_RO_NORMAL:
838b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            flags = flags ^ vboot.PREAMBLE_USE_RO_NORMAL
839b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.faft_client.bios.set_preamble_flags(section, flags)
840b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.switcher.mode_aware_reboot()
841b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
842b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def setup_kernel(self, part):
843b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Setup for kernel test.
844b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
845b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        It makes sure both kernel A and B bootable and the current boot is
846b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        the requested kernel part.
8471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
848b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param part: A string of kernel partition number or 'a'/'b'.
849b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
850b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.ensure_kernel_boot(part)
851b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        logging.info('Checking the integrity of kernel B and rootfs B...')
852b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if (self.faft_client.kernel.diff_a_b() or
853b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                not self.faft_client.rootfs.verify_rootfs('B')):
854b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info('Copying kernel and rootfs from A to B...')
855b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.copy_kernel_and_rootfs(from_part=part,
856b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                        to_part=self.OTHER_KERNEL_MAP[part])
857b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.reset_and_prioritize_kernel(part)
858b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
859b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def reset_and_prioritize_kernel(self, part):
860b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Make the requested partition highest priority.
8611e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
862b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        This function also reset kerenl A and B to bootable.
8631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8641e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @param part: A string of partition number to be prioritized.
8651e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
8661e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        root_dev = self.faft_client.system.get_root_dev()
867b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # Reset kernel A and B to bootable.
868b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command(
869b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['a'], root_dev))
8701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.faft_client.system.run_shell_command(
8711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['b'], root_dev))
872b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Set kernel part highest priority.
873b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command('cgpt prioritize -i%s %s' %
874b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                (self.KERNEL_MAP[part], root_dev))
8751e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
876b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def blocking_sync(self):
8771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """Run a blocking sync command."""
8781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # The double calls to sync fakes a blocking call
8791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # since the first call returns before the flush
8801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # is complete, but the second will wait for the
881b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # first to finish.
882b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command('sync')
883b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command('sync')
8841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
8851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # sync only sends SYNCHRONIZE_CACHE but doesn't
886b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # check the status. For mmc devices, use `mmc
887b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # status get` command to send an empty command to
888b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # wait for the disk to be available again.  For
889b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # other devices, hdparm sends TUR to check if
890086aeeaae12517475c22695a200be45495516549Ben Murdoch        # a device is ready for transfer operation.
891b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        root_dev = self.faft_client.system.get_root_dev()
892b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if 'mmcblk' in root_dev:
893b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.faft_client.system.run_shell_command('mmc status get %s' %
894b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                                                      root_dev)
895086aeeaae12517475c22695a200be45495516549Ben Murdoch        else:
896086aeeaae12517475c22695a200be45495516549Ben Murdoch            self.faft_client.system.run_shell_command('hdparm -f %s' % root_dev)
897086aeeaae12517475c22695a200be45495516549Ben Murdoch
898086aeeaae12517475c22695a200be45495516549Ben Murdoch    def wait_for_kernel_up(self):
899086aeeaae12517475c22695a200be45495516549Ben Murdoch        """
900086aeeaae12517475c22695a200be45495516549Ben Murdoch        Helper function that waits for the device to boot up to kernel.
901086aeeaae12517475c22695a200be45495516549Ben Murdoch        """
902086aeeaae12517475c22695a200be45495516549Ben Murdoch        logging.info("-[FAFT]-[ start wait_for_kernel_up ]---")
903086aeeaae12517475c22695a200be45495516549Ben Murdoch        # Wait for the system to respond to ping before attempting ssh
904b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if not self._client.ping_wait_up(90):
905b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.warning("-[FAFT]-[ system did not respond to ping ]")
906b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        try:
907b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.wait_for_client()
908b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            # Stop update-engine as it may change firmware/kernel.
909b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._stop_service('update-engine')
910b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        except ConnectionError:
911b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.error('wait_for_client() timed out.')
912b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._restore_routine_from_timeout()
913b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info("-[FAFT]-[ end wait_for_kernel_up ]-----")
914b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
915b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def sync_and_ec_reboot(self, flags=''):
916b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Request the client sync and do a EC triggered reboot.
917b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
9181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @param flags: Optional, a space-separated string of flags passed to EC
919b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                      reboot command, including:
920b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                          default: EC soft reboot;
921b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                          'hard': EC cold/hard reboot.
922b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
923b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.blocking_sync()
924b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.ec.reboot(flags)
925b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        time.sleep(self.faft_config.ec_boot_to_console)
926b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.check_lid_and_power_on()
927b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
928b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def reboot_and_reset_tpm(self):
929b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Reboot into recovery mode, reset TPM, then reboot back to disk."""
930b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher.reboot_to_mode(to_mode='rec')
931b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.faft_client.system.run_shell_command('chromeos-tpm-recovery')
932b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher.mode_aware_reboot()
933b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
934b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def full_power_off_and_on(self):
9351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """Shutdown the device by pressing power button and power on again."""
936b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        boot_id = self.get_bootid()
937b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Press power button to trigger Chrome OS normal shutdown process.
938b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # We use a customized delay since the normal-press 1.2s is not enough.
939b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.servo.power_key(self.faft_config.hold_pwr_button)
940b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # device can take 44-51 seconds to restart,
941b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # add buffer from the default timeout of 60 seconds.
942b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.wait_for_client_offline(timeout=100, orig_boot_id=boot_id)
943b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        time.sleep(self.faft_config.shutdown)
944b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Short press power button to boot DUT again.
945b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.servo.power_short_press()
946b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
947b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def check_lid_and_power_on(self):
948b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
949b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        On devices with EC software sync, system powers on after EC reboots if
950b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
951b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        This method checks lid switch state and presses power button if
952b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        necessary.
953b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
954b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.servo.get("lid_open") == "no":
9551e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            time.sleep(self.faft_config.software_sync)
956b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.servo.power_short_press()
957b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
958b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
959b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Modify the kernel header magic in USB stick.
960b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
961b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        The kernel header magic is the first 8-byte of kernel partition.
962b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        We modify it to make it fail on kernel verification check.
963b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
964b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
965b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param from_magic: A string of magic which we change it from.
966b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param to_magic: A string of magic which we change it to.
9671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @raise TestError: if failed to change magic.
968b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
969b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        assert len(from_magic) == 8
9701e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        assert len(to_magic) == 8
971b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # USB image only contains one kernel.
9721e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
973b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
974b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        current_magic = self.servo.system_output(read_cmd)
975b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if current_magic == to_magic:
9761e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            logging.info("The kernel magic is already %s.", current_magic)
977b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return
9781e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if current_magic != from_magic:
9791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            raise error.TestError("Invalid kernel image on USB: wrong magic.")
9801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
981b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Modify the kernel magic in USB, from %s to %s.',
982b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                     from_magic, to_magic)
9831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
984b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                     " 2>/dev/null" % (to_magic, kernel_part))
9851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.servo.system(write_cmd)
986b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
987b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if self.servo.system_output(read_cmd) != to_magic:
988b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise error.TestError("Failed to write new magic.")
9891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
990b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def corrupt_usb_kernel(self, usb_dev):
991b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
9921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
993b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
9941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
995b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
996b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                self.CORRUPTED_MAGIC)
997b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
9981e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def restore_usb_kernel(self, usb_dev):
999b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
1000b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1001b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
1002b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
1003b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
1004b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                self.CHROMEOS_MAGIC)
1005b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1006b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def _call_action(self, action_tuple, check_status=False):
1007b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Call the action function with/without arguments.
1008b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1009b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param action_tuple: A function, or a tuple (function, args, error_msg),
1010b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             in which, args and error_msg are optional. args is
10111e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                             either a value or a tuple if multiple arguments.
1012b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             This can also be a list containing multiple
1013b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             function or tuple. In this case, these actions are
1014b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             called in sequence.
1015b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param check_status: Check the return value of action function. If not
1016b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             succeed, raises a TestFail exception.
1017b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @return: The result value of the action function.
10181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @raise TestError: An error when the action function is not callable.
1019b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise TestFail: When check_status=True, action function not succeed.
1020b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
1021b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if isinstance(action_tuple, list):
1022086aeeaae12517475c22695a200be45495516549Ben Murdoch            return all([self._call_action(action, check_status=check_status)
1023086aeeaae12517475c22695a200be45495516549Ben Murdoch                        for action in action_tuple])
10241e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1025086aeeaae12517475c22695a200be45495516549Ben Murdoch        action = action_tuple
1026086aeeaae12517475c22695a200be45495516549Ben Murdoch        args = ()
10271e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        error_msg = 'Not succeed'
1028086aeeaae12517475c22695a200be45495516549Ben Murdoch        if isinstance(action_tuple, tuple):
1029b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            action = action_tuple[0]
1030b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            if len(action_tuple) >= 2:
1031b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                args = action_tuple[1]
10321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                if not isinstance(args, tuple):
1033b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    args = (args,)
1034b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if len(action_tuple) >= 3:
1035b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                error_msg = action_tuple[2]
1036b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1037b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if action is None:
10389fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block            return
10399fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
10409fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        if not callable(action):
1041b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise error.TestError('action is not callable!')
1042b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
104344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        info_msg = 'calling %s' % str(action)
10441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if args:
104544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            info_msg += ' with args %s' % str(args)
10461e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info(info_msg)
10471e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        ret = action(*args)
10481e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
104944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        if check_status and not ret:
105044f0eee88ff00398ff7f715fab053374d808c90dSteve Block            raise error.TestFail('%s: %s returning %s' %
10511e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                                 (error_msg, info_msg, str(ret)))
10521e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        return ret
10531e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
10541e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def run_shutdown_process(self, shutdown_action, pre_power_action=None,
10559fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block            post_power_action=None, shutdown_timeout=None):
1056b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Run shutdown_action(), which makes DUT shutdown, and power it on.
1057b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1058b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param shutdown_action: function which makes DUT shutdown, like
10599fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block                                pressing power key.
10609fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        @param pre_power_action: function which is called before next power on.
10619fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        @param post_power_action: function which is called after next power on.
1062b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param shutdown_timeout: a timeout to confirm DUT shutdown.
1063b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise TestFail: if the shutdown_action() failed to turn DUT off.
1064b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
1065b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._call_action(shutdown_action)
1066b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Wait to ensure DUT shut down...')
1067b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        try:
1068b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if shutdown_timeout is None:
1069b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                shutdown_timeout = self.faft_config.shutdown_timeout
1070b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self.wait_for_client(timeout=shutdown_timeout)
1071b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise error.TestFail(
1072b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    'Should shut the device down after calling %s.' %
1073b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    str(shutdown_action))
1074b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        except ConnectionError:
1075b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info(
1076b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                'DUT is surely shutdown. We are going to power it on again...')
10771e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1078b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if pre_power_action:
1079b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._call_action(pre_power_action)
1080b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.servo.power_short_press()
1081b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        if post_power_action:
1082b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self._call_action(post_power_action)
1083b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1084b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def get_bootid(self, retry=3):
1085b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
1086b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Return the bootid.
10871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
1088b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        boot_id = None
1089b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        while retry:
1090b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            try:
1091b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                boot_id = self._client.get_boot_id()
1092b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                break
1093b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            except error.AutoservRunError:
1094b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                retry -= 1
1095b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                if retry:
1096b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    logging.info('Retry to get boot_id...')
10971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                else:
1098b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    logging.warning('Failed to get boot_id.')
1099b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        logging.info('boot_id: %s', boot_id)
1100b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        return boot_id
1101b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1102b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def check_state(self, func):
1103b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
1104b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        Wrapper around _call_action with check_status set to True. This is a
1105b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        helper function to be used by tests and is currently implemented by
1106b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        calling _call_action with check_status=True.
1107b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1108b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        TODO: This function's arguments need to be made more stringent. And
11091e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        its functionality should be moved over to check functions directly in
1110b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        the future.
1111b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1112b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param func: A function, or a tuple (function, args, error_msg),
1113b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             in which, args and error_msg are optional. args is
1114b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                             either a value or a tuple if multiple arguments.
1115b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             This can also be a list containing multiple
1116b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             function or tuple. In this case, these actions are
1117b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             called in sequence.
1118b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @return: The result value of the action function.
1119b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @raise TestFail: If the function does notsucceed.
1120b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
11211e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info("-[FAFT]-[ start stepstate_checker ]----------")
1122b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._call_action(func, check_status=True)
1123b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info("-[FAFT]-[ end state_checker ]----------------")
1124b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1125b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def get_current_firmware_sha(self):
1126b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Get current firmware sha of body and vblock.
1127b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1128b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @return: Current firmware sha follows the order (
1129b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
1130b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
1131b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        current_firmware_sha = (self.faft_client.bios.get_sig_sha('a'),
1132b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                self.faft_client.bios.get_body_sha('a'),
1133b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                self.faft_client.bios.get_sig_sha('b'),
1134b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                                self.faft_client.bios.get_body_sha('b'))
1135b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if not all(current_firmware_sha):
1136b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            raise error.TestError('Failed to get firmware sha.')
1137b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        return current_firmware_sha
1138b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
11391e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def is_firmware_changed(self):
1140b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Check if the current firmware changed, by comparing its SHA.
1141b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1142b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @return: True if it is changed, otherwise Flase.
1143b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
1144b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        # Device may not be rebooted after test.
1145b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.faft_client.bios.reload()
1146b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1147b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        current_sha = self.get_current_firmware_sha()
1148b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1149b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if current_sha == self._backup_firmware_sha:
1150b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return False
1151b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        else:
1152b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
1153b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
1154b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
1155b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
1156b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info("Firmware changed:")
11571e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
1158b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
1159b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
1160b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
1161b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            return True
1162b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1163b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def backup_firmware(self, suffix='.original'):
1164b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Backup firmware to file, and then send it to host.
1165b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1166b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param suffix: a string appended to backup file name
11671e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
1168b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        remote_temp_dir = self.faft_client.system.create_temp_dir()
1169b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self.faft_client.bios.dump_whole(os.path.join(remote_temp_dir, 'bios'))
1170b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._client.get_file(os.path.join(remote_temp_dir, 'bios'),
1171b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                              os.path.join(self.resultsdir, 'bios' + suffix))
1172b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1173b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._backup_firmware_sha = self.get_current_firmware_sha()
1174b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Backup firmware stored in %s with suffix %s',
117544f0eee88ff00398ff7f715fab053374d808c90dSteve Block            self.resultsdir, suffix)
117644f0eee88ff00398ff7f715fab053374d808c90dSteve Block
117744f0eee88ff00398ff7f715fab053374d808c90dSteve Block    def is_firmware_saved(self):
117844f0eee88ff00398ff7f715fab053374d808c90dSteve Block        """Check if a firmware saved (called backup_firmware before).
117944f0eee88ff00398ff7f715fab053374d808c90dSteve Block
118044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        @return: True if the firmware is backuped; otherwise False.
118144f0eee88ff00398ff7f715fab053374d808c90dSteve Block        """
118244f0eee88ff00398ff7f715fab053374d808c90dSteve Block        return self._backup_firmware_sha != ()
118344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
118444f0eee88ff00398ff7f715fab053374d808c90dSteve Block    def clear_saved_firmware(self):
118544f0eee88ff00398ff7f715fab053374d808c90dSteve Block        """Clear the firmware saved by the method backup_firmware."""
118644f0eee88ff00398ff7f715fab053374d808c90dSteve Block        self._backup_firmware_sha = ()
118744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
118844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    def restore_firmware(self, suffix='.original'):
118944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        """Restore firmware from host in resultsdir.
1190b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1191b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param suffix: a string appended to backup file name
1192b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
11931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if not self.is_firmware_changed():
1194b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return
11951e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
11961e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # Backup current corrupted firmware.
11971e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.backup_firmware(suffix='.corrupt')
1198b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1199b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        # Restore firmware.
1200b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        remote_temp_dir = self.faft_client.system.create_temp_dir()
1201b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
1202b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                               os.path.join(remote_temp_dir, 'bios'))
12031e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12041e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.faft_client.bios.write_whole(
1205b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            os.path.join(remote_temp_dir, 'bios'))
1206b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher.mode_aware_reboot()
1207b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Successfully restore firmware.')
1208b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1209b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def setup_firmwareupdate_shellball(self, shellball=None):
12109fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        """Deside a shellball to use in firmware update test.
1211b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1212b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        Check if there is a given shellball, and it is a shell script. Then,
1213b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        send it to the remote host. Otherwise, use
1214b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        /usr/sbin/chromeos-firmwareupdate.
12159fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
12169fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        @param shellball: path of a shellball or default to None.
12179fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block
12189fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        @return: Path of shellball in remote host. If use default shellball,
1219b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                 reutrn None.
12209fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        """
12219fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        updater_path = None
12229fac840a46e8b7e26894f4792ba26dde14c56b04Steve Block        if shellball:
12231e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            # Determine the firmware file is a shellball or a raw binary.
1224b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            is_shellball = (utils.system_output("file %s" % shellball).find(
1225b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    "shell script") != -1)
1226b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if is_shellball:
1227b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                logging.info('Device will update firmware with shellball %s',
1228b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                             shellball)
1229b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                temp_dir = self.faft_client.system.create_temp_dir(
1230b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                            'shellball_')
1231b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                temp_shellball = os.path.join(temp_dir, 'updater.sh')
1232b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                self._client.send_file(shellball, temp_shellball)
123344f0eee88ff00398ff7f715fab053374d808c90dSteve Block                updater_path = temp_shellball
12341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            else:
123544f0eee88ff00398ff7f715fab053374d808c90dSteve Block                raise error.TestFail(
12361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                    'The given shellball is not a shell script.')
12371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            return updater_path
12381e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
123944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    def is_kernel_changed(self):
124044f0eee88ff00398ff7f715fab053374d808c90dSteve Block        """Check if the current kernel is changed, by comparing its SHA1 hash.
12411e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12421e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @return: True if it is changed; otherwise, False.
12431e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
12441e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        changed = False
1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        for p in ('A', 'B'):
1246b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            backup_sha = self._backup_kernel_sha.get(p, None)
1247b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            current_sha = self.faft_client.kernel.get_sha(p)
1248b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            if backup_sha != current_sha:
1249b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                changed = True
1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                logging.info('Kernel %s is changed', p)
1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        return changed
1252b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1253b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def backup_kernel(self, suffix='.original'):
1254b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Backup kernel to files, and the send them to host.
1255b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1256b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        @param suffix: a string appended to backup file name.
1257b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """
1258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        remote_temp_dir = self.faft_client.system.create_temp_dir()
125944f0eee88ff00398ff7f715fab053374d808c90dSteve Block        for p in ('A', 'B'):
1260b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            remote_path = os.path.join(remote_temp_dir, 'kernel_%s' % p)
126144f0eee88ff00398ff7f715fab053374d808c90dSteve Block            self.faft_client.kernel.dump(p, remote_path)
126244f0eee88ff00398ff7f715fab053374d808c90dSteve Block            self._client.get_file(
12631e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                    remote_path,
1264b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    os.path.join(self.resultsdir, 'kernel_%s%s' % (p, suffix)))
1265b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._backup_kernel_sha[p] = self.faft_client.kernel.get_sha(p)
1266b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Backup kernel stored in %s with suffix %s',
126744f0eee88ff00398ff7f715fab053374d808c90dSteve Block            self.resultsdir, suffix)
126844f0eee88ff00398ff7f715fab053374d808c90dSteve Block
126944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    def is_kernel_saved(self):
1270b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Check if kernel images are saved (backup_kernel called before).
12711e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1272b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @return: True if the kernel is saved; otherwise, False.
127344f0eee88ff00398ff7f715fab053374d808c90dSteve Block        """
127444f0eee88ff00398ff7f715fab053374d808c90dSteve Block        return len(self._backup_kernel_sha) != 0
127544f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1276b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def clear_saved_kernel(self):
1277b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Clear the kernel saved by backup_kernel()."""
1278b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self._backup_kernel_sha = dict()
12791e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12801e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block    def restore_kernel(self, suffix='.original'):
12811e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """Restore kernel from host in resultsdir.
12821e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12831e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        @param suffix: a string appended to backup file name.
12841e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        """
12851e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if not self.is_kernel_changed():
12861e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            return
12871e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12881e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # Backup current corrupted kernel.
12891e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.backup_kernel(suffix='.corrupt')
12901e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
12911e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        # Restore kernel.
12921e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        remote_temp_dir = self.faft_client.system.create_temp_dir()
12931e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        for p in ('A', 'B'):
12941e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            remote_path = os.path.join(remote_temp_dir, 'kernel_%s' % p)
1295b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch            self._client.send_file(
1296b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    os.path.join(self.resultsdir, 'kernel_%s%s' % (p, suffix)),
1297b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    remote_path)
1298b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            self.faft_client.kernel.write(p, remote_path)
1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
1300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        self.switcher.mode_aware_reboot()
1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('Successfully restored kernel.')
13021e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def backup_cgpt_attributes(self):
1304b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """Backup CGPT partition table attributes."""
1305b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        self._backup_cgpt_attr = self.faft_client.cgpt.get_attributes()
1306b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1307b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    def restore_cgpt_attributes(self):
1308b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        """Restore CGPT partition table attributes."""
1309b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        current_table = self.faft_client.cgpt.get_attributes()
1310b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        if current_table == self._backup_cgpt_attr:
1311b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch            return
1312b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        logging.info('CGPT table is changed. Original: %r. Current: %r.',
13131e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                     self._backup_cgpt_attr,
1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                     current_table)
13151e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.faft_client.cgpt.set_attributes(self._backup_cgpt_attr)
13161e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
13171e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        self.switcher.mode_aware_reboot()
13181e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        logging.info('Successfully restored CGPT table.')
1319b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1320b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    def try_fwb(self, count=0):
1321b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """set to try booting FWB count # times
13221e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
1323b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        Wrapper to set fwb_tries for vboot1 and fw_try_count,fw_try_next for
1324b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        vboot2
1325b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch
1326b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        @param count: an integer specifying value to program into
1327b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                      fwb_tries(vb1)/fw_try_next(vb2)
1328b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch        """
13291e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        if self.fw_vboot2:
13301e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            self.faft_client.system.set_fw_try_next('B', count)
13311e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block        else:
13321e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            # vboot1: we need to boot into fwb at least once
13331e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            if not count:
13341e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block                count = count + 1
13351e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block            self.faft_client.system.set_try_fw_b(count)
13361e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block
13371e0659c275bb392c045087af4f6b0d7565cb3d77Steve Block