105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally# Use of this source code is governed by a BSD-style license that can be
305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally# found in the LICENSE file.
405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport ast
605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport ctypes
705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport logging
805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport os
99a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tamimport pprint
1005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport re
1105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport time
1205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyimport uuid
1305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
14530490a25d656468ade45a4e165e683846ccd403Shelley Chenfrom threading import Timer
1505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyfrom autotest_lib.client.bin import utils
1605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyfrom autotest_lib.client.common_lib import error
17cab6be36a26c73dd4e6fa2f85ba48f50cfd92acaJ. Richard Barnettefrom autotest_lib.server import test
1805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyfrom autotest_lib.server.cros import vboot_constants as vboot
1905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyfrom autotest_lib.server.cros.faft.config.config import Config as FAFTConfig
2005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyfrom autotest_lib.server.cros.faft.rpc_proxy import RPCProxy
21ed4d67be4d0faa1a267d33e86905df1153d78333Tom Wai-Hong Tamfrom autotest_lib.server.cros.faft.utils import mode_switcher
22a57ff841026d6878e4ecbf993efd994638fde879J. Richard Barnettefrom autotest_lib.server.cros.faft.utils.faft_checkers import FAFTCheckers
2305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyfrom autotest_lib.server.cros.servo import chrome_ec
24fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scottfrom autotest_lib.server.cros.servo import chrome_usbpd
2505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
2619bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong TamConnectionError = mode_switcher.ConnectionError
2705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
2805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
29cab6be36a26c73dd4e6fa2f85ba48f50cfd92acaJ. Richard Barnetteclass FAFTBase(test.test):
3005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    """The base class of FAFT classes.
3105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
3205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    It launches the FAFTClient on DUT, such that the test can access its
3305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    firmware functions and interfaces. It also provides some methods to
3405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    handle the reboot mechanism, in order to ensure FAFTClient is still
3505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    connected after reboot.
3605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    """
3705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def initialize(self, host):
3805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Create a FAFTClient object and install the dependency."""
39cab6be36a26c73dd4e6fa2f85ba48f50cfd92acaJ. Richard Barnette        self.servo = host.servo
40cab6be36a26c73dd4e6fa2f85ba48f50cfd92acaJ. Richard Barnette        self.servo.initialize_dut()
4105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._client = host
4205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client = RPCProxy(host)
4310eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        self.lockfile = '/var/tmp/faft/lock'
4405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
4505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
4605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinallyclass FirmwareTest(FAFTBase):
4705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    """
48ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally    Base class that sets up helper objects/functions for firmware tests.
49ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally
50ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally    TODO: add documentaion as the FAFT rework progresses.
5105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    """
5205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    version = 1
5305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
5405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    # Mapping of partition number of kernel and rootfs.
5505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    KERNEL_MAP = {'a':'2', 'b':'4', '2':'2', '4':'4', '3':'2', '5':'4'}
5605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    ROOTFS_MAP = {'a':'3', 'b':'5', '2':'3', '4':'5', '3':'3', '5':'5'}
5705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    OTHER_KERNEL_MAP = {'a':'4', 'b':'2', '2':'4', '4':'2', '3':'4', '5':'2'}
5805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    OTHER_ROOTFS_MAP = {'a':'5', 'b':'3', '2':'5', '4':'3', '3':'5', '5':'3'}
5905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
6005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    CHROMEOS_MAGIC = "CHROMEOS"
6105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    CORRUPTED_MAGIC = "CORRUPTD"
6205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
63530490a25d656468ade45a4e165e683846ccd403Shelley Chen    # Delay for waiting client to return before EC suspend
64530490a25d656468ade45a4e165e683846ccd403Shelley Chen    EC_SUSPEND_DELAY = 5
65530490a25d656468ade45a4e165e683846ccd403Shelley Chen
66530490a25d656468ade45a4e165e683846ccd403Shelley Chen    # Delay between EC suspend and wake
67530490a25d656468ade45a4e165e683846ccd403Shelley Chen    WAKE_DELAY = 10
68530490a25d656468ade45a4e165e683846ccd403Shelley Chen
69530490a25d656468ade45a4e165e683846ccd403Shelley Chen    # Delay between closing and opening lid
70530490a25d656468ade45a4e165e683846ccd403Shelley Chen    LID_DELAY = 1
71530490a25d656468ade45a4e165e683846ccd403Shelley Chen
7205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _SERVOD_LOG = '/var/log/servod.log'
7305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
7405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _ROOTFS_PARTITION_NUMBER = 3
7505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
7605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _backup_firmware_sha = ()
7705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _backup_kernel_sha = dict()
7805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _backup_cgpt_attr = dict()
7905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _backup_gbb_flags = None
8005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _backup_dev_mode = None
8105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
8205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    # Class level variable, keep track the states of one time setup.
8305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    # This variable is preserved across tests which inherit this class.
8405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    _global_setup_done = {
8505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        'gbb_flags': False,
8605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        'reimage': False,
8705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        'usb_check': False,
8805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    }
8905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
9005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    @classmethod
9105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def check_setup_done(cls, label):
9205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check if the given setup is done.
9305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
9405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param label: The label of the setup.
9505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
9605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return cls._global_setup_done[label]
9705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
9805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    @classmethod
9905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def mark_setup_done(cls, label):
10005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Mark the given setup done.
10105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
10205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param label: The label of the setup.
10305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
10405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        cls._global_setup_done[label] = True
10505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
10605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    @classmethod
10705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def unmark_setup_done(cls, label):
10805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Mark the given setup not done.
10905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
11005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param label: The label of the setup.
11105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
11205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        cls._global_setup_done[label] = False
11305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
11405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def initialize(self, host, cmdline_args, ec_wp=None):
11505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        super(FirmwareTest, self).initialize(host)
11605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.run_id = str(uuid.uuid4())
11705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('FirmwareTest initialize begin (id=%s)', self.run_id)
11805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Parse arguments from command line
11905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        args = {}
12005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.power_control = host.POWER_CONTROL_RPM
12105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        for arg in cmdline_args:
12205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            match = re.search("^(\w+)=(.+)", arg)
12305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if match:
12405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                args[match.group(1)] = match.group(2)
12505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if 'power_control' in args:
12605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.power_control = args['power_control']
12705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if self.power_control not in host.POWER_CONTROL_VALID_ARGS:
12805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                raise error.TestError('Valid values for --args=power_control '
12905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                      'are %s. But you entered wrong argument '
13005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                      'as "%s".'
13105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                       % (host.POWER_CONTROL_VALID_ARGS,
13205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                       self.power_control))
13305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
13405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_config = FAFTConfig(
13505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                self.faft_client.system.get_platform_name())
1360cc9a4fe28f221cfc73bb35c30fa79338c4b43f1Tom Wai-Hong Tam        self.checkers = FAFTCheckers(self)
137ed4d67be4d0faa1a267d33e86905df1153d78333Tom Wai-Hong Tam        self.switcher = mode_switcher.create_mode_switcher(self)
13805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
13905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.faft_config.chrome_ec:
14005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.ec = chrome_ec.ChromeEC(self.servo)
141fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott        # Check for presence of a USBPD console
142fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott        if self.faft_config.chrome_usbpd:
143fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott            self.usbpd = chrome_usbpd.ChromeUSBPD(self.servo)
144fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott        elif self.faft_config.chrome_ec:
145fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott            # If no separate USBPD console, then PD exists on EC console
146fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott            self.usbpd = self.ec
147fe06ed8afdd7323a1f3ee60c746b5c0335c659c0Scott        # Get plankton console
14807a848f9faddc3302cf46e7d3238adcbabfaca6cScott        self.plankton = host.plankton
14907a848f9faddc3302cf46e7d3238adcbabfaca6cScott        self.plankton_host = host._plankton_host
15005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1518b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._setup_uart_capture()
1528b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._setup_servo_log()
1538b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._record_system_info()
154682a6d6a8f607fb70a7812194202826e1e6e85ccDaisuke Nojiri        self.fw_vboot2 = self.faft_client.system.get_fw_vboot2()
155682a6d6a8f607fb70a7812194202826e1e6e85ccDaisuke Nojiri        logging.info('vboot version: %d', 2 if self.fw_vboot2 else 1)
156682a6d6a8f607fb70a7812194202826e1e6e85ccDaisuke Nojiri        if self.fw_vboot2:
157682a6d6a8f607fb70a7812194202826e1e6e85ccDaisuke Nojiri            self.faft_client.system.set_fw_try_next('A')
158682a6d6a8f607fb70a7812194202826e1e6e85ccDaisuke Nojiri            if self.faft_client.system.get_crossystem_value('mainfw_act') == 'B':
159682a6d6a8f607fb70a7812194202826e1e6e85ccDaisuke Nojiri                logging.info('mainfw_act is B. rebooting to set it A')
1604777624b69b3b223a5d3c3abe86000783f6c0e96Tom Wai-Hong Tam                self.switcher.mode_aware_reboot()
1618b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._setup_gbb_flags()
1628b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._stop_service('update-engine')
16310eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        self._create_faft_lockfile()
1648b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._setup_ec_write_protect(ec_wp)
1651b7a48b6c4e7cd007039a22d47667ea126240aadYusuf Mohsinally        # See chromium:239034 regarding needing this sync.
1661bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        self.blocking_sync()
16705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('FirmwareTest initialize done (id=%s)', self.run_id)
16805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
16905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def cleanup(self):
17005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Autotest cleanup function."""
17105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Unset state checker in case it's set by subclass
17205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('FirmwareTest cleaning up (id=%s)', self.run_id)
17305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        try:
17405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.faft_client.system.is_available()
17505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        except:
17605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # Remote is not responding. Revive DUT so that subsequent tests
17705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # don't fail.
17805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._restore_routine_from_timeout()
1790cc9a4fe28f221cfc73bb35c30fa79338c4b43f1Tom Wai-Hong Tam        self.switcher.restore_mode()
1808b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._restore_ec_write_protect()
1818b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._restore_gbb_flags()
1828b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._start_service('update-engine')
18310eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        self._remove_faft_lockfile()
1848b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._record_servo_log()
1858b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._record_faft_client_log()
1868b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._cleanup_uart_capture()
18705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        super(FirmwareTest, self).cleanup()
18805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('FirmwareTest cleanup done (id=%s)', self.run_id)
18905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1908b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _record_system_info(self):
19105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Record some critical system info to the attr keyval.
19205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
193004a8cd96f2c9bc228ca9d58428e88d36fc36307Christopher Wiley        This info is used by generate_test_report later.
19405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
1959a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tam        system_info = {
19605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            'hwid': self.faft_client.system.get_crossystem_value('hwid'),
19732075c167a2d4252802645c46378b5d5bea91ae6Tom Wai-Hong Tam            'ec_version': self.faft_client.ec.get_version(),
19832075c167a2d4252802645c46378b5d5bea91ae6Tom Wai-Hong Tam            'ro_fwid': self.faft_client.system.get_crossystem_value('ro_fwid'),
19932075c167a2d4252802645c46378b5d5bea91ae6Tom Wai-Hong Tam            'rw_fwid': self.faft_client.system.get_crossystem_value('fwid'),
2009a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tam            'servod_version': self._client._servo_host.run(
2019a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tam                'servod --version').stdout.strip(),
2029a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tam        }
2039a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tam        logging.info('System info:\n' + pprint.pformat(system_info))
2049a10b9bfa8a160ca306e8f4ad9666c555ab3f94bTom Wai-Hong Tam        self.write_attr_keyval(system_info)
20505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
20605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def invalidate_firmware_setup(self):
20705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Invalidate all firmware related setup state.
20805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
20905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This method is called when the firmware is re-flashed. It resets all
21005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        firmware related setup states so that the next test setup properly
21105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        again.
21205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
21305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.unmark_setup_done('gbb_flags')
21405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
21505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def _retrieve_recovery_reason_from_trap(self):
21605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Try to retrieve the recovery reason from a trapped recovery screen.
21705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
21805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: The recovery_reason, 0 if any error.
21905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
22005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        recovery_reason = 0
22105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Try to retrieve recovery reason...')
22205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.servo.get_usbkey_direction() == 'dut':
2230430288e1ea7c2976db8612c595223dc2a220563Tom Wai-Hong Tam            self.switcher.bypass_rec_mode()
22405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
22505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.switch_usbkey('dut')
22605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
22705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        try:
22819bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam            self.switcher.wait_for_client()
22905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            lines = self.faft_client.system.run_shell_command_get_output(
23005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                        'crossystem recovery_reason')
23105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            recovery_reason = int(lines[0])
23205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Got the recovery reason %d.', recovery_reason)
23305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        except ConnectionError:
23405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.error('Failed to get the recovery reason due to connection '
23505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                          'error.')
23605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return recovery_reason
23705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
23805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def _reset_client(self):
23905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Reset client to a workable state.
24005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
24105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This method is called when the client is not responsive. It may be
24205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        caused by the following cases:
24305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally          - halt on a firmware screen without timeout, e.g. REC_INSERT screen;
24405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally          - corrupted firmware;
24505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally          - corrutped OS image.
24605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
24705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # DUT may halt on a firmware screen. Try cold reboot.
24805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Try cold reboot...')
249a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam        self.switcher.mode_aware_reboot(reboot_type='cold',
250a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam                                        sync_before_boot=False,
251a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam                                        wait_for_dut_up=False)
25219bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam        self.switcher.wait_for_client_offline()
2530430288e1ea7c2976db8612c595223dc2a220563Tom Wai-Hong Tam        self.switcher.bypass_dev_mode()
25405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        try:
25519bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam            self.switcher.wait_for_client()
25605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
25705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        except ConnectionError:
25805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.warn('Cold reboot doesn\'t help, still connection error.')
25905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
26005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # DUT may be broken by a corrupted firmware. Restore firmware.
26105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # We assume the recovery boot still works fine. Since the recovery
26205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # code is in RO region and all FAFT tests don't change the RO region
26305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # except GBB.
26405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.is_firmware_saved():
26505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._ensure_client_in_recovery()
26605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Try restore the original firmware...')
26705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if self.is_firmware_changed():
26805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                try:
26905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    self.restore_firmware()
27005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    return
27105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                except ConnectionError:
27205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    logging.warn('Restoring firmware doesn\'t help, still '
27305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 'connection error.')
27405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
27505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Perhaps it's kernel that's broken. Let's try restoring it.
27605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.is_kernel_saved():
27705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._ensure_client_in_recovery()
27805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Try restore the original kernel...')
27905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if self.is_kernel_changed():
28005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                try:
28105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    self.restore_kernel()
28205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    return
28305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                except ConnectionError:
28405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    logging.warn('Restoring kernel doesn\'t help, still '
28505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 'connection error.')
28605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
28705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # DUT may be broken by a corrupted OS image. Restore OS image.
28805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._ensure_client_in_recovery()
28905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Try restore the OS image...')
29005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command('chromeos-install --yes')
291a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam        self.switcher.mode_aware_reboot(wait_for_dut_up=False)
29219bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam        self.switcher.wait_for_client_offline()
2930430288e1ea7c2976db8612c595223dc2a220563Tom Wai-Hong Tam        self.switcher.bypass_dev_mode()
29405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        try:
29519bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam            self.switcher.wait_for_client()
29605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Successfully restore OS image.')
29705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
29805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        except ConnectionError:
29905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.warn('Restoring OS image doesn\'t help, still connection '
30005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                         'error.')
30105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
30205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def _ensure_client_in_recovery(self):
30305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Ensure client in recovery boot; reboot into it if necessary.
30405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
30505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @raise TestError: if failed to boot the USB image.
30605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
30705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Try boot into USB image...')
308d7a0d05665faa4ee5621b906efeb6e718b9ed1a8Tom Wai-Hong Tam        self.switcher.reboot_to_mode(to_mode='rec', sync_before_boot=False,
309d7a0d05665faa4ee5621b906efeb6e718b9ed1a8Tom Wai-Hong Tam                                     wait_for_dut_up=False)
310f2de4debd08a4825542fd4fd848ccd6b4fb000f8Tom Wai-Hong Tam        self.servo.switch_usbkey('host')
3110430288e1ea7c2976db8612c595223dc2a220563Tom Wai-Hong Tam        self.switcher.bypass_rec_mode()
31205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        try:
31319bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam            self.switcher.wait_for_client()
31405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        except ConnectionError:
31505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestError('Failed to boot the USB image.')
31605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
31764ee3a7f9105e8819abf9e14f5a767a23d836823Yusuf Mohsinally    def _restore_routine_from_timeout(self):
31805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """A routine to try to restore the system from a timeout error.
31905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
32005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This method is called when FAFT failed to connect DUT after reboot.
32105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
32205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @raise TestFail: This exception is already raised, with a decription
32305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                         why it failed.
32405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
32505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # DUT is disconnected. Capture the UART output for debug.
3268b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._record_uart_capture()
32705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
32805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # TODO(waihong@chromium.org): Implement replugging the Ethernet to
32905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # identify if it is a network flaky.
33005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
33105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        recovery_reason = self._retrieve_recovery_reason_from_trap()
33205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
33305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Reset client to a workable state.
33405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._reset_client()
33505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
33605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Raise the proper TestFail exception.
33764ee3a7f9105e8819abf9e14f5a767a23d836823Yusuf Mohsinally        if recovery_reason:
33805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestFail('Trapped in the recovery screen (reason: %d) '
33905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 'and timed out' % recovery_reason)
34005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
34105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestFail('Timed out waiting for DUT reboot')
34205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
34318c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner    def assert_test_image_in_usb_disk(self, usb_dev=None):
34405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Assert an USB disk plugged-in on servo and a test image inside.
34505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
34605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
34705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                        If None, it is detected automatically.
34818c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner        @raise TestError: if USB disk not detected or not a test image.
34905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
35005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.check_setup_done('usb_check'):
35105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
35205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if usb_dev:
35305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            assert self.servo.get_usbkey_direction() == 'host'
35405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
35505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.switch_usbkey('host')
35605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            usb_dev = self.servo.probe_host_usb_dev()
35705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if not usb_dev:
35805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                raise error.TestError(
35905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                        'An USB disk should be plugged in the servo board.')
36005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
36105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        rootfs = '%s%s' % (usb_dev, self._ROOTFS_PARTITION_NUMBER)
36205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('usb dev is %s', usb_dev)
36305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        tmpd = self.servo.system_output('mktemp -d -t usbcheck.XXXX')
36405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.system('mount -o ro %s %s' % (rootfs, tmpd))
36505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
366dc535dfe1f95fe8ec4b95b02ffc12ed0fb40f83cJulius Werner        try:
36718c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            usb_lsb = self.servo.system_output('cat %s' %
36818c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner                os.path.join(tmpd, 'etc/lsb-release'))
36918c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            logging.debug('Dumping lsb-release on USB stick:\n%s', usb_lsb)
37018c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            dut_lsb = '\n'.join(self.faft_client.system.
37118c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner                run_shell_command_get_output('cat /etc/lsb-release'))
37218c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            logging.debug('Dumping lsb-release on DUT:\n%s', dut_lsb)
373e6adca4984389bc6fd46f7e5d7a45aec43f884fdJulius Werner            if not re.search(r'RELEASE_TRACK=.*test', usb_lsb):
37418c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner                raise error.TestError('USB stick in servo is no test image')
37518c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            usb_board = re.search(r'BOARD=(.*)', usb_lsb).group(1)
37618c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            dut_board = re.search(r'BOARD=(.*)', dut_lsb).group(1)
37718c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            if usb_board != dut_board:
37818c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner                raise error.TestError('USB stick in servo contains a %s '
37918c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner                    'image, but DUT is a %s' % (usb_board, dut_board))
380dc535dfe1f95fe8ec4b95b02ffc12ed0fb40f83cJulius Werner        finally:
381dc535dfe1f95fe8ec4b95b02ffc12ed0fb40f83cJulius Werner            for cmd in ('umount %s' % rootfs, 'sync', 'rm -rf %s' % tmpd):
382dc535dfe1f95fe8ec4b95b02ffc12ed0fb40f83cJulius Werner                self.servo.system(cmd)
38305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
38405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.mark_setup_done('usb_check')
38505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
38618c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner    def setup_usbkey(self, usbkey, host=None):
38705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Setup the USB disk for the test.
38805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
38905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        It checks the setup of USB disk and a valid ChromeOS test image inside.
39005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        It also muxes the USB disk to either the host or DUT by request.
39105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
39205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param usbkey: True if the USB disk is required for the test, False if
39305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                       not required.
39405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param host: Optional, True to mux the USB disk to host, False to mux it
39505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    to DUT, default to do nothing.
39605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
39705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if usbkey:
39818c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner            self.assert_test_image_in_usb_disk()
39905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        elif host is None:
40005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # USB disk is not required for the test. Better to mux it to host.
40105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            host = True
40205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
40305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if host is True:
40405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.switch_usbkey('host')
40505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        elif host is False:
40605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.switch_usbkey('dut')
40705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
40805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def get_usbdisk_path_on_dut(self):
40905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Get the path of the USB disk device plugged-in the servo on DUT.
41005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
41105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        Returns:
41205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally          A string representing USB disk path, like '/dev/sdb', or None if
41305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally          no USB disk is found.
41405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
41505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        cmd = 'ls -d /dev/s*[a-z]'
41605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        original_value = self.servo.get_usbkey_direction()
41705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
41805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Make the dut unable to see the USB disk.
41905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.switch_usbkey('off')
42005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        no_usb_set = set(
42105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.faft_client.system.run_shell_command_get_output(cmd))
42205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
42305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Make the dut able to see the USB disk.
42405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.switch_usbkey('dut')
425b0314a0ab7b590cb0b25b80513673eb157f7b5e9Tom Wai-Hong Tam        time.sleep(self.faft_config.usb_plug)
42605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        has_usb_set = set(
42705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.faft_client.system.run_shell_command_get_output(cmd))
42805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
42905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Back to its original value.
43005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if original_value != self.servo.get_usbkey_direction():
43105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.switch_usbkey(original_value)
43205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
43305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        diff_set = has_usb_set - no_usb_set
43405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if len(diff_set) == 1:
43505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return diff_set.pop()
43605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
43705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return None
43805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
43910eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie    def _create_faft_lockfile(self):
44010eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        """Creates the FAFT lockfile."""
44110eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        logging.info('Creating FAFT lockfile...')
44210eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        command = 'touch %s' % (self.lockfile)
44310eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        self.faft_client.system.run_shell_command(command)
44410eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie
44510eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie    def _remove_faft_lockfile(self):
44610eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        """Removes the FAFT lockfile."""
44710eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        logging.info('Removing FAFT lockfile...')
44810eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        command = 'rm -f %s' % (self.lockfile)
44910eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie        self.faft_client.system.run_shell_command(command)
45010eb618d5336f1bd6f4cd4c135ea93d1e3a880bfDuncan Laurie
4518b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _stop_service(self, service):
45205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Stops a upstart service on the client.
45305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
45405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param service: The name of the upstart service.
45505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
45605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Stopping %s...', service)
45705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        command = 'status %s | grep stop || stop %s' % (service, service)
45805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command(command)
45905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
4608b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _start_service(self, service):
46105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Starts a upstart service on the client.
46205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
46305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param service: The name of the upstart service.
46405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
46505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Starting %s...', service)
46605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        command = 'status %s | grep start || start %s' % (service, service)
46705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command(command)
46805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
46905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def clear_set_gbb_flags(self, clear_mask, set_mask):
47005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Clear and set the GBB flags in the current flashrom.
47105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
47205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param clear_mask: A mask of flags to be cleared.
47305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param set_mask: A mask of flags to be set.
47405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
47505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        gbb_flags = self.faft_client.bios.get_gbb_flags()
47605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        new_flags = gbb_flags & ctypes.c_uint32(~clear_mask).value | set_mask
477fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam        if new_flags != gbb_flags:
478fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam            self._backup_gbb_flags = gbb_flags
479fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam            logging.info('Changing GBB flags from 0x%x to 0x%x.',
480fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam                         gbb_flags, new_flags)
481fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam            self.faft_client.bios.set_gbb_flags(new_flags)
482fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam            # If changing FORCE_DEV_SWITCH_ON flag, reboot to get a clear state
483fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam            if ((gbb_flags ^ new_flags) & vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON):
484fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam                self.switcher.mode_aware_reboot()
485fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam        else:
486fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam            logging.info('Current GBB flags look good for test: 0x%x.',
487fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam                         gbb_flags)
48805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
48905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def check_ec_capability(self, required_cap=None, suppress_warning=False):
49005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check if current platform has required EC capabilities.
49105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
49205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param required_cap: A list containing required EC capabilities. Pass in
49305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             None to only check for presence of Chrome EC.
49405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param suppress_warning: True to suppress any warning messages.
49505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: True if requirements are met. Otherwise, False.
49605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
49705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not self.faft_config.chrome_ec:
49805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if not suppress_warning:
49905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                logging.warn('Requires Chrome EC to run this test.')
50005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return False
50105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
50205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not required_cap:
50305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return True
50405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
50505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        for cap in required_cap:
50605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if cap not in self.faft_config.ec_capability:
50705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                if not suppress_warning:
50805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    logging.warn('Requires EC capability "%s" to run this '
50905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 'test.', cap)
51005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                return False
51105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
51205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return True
51305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
51405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def check_root_part_on_non_recovery(self, part):
51505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check the partition number of root device and on normal/dev boot.
51605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
51705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param part: A string of partition number, e.g.'3'.
51805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: True if the root device matched and on normal/dev boot;
51905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                 otherwise, False.
52005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
52105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return self.checkers.root_part_checker(part) and \
52205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                self.checkers.crossystem_checker({
52305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    'mainfw_type': ('normal', 'developer'),
52405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                })
52505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
52605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def _join_part(self, dev, part):
52705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Return a concatenated string of device and partition number.
52805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
52905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param dev: A string of device, e.g.'/dev/sda'.
53005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param part: A string of partition number, e.g.'3'.
53105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: A concatenated string of device and partition number,
53205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                 e.g.'/dev/sda3'.
53305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
53405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        >>> seq = FirmwareTest()
53505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        >>> seq._join_part('/dev/sda', '3')
53605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        '/dev/sda3'
53705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        >>> seq._join_part('/dev/mmcblk0', '2')
53805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        '/dev/mmcblk0p2'
53905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
54005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if 'mmcblk' in dev:
54105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return dev + 'p' + part
54205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
54305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return dev + part
54405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
54505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def copy_kernel_and_rootfs(self, from_part, to_part):
54605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Copy kernel and rootfs from from_part to to_part.
54705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
54805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param from_part: A string of partition number to be copied from.
54905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param to_part: A string of partition number to be copied to.
55005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
55105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        root_dev = self.faft_client.system.get_root_dev()
55205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Copying kernel from %s to %s. Please wait...',
55305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                     from_part, to_part)
55405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
55505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                (self._join_part(root_dev, self.KERNEL_MAP[from_part]),
55605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                 self._join_part(root_dev, self.KERNEL_MAP[to_part])))
55705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Copying rootfs from %s to %s. Please wait...',
55805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                     from_part, to_part)
55905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command('dd if=%s of=%s bs=4M' %
56005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                (self._join_part(root_dev, self.ROOTFS_MAP[from_part]),
56105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                 self._join_part(root_dev, self.ROOTFS_MAP[to_part])))
56205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
56305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def ensure_kernel_boot(self, part):
56405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Ensure the request kernel boot.
56505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
56605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        If not, it duplicates the current kernel to the requested kernel
56705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        and sets the requested higher priority to ensure it boot.
56805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
56905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param part: A string of kernel partition number or 'a'/'b'.
57005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
57105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not self.checkers.root_part_checker(part):
57205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if self.faft_client.kernel.diff_a_b():
57305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                self.copy_kernel_and_rootfs(
57405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                        from_part=self.OTHER_KERNEL_MAP[part],
57505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                        to_part=part)
576ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally            self.reset_and_prioritize_kernel(part)
577b1a8601683815deaa44a912647534dbe1a37f643Tom Wai-Hong Tam            self.switcher.mode_aware_reboot()
57805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
57905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def set_hardware_write_protect(self, enable):
58005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Set hardware write protect pin.
58105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
58205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param enable: True if asserting write protect pin. Otherwise, False.
58305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
58405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.set('fw_wp_vref', self.faft_config.wp_voltage)
58505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.set('fw_wp_en', 'on')
58605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.set('fw_wp', 'on' if enable else 'off')
58705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
58805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def set_ec_write_protect_and_reboot(self, enable):
58905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Set EC write protect status and reboot to take effect.
59005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
59105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        The write protect state is only activated if both hardware write
59205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        protect pin is asserted and software write protect flag is set.
59305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This method asserts/deasserts hardware write protect pin first, and
59405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        set corresponding EC software write protect flag.
59505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
59605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        If the device uses non-Chrome EC, set the software write protect via
59705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        flashrom.
59805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
59905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        If the device uses Chrome EC, a reboot is required for write protect
60005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        to take effect. Since the software write protect flag cannot be unset
60105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if hardware write protect pin is asserted, we need to deasserted the
60205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        pin first if we are deactivating write protect. Similarly, a reboot
60305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        is required before we can modify the software flag.
60405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
60505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param enable: True if activating EC write protect. Otherwise, False.
60605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
60705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.set_hardware_write_protect(enable)
60805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.faft_config.chrome_ec:
60905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.set_chrome_ec_write_protect_and_reboot(enable)
61005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
61105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.faft_client.ec.set_write_protect(enable)
612a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam            self.switcher.mode_aware_reboot()
61305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
61405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def set_chrome_ec_write_protect_and_reboot(self, enable):
61505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Set Chrome EC write protect status and reboot to take effect.
61605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
61705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param enable: True if activating EC write protect. Otherwise, False.
61805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
61905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if enable:
62005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # Set write protect flag and reboot to take effect.
62105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.ec.set_flash_write_protect(enable)
62205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.sync_and_ec_reboot()
62305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
62405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # Reboot after deasserting hardware write protect pin to deactivate
62505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # write protect. And then remove software write protect flag.
62605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.sync_and_ec_reboot()
62705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.ec.set_flash_write_protect(enable)
62805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
6298b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _setup_ec_write_protect(self, ec_wp):
63005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Setup for EC write-protection.
63105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
63205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        It makes sure the EC in the requested write-protection state. If not, it
63305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        flips the state. Flipping the write-protection requires DUT reboot.
63405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
63505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param ec_wp: True to request EC write-protected; False to request EC
63605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                      not write-protected; None to do nothing.
63705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
63805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if ec_wp is None:
63905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._old_ec_wp = None
64005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
64105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._old_ec_wp = self.checkers.crossystem_checker({'wpsw_boot': '1'})
64205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if ec_wp != self._old_ec_wp:
64305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('The test required EC is %swrite-protected. Reboot '
64405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                         'and flip the state.', '' if ec_wp else 'not ')
6453e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam            self.switcher.mode_aware_reboot(
6463e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam                    'custom',
6473e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam                     lambda:self.set_ec_write_protect_and_reboot(ec_wp))
64805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
6498b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _restore_ec_write_protect(self):
65005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Restore the original EC write-protection."""
65105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if (not hasattr(self, '_old_ec_wp')) or (self._old_ec_wp is None):
65205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
65305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not self.checkers.crossystem_checker(
65405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                {'wpsw_boot': '1' if self._old_ec_wp else '0'}):
655ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally            logging.info('Restore original EC write protection and reboot.')
6563e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam            self.switcher.mode_aware_reboot(
6573e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam                    'custom',
6583e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam                    lambda:self.set_ec_write_protect_and_reboot(
6593e92b8e9041fa7bb44dc9285e2c415eb611697a9Tom Wai-Hong Tam                            self._old_ec_wp))
66005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
6618b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _setup_uart_capture(self):
662af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie        """Setup the CPU/EC/PD UART capture."""
66305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.cpu_uart_file = os.path.join(self.resultsdir, 'cpu_uart.txt')
66405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.set('cpu_uart_capture', 'on')
66505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.ec_uart_file = None
666af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie        self.usbpd_uart_file = None
66705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.faft_config.chrome_ec:
66805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            try:
66905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                self.servo.set('ec_uart_capture', 'on')
67005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                self.ec_uart_file = os.path.join(self.resultsdir, 'ec_uart.txt')
67105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            except error.TestFail as e:
67205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                if 'No control named' in str(e):
67305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    logging.warn('The servod is too old that ec_uart_capture '
67405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 'not supported.')
675af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie            # Log separate PD console if supported
676af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie            if self.check_ec_capability(['usbpd_uart'], suppress_warning=True):
677af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                try:
678af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                    self.servo.set('usbpd_uart_capture', 'on')
679af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                    self.usbpd_uart_file = os.path.join(self.resultsdir,
680af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                                                        'usbpd_uart.txt')
681af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                except error.TestFail as e:
682af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                    if 'No control named' in str(e):
683af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                        logging.warn('The servod is too old that '
684af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                                     'usbpd_uart_capture is not supported.')
68505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
68605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Not a Google EC, cannot capture ec console output.')
68705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
6888b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _record_uart_capture(self):
689af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie        """Record the CPU/EC/PD UART output stream to files."""
69005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.cpu_uart_file:
69105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            with open(self.cpu_uart_file, 'a') as f:
69205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                f.write(ast.literal_eval(self.servo.get('cpu_uart_stream')))
69305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.ec_uart_file and self.faft_config.chrome_ec:
69405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            with open(self.ec_uart_file, 'a') as f:
69505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                f.write(ast.literal_eval(self.servo.get('ec_uart_stream')))
696af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie        if (self.usbpd_uart_file and self.faft_config.chrome_ec and
697af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie            self.check_ec_capability(['usbpd_uart'], suppress_warning=True)):
698af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie            with open(self.usbpd_uart_file, 'a') as f:
699af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie                f.write(ast.literal_eval(self.servo.get('usbpd_uart_stream')))
70005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
7018b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _cleanup_uart_capture(self):
702af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie        """Cleanup the CPU/EC/PD UART capture."""
70305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Flush the remaining UART output.
7048b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        self._record_uart_capture()
70505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.set('cpu_uart_capture', 'off')
70605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.ec_uart_file and self.faft_config.chrome_ec:
70705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.set('ec_uart_capture', 'off')
708af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie        if (self.usbpd_uart_file and self.faft_config.chrome_ec and
709af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie            self.check_ec_capability(['usbpd_uart'], suppress_warning=True)):
710af61c1fb249fe2e0702eba0385cb07f368d6eb68Duncan Laurie            self.servo.set('usbpd_uart_capture', 'off')
71105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
712c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen    def _get_power_state(self, power_state):
713c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        """
714c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        Return the current power state of the AP
715c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        """
716c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        return self.ec.send_command_get_output("powerinfo", [power_state])
717c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen
718c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen    def wait_power_state(self, power_state, retries):
719c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        """
720c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        Wait for certain power state.
721c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen
722c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        @param power_state: power state you are expecting
723c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        @param retries: retries.  This is necessary if AP is powering down
724c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        and transitioning through different states.
725c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        """
726c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        logging.info('Checking power state "%s" maximum %d times.',
727c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen                     power_state, retries)
728c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        while retries > 0:
729c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen            logging.info("try count: %d" % retries)
730c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen            try:
731c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen                retries = retries - 1
732c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen                ret = self._get_power_state(power_state)
733c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen                return True
734c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen            except error.TestFail:
735c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen                pass
736c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen        return False
737c0781c4988c2ad6bd3b56be567f966ae3124661cShelley Chen
738530490a25d656468ade45a4e165e683846ccd403Shelley Chen    def delayed(seconds):
739530490a25d656468ade45a4e165e683846ccd403Shelley Chen        def decorator(f):
740530490a25d656468ade45a4e165e683846ccd403Shelley Chen            def wrapper(*args, **kargs):
741530490a25d656468ade45a4e165e683846ccd403Shelley Chen                t = Timer(seconds, f, args, kargs)
742530490a25d656468ade45a4e165e683846ccd403Shelley Chen                t.start()
743530490a25d656468ade45a4e165e683846ccd403Shelley Chen            return wrapper
744530490a25d656468ade45a4e165e683846ccd403Shelley Chen        return decorator
745530490a25d656468ade45a4e165e683846ccd403Shelley Chen
746530490a25d656468ade45a4e165e683846ccd403Shelley Chen    @delayed(WAKE_DELAY)
747530490a25d656468ade45a4e165e683846ccd403Shelley Chen    def wake_by_power_button(self):
748530490a25d656468ade45a4e165e683846ccd403Shelley Chen        """Delay by WAKE_DELAY seconds and then wake DUT with power button."""
749530490a25d656468ade45a4e165e683846ccd403Shelley Chen        self.servo.power_normal_press()
750530490a25d656468ade45a4e165e683846ccd403Shelley Chen
751530490a25d656468ade45a4e165e683846ccd403Shelley Chen    @delayed(WAKE_DELAY)
752530490a25d656468ade45a4e165e683846ccd403Shelley Chen    def wake_by_lid_switch(self):
753530490a25d656468ade45a4e165e683846ccd403Shelley Chen        """Delay by WAKE_DELAY seconds and then wake DUT with lid switch."""
754530490a25d656468ade45a4e165e683846ccd403Shelley Chen        self.servo.set('lid_open', 'no')
755530490a25d656468ade45a4e165e683846ccd403Shelley Chen        time.sleep(self.LID_DELAY)
756530490a25d656468ade45a4e165e683846ccd403Shelley Chen        self.servo.set('lid_open', 'yes')
757530490a25d656468ade45a4e165e683846ccd403Shelley Chen
758530490a25d656468ade45a4e165e683846ccd403Shelley Chen    def suspend_as_reboot(self, wake_func):
759530490a25d656468ade45a4e165e683846ccd403Shelley Chen        """
760530490a25d656468ade45a4e165e683846ccd403Shelley Chen        Suspend DUT and also kill FAFT client so that this acts like a reboot.
761530490a25d656468ade45a4e165e683846ccd403Shelley Chen
762530490a25d656468ade45a4e165e683846ccd403Shelley Chen        Args:
763530490a25d656468ade45a4e165e683846ccd403Shelley Chen          wake_func: A function that is called to wake DUT. Note that this
764530490a25d656468ade45a4e165e683846ccd403Shelley Chen            function must delay itself so that we don't wake DUT before
765530490a25d656468ade45a4e165e683846ccd403Shelley Chen            suspend_as_reboot returns.
766530490a25d656468ade45a4e165e683846ccd403Shelley Chen        """
767530490a25d656468ade45a4e165e683846ccd403Shelley Chen        cmd = '(sleep %d; powerd_dbus_suspend) &' % self.EC_SUSPEND_DELAY
768530490a25d656468ade45a4e165e683846ccd403Shelley Chen        self.faft_client.system.run_shell_command(cmd)
769530490a25d656468ade45a4e165e683846ccd403Shelley Chen        self.faft_client.disconnect()
770530490a25d656468ade45a4e165e683846ccd403Shelley Chen        time.sleep(self.EC_SUSPEND_DELAY)
771530490a25d656468ade45a4e165e683846ccd403Shelley Chen        logging.info("wake function disabled")
772530490a25d656468ade45a4e165e683846ccd403Shelley Chen        wake_func()
773530490a25d656468ade45a4e165e683846ccd403Shelley Chen
7748b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _fetch_servo_log(self):
77505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Fetch the servo log."""
77605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        cmd = '[ -e %s ] && cat %s || echo NOTFOUND' % ((self._SERVOD_LOG,) * 2)
77705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        servo_log = self.servo.system_output(cmd)
77805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return None if servo_log == 'NOTFOUND' else servo_log
77905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
7808b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _setup_servo_log(self):
78105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Setup the servo log capturing."""
78205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo_log_original_len = -1
78305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.servo.is_localhost():
78405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # No servo log recorded when servod runs locally.
78505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
78605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
7878b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally        servo_log = self._fetch_servo_log()
78805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if servo_log:
78905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo_log_original_len = len(servo_log)
79005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
79105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.warn('Servo log file not found.')
79205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
7938b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _record_servo_log(self):
79405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Record the servo log to the results directory."""
79505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.servo_log_original_len != -1:
7968b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally            servo_log = self._fetch_servo_log()
79705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            servo_log_file = os.path.join(self.resultsdir, 'servod.log')
79805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            with open(servo_log_file, 'a') as f:
79905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                f.write(servo_log[self.servo_log_original_len:])
80005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
8018b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _record_faft_client_log(self):
80205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Record the faft client log to the results directory."""
80305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        client_log = self.faft_client.system.dump_log(True)
80405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        client_log_file = os.path.join(self.resultsdir, 'faft_client.log')
80505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        with open(client_log_file, 'w') as f:
80605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            f.write(client_log)
80705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
8088b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _setup_gbb_flags(self):
80905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Setup the GBB flags for FAFT test."""
81005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.faft_config.gbb_version < 1.1:
81105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Skip modifying GBB on versions older than 1.1.')
81205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
81305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
81405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.check_setup_done('gbb_flags'):
81505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
81605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
81705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Set proper GBB flags for test.')
81805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.clear_set_gbb_flags(vboot.GBB_FLAG_DEV_SCREEN_SHORT_DELAY |
81905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 vboot.GBB_FLAG_FORCE_DEV_SWITCH_ON |
82005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 vboot.GBB_FLAG_FORCE_DEV_BOOT_USB |
82146ebbb1ee25320a2fe6330edb13a062eec7ef7bbTom Wai-Hong Tam                                 vboot.GBB_FLAG_DISABLE_FW_ROLLBACK_CHECK |
82246ebbb1ee25320a2fe6330edb13a062eec7ef7bbTom Wai-Hong Tam                                 vboot.GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP,
82305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 vboot.GBB_FLAG_ENTER_TRIGGERS_TONORM |
82405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 vboot.GBB_FLAG_FAFT_KEY_OVERIDE)
82505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.mark_setup_done('gbb_flags')
82605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
82705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def drop_backup_gbb_flags(self):
82805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Drops the backup GBB flags.
82905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
83005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This can be used when a test intends to permanently change GBB flags.
83105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
83205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._backup_gbb_flags = None
83305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
8348b377eb0528c632e4cb2d888f7388faf764f9987Yusuf Mohsinally    def _restore_gbb_flags(self):
83505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Restore GBB flags to their original state."""
836fc0c77097ba960aa1e2a6388770fea905ab0d4a7Tom Wai-Hong Tam        if self._backup_gbb_flags is None:
83705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
8382e3db4a5e9179d2a4f8f01b885884bf64b664646Tom Wai-Hong Tam        # Setting up and restoring the GBB flags take a lot of time. For
8392e3db4a5e9179d2a4f8f01b885884bf64b664646Tom Wai-Hong Tam        # speed-up purpose, don't restore it.
8402e3db4a5e9179d2a4f8f01b885884bf64b664646Tom Wai-Hong Tam        logging.info('***')
8412e3db4a5e9179d2a4f8f01b885884bf64b664646Tom Wai-Hong Tam        logging.info('*** Please manually restore the original GBB flags to: '
8422e3db4a5e9179d2a4f8f01b885884bf64b664646Tom Wai-Hong Tam                     '0x%x ***', self._backup_gbb_flags)
8432e3db4a5e9179d2a4f8f01b885884bf64b664646Tom Wai-Hong Tam        logging.info('***')
84405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.unmark_setup_done('gbb_flags')
84505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
84605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def setup_tried_fwb(self, tried_fwb):
84705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Setup for fw B tried state.
84805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
84905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        It makes sure the system in the requested fw B tried state. If not, it
85005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        tries to do so.
85105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
85205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param tried_fwb: True if requested in tried_fwb=1;
85305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                          False if tried_fwb=0.
85405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
85505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if tried_fwb:
85605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if not self.checkers.crossystem_checker({'tried_fwb': '1'}):
85705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                logging.info(
85805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    'Firmware is not booted with tried_fwb. Reboot into it.')
859ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally                self.faft_client.system.set_try_fw_b()
86005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
86105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if not self.checkers.crossystem_checker({'tried_fwb': '0'}):
86205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                logging.info(
86305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    'Firmware is booted with tried_fwb. Reboot to clear.')
86405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
86505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def power_on(self):
86605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Switch DUT AC power on."""
86705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._client.power_on(self.power_control)
86805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
86905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def power_off(self):
87005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Switch DUT AC power off."""
87105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._client.power_off(self.power_control)
87205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
87305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def power_cycle(self):
87405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Power cycle DUT AC power."""
87505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._client.power_cycle(self.power_control)
87605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
87705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def setup_rw_boot(self, section='a'):
87805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Make sure firmware is in RW-boot mode.
87905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
88005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        If the given firmware section is in RO-boot mode, turn off the RO-boot
88105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        flag and reboot DUT into RW-boot mode.
88205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
88305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param section: A firmware section, either 'a' or 'b'.
88405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
88505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        flags = self.faft_client.bios.get_preamble_flags(section)
88605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if flags & vboot.PREAMBLE_USE_RO_NORMAL:
88705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            flags = flags ^ vboot.PREAMBLE_USE_RO_NORMAL
888ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally            self.faft_client.bios.set_preamble_flags(section, flags)
8894777624b69b3b223a5d3c3abe86000783f6c0e96Tom Wai-Hong Tam            self.switcher.mode_aware_reboot()
89005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
89105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def setup_kernel(self, part):
89205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Setup for kernel test.
89305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
89405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        It makes sure both kernel A and B bootable and the current boot is
89505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        the requested kernel part.
89605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
89705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param part: A string of kernel partition number or 'a'/'b'.
89805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
89905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.ensure_kernel_boot(part)
90005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Checking the integrity of kernel B and rootfs B...')
90105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if (self.faft_client.kernel.diff_a_b() or
90205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                not self.faft_client.rootfs.verify_rootfs('B')):
90305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('Copying kernel and rootfs from A to B...')
90405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.copy_kernel_and_rootfs(from_part=part,
90505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                        to_part=self.OTHER_KERNEL_MAP[part])
90605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.reset_and_prioritize_kernel(part)
90705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
90805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def reset_and_prioritize_kernel(self, part):
90905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Make the requested partition highest priority.
91005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
91105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This function also reset kerenl A and B to bootable.
91205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
91305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param part: A string of partition number to be prioritized.
91405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
91505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        root_dev = self.faft_client.system.get_root_dev()
91605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Reset kernel A and B to bootable.
91705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command(
91805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['a'], root_dev))
91905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command(
92005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            'cgpt add -i%s -P1 -S1 -T0 %s' % (self.KERNEL_MAP['b'], root_dev))
92105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Set kernel part highest priority.
92205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.system.run_shell_command('cgpt prioritize -i%s %s' %
92305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                (self.KERNEL_MAP[part], root_dev))
92405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
9251bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally    def blocking_sync(self):
9261bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        """Run a blocking sync command."""
9271bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        # The double calls to sync fakes a blocking call
9281bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        # since the first call returns before the flush
9291bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        # is complete, but the second will wait for the
9301bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        # first to finish.
9311bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        self.faft_client.system.run_shell_command('sync')
9321bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        self.faft_client.system.run_shell_command('sync')
9331bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally
9345bee610032835a130b14892b29c70d867639ea43Ryan Lin        # sync only sends SYNCHRONIZE_CACHE but doesn't
935b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung        # check the status. For mmc devices, use `mmc
936b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung        # status get` command to send an empty command to
937b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung        # wait for the disk to be available again.  For
938b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung        # other devices, hdparm sends TUR to check if
9395bee610032835a130b14892b29c70d867639ea43Ryan Lin        # a device is ready for transfer operation.
9405bee610032835a130b14892b29c70d867639ea43Ryan Lin        root_dev = self.faft_client.system.get_root_dev()
941b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung        if 'mmcblk' in root_dev:
942b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung            self.faft_client.system.run_shell_command('mmc status get %s' %
943b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung                                                      root_dev)
944b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung        else:
945b575242a8f8d8e5f67350f20701f3a9b73a33504Steve Fung            self.faft_client.system.run_shell_command('hdparm -f %s' % root_dev)
946ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally
94705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def sync_and_ec_reboot(self, flags=''):
94805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Request the client sync and do a EC triggered reboot.
94905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
95005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param flags: Optional, a space-separated string of flags passed to EC
95105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                      reboot command, including:
95205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                          default: EC soft reboot;
95305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                          'hard': EC cold/hard reboot.
95405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
9551bacc9661de528d838294d0c517905f4ded7f632Yusuf Mohsinally        self.blocking_sync()
95605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.ec.reboot(flags)
95705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        time.sleep(self.faft_config.ec_boot_to_console)
95805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.check_lid_and_power_on()
95905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
96018c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner    def reboot_and_reset_tpm(self):
96118c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner        """Reboot into recovery mode, reset TPM, then reboot back to disk."""
96218c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner        self.switcher.reboot_to_mode(to_mode='rec')
96318c4e1643b3ac6f6a201e2008020cdae8c590a7dJulius Werner        self.faft_client.system.run_shell_command('chromeos-tpm-recovery')
964a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam        self.switcher.mode_aware_reboot()
96505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
96605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def full_power_off_and_on(self):
96705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Shutdown the device by pressing power button and power on again."""
968101b0b26778060c13e6fbceddc92f21734f2878fDanny Chan        boot_id = self.get_bootid()
96905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Press power button to trigger Chrome OS normal shutdown process.
97005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # We use a customized delay since the normal-press 1.2s is not enough.
97125d703a846f3a717dd8a65997aee0ddfd6afe440David Hendricks        self.servo.power_key(self.faft_config.hold_pwr_button_poweroff)
972101b0b26778060c13e6fbceddc92f21734f2878fDanny Chan        # device can take 44-51 seconds to restart,
973101b0b26778060c13e6fbceddc92f21734f2878fDanny Chan        # add buffer from the default timeout of 60 seconds.
97419bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam        self.switcher.wait_for_client_offline(timeout=100, orig_boot_id=boot_id)
97505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        time.sleep(self.faft_config.shutdown)
97605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Short press power button to boot DUT again.
97725d703a846f3a717dd8a65997aee0ddfd6afe440David Hendricks        self.servo.power_key(self.faft_config.hold_pwr_button_poweron)
97805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
97905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def check_lid_and_power_on(self):
98005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
98105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        On devices with EC software sync, system powers on after EC reboots if
98205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        lid is open. Otherwise, the EC shuts down CPU after about 3 seconds.
98305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        This method checks lid switch state and presses power button if
98405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        necessary.
98505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
98605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.servo.get("lid_open") == "no":
98705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            time.sleep(self.faft_config.software_sync)
98805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.servo.power_short_press()
98905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
99005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def _modify_usb_kernel(self, usb_dev, from_magic, to_magic):
99105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Modify the kernel header magic in USB stick.
99205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
99305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        The kernel header magic is the first 8-byte of kernel partition.
99405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        We modify it to make it fail on kernel verification check.
99505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
99605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
99705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param from_magic: A string of magic which we change it from.
99805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param to_magic: A string of magic which we change it to.
99905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @raise TestError: if failed to change magic.
100005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
100105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        assert len(from_magic) == 8
100205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        assert len(to_magic) == 8
100305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # USB image only contains one kernel.
100405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        kernel_part = self._join_part(usb_dev, self.KERNEL_MAP['a'])
100505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        read_cmd = "sudo dd if=%s bs=8 count=1 2>/dev/null" % kernel_part
100605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        current_magic = self.servo.system_output(read_cmd)
100705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if current_magic == to_magic:
100805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info("The kernel magic is already %s.", current_magic)
100905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
101005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if current_magic != from_magic:
101105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestError("Invalid kernel image on USB: wrong magic.")
101205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
101305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Modify the kernel magic in USB, from %s to %s.',
101405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                     from_magic, to_magic)
101505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        write_cmd = ("echo -n '%s' | sudo dd of=%s oflag=sync conv=notrunc "
101605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                     " 2>/dev/null" % (to_magic, kernel_part))
101705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.servo.system(write_cmd)
101805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
101905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if self.servo.system_output(read_cmd) != to_magic:
102005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestError("Failed to write new magic.")
102105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
102205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def corrupt_usb_kernel(self, usb_dev):
102305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Corrupt USB kernel by modifying its magic from CHROMEOS to CORRUPTD.
102405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
102505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
102605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
102705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._modify_usb_kernel(usb_dev, self.CHROMEOS_MAGIC,
102805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                self.CORRUPTED_MAGIC)
102905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
103005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def restore_usb_kernel(self, usb_dev):
103105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Restore USB kernel by modifying its magic from CORRUPTD to CHROMEOS.
103205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
103305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param usb_dev: A string of USB stick path on the host, like '/dev/sdc'.
103405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
103505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._modify_usb_kernel(usb_dev, self.CORRUPTED_MAGIC,
103605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                self.CHROMEOS_MAGIC)
103705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
103805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def _call_action(self, action_tuple, check_status=False):
103905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Call the action function with/without arguments.
104005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
104105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param action_tuple: A function, or a tuple (function, args, error_msg),
104205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             in which, args and error_msg are optional. args is
104305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             either a value or a tuple if multiple arguments.
104405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             This can also be a list containing multiple
104505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             function or tuple. In this case, these actions are
104605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             called in sequence.
104705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param check_status: Check the return value of action function. If not
104805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             succeed, raises a TestFail exception.
104905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: The result value of the action function.
105005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @raise TestError: An error when the action function is not callable.
105105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @raise TestFail: When check_status=True, action function not succeed.
105205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
105305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if isinstance(action_tuple, list):
105405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return all([self._call_action(action, check_status=check_status)
105505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                        for action in action_tuple])
105605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
105705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        action = action_tuple
105805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        args = ()
105905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        error_msg = 'Not succeed'
106005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if isinstance(action_tuple, tuple):
106105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            action = action_tuple[0]
106205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if len(action_tuple) >= 2:
106305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                args = action_tuple[1]
106405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                if not isinstance(args, tuple):
106505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    args = (args,)
106605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if len(action_tuple) >= 3:
106705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                error_msg = action_tuple[2]
106805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
106905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if action is None:
107005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
107105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
107205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not callable(action):
107305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestError('action is not callable!')
107405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
107505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        info_msg = 'calling %s' % str(action)
107605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if args:
107705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            info_msg += ' with args %s' % str(args)
107805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info(info_msg)
107905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        ret = action(*args)
108005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
108105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if check_status and not ret:
108205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestFail('%s: %s returning %s' %
108305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                 (error_msg, info_msg, str(ret)))
108405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return ret
108505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
108605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def run_shutdown_process(self, shutdown_action, pre_power_action=None,
1087a7db9b5519c73ad922c8926ecb0c4d30a376dbfcDanny Chan            run_power_action=True, post_power_action=None, shutdown_timeout=None):
108805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Run shutdown_action(), which makes DUT shutdown, and power it on.
108905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
109005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param shutdown_action: function which makes DUT shutdown, like
109105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                pressing power key.
109205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param pre_power_action: function which is called before next power on.
1093a7db9b5519c73ad922c8926ecb0c4d30a376dbfcDanny Chan        @param power_action: power_key press by default, set to None to skip.
109405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param post_power_action: function which is called after next power on.
109505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param shutdown_timeout: a timeout to confirm DUT shutdown.
109605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @raise TestFail: if the shutdown_action() failed to turn DUT off.
109705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
109805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._call_action(shutdown_action)
109905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Wait to ensure DUT shut down...')
110005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        try:
110105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if shutdown_timeout is None:
110205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                shutdown_timeout = self.faft_config.shutdown_timeout
110319bfb6ea468c34e1b44842033eb784c2ef3eed42Tom Wai-Hong Tam            self.switcher.wait_for_client(timeout=shutdown_timeout)
110405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestFail(
110505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    'Should shut the device down after calling %s.' %
110605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    str(shutdown_action))
110705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        except ConnectionError:
110805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info(
110905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                'DUT is surely shutdown. We are going to power it on again...')
111005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
111105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if pre_power_action:
111205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._call_action(pre_power_action)
1113a7db9b5519c73ad922c8926ecb0c4d30a376dbfcDanny Chan        if run_power_action:
1114a7db9b5519c73ad922c8926ecb0c4d30a376dbfcDanny Chan            self.servo.power_key(self.faft_config.hold_pwr_button_poweron)
111505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if post_power_action:
111605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._call_action(post_power_action)
111705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1118ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally    def get_bootid(self, retry=3):
111905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
1120ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        Return the bootid.
112105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
112205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        boot_id = None
112305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        while retry:
112405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            try:
112505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                boot_id = self._client.get_boot_id()
112605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                break
112705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            except error.AutoservRunError:
112805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                retry -= 1
112905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                if retry:
113005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    logging.info('Retry to get boot_id...')
113105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                else:
113205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    logging.warning('Failed to get boot_id.')
113305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('boot_id: %s', boot_id)
1134ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        return boot_id
113505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1136ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally    def check_state(self, func):
1137ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        """
1138ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        Wrapper around _call_action with check_status set to True. This is a
1139ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        helper function to be used by tests and is currently implemented by
1140ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        calling _call_action with check_status=True.
114105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1142ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        TODO: This function's arguments need to be made more stringent. And
1143ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        its functionality should be moved over to check functions directly in
1144ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        the future.
114505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1146ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        @param func: A function, or a tuple (function, args, error_msg),
1147ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally                             in which, args and error_msg are optional. args is
1148ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally                             either a value or a tuple if multiple arguments.
1149ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally                             This can also be a list containing multiple
1150ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally                             function or tuple. In this case, these actions are
1151ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally                             called in sequence.
1152ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        @return: The result value of the action function.
1153ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        @raise TestFail: If the function does notsucceed.
1154ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        """
1155ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        logging.info("-[FAFT]-[ start stepstate_checker ]----------")
1156ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        self._call_action(func, check_status=True)
1157ab1b5fc3918ca226dda7d39487dedc24b5efe20bYusuf Mohsinally        logging.info("-[FAFT]-[ end state_checker ]----------------")
115805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
115905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def get_current_firmware_sha(self):
116005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Get current firmware sha of body and vblock.
116105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
116205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: Current firmware sha follows the order (
116305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                 vblock_a_sha, body_a_sha, vblock_b_sha, body_b_sha)
116405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
116505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        current_firmware_sha = (self.faft_client.bios.get_sig_sha('a'),
116605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                self.faft_client.bios.get_body_sha('a'),
116705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                self.faft_client.bios.get_sig_sha('b'),
116805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                                self.faft_client.bios.get_body_sha('b'))
116905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not all(current_firmware_sha):
117005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            raise error.TestError('Failed to get firmware sha.')
117105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return current_firmware_sha
117205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
117305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def is_firmware_changed(self):
117405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check if the current firmware changed, by comparing its SHA.
117505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
117605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: True if it is changed, otherwise Flase.
117705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
117805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Device may not be rebooted after test.
117905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.bios.reload()
118005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
118105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        current_sha = self.get_current_firmware_sha()
118205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
118305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if current_sha == self._backup_firmware_sha:
118405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return False
118505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        else:
118605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            corrupt_VBOOTA = (current_sha[0] != self._backup_firmware_sha[0])
118705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            corrupt_FVMAIN = (current_sha[1] != self._backup_firmware_sha[1])
118805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            corrupt_VBOOTB = (current_sha[2] != self._backup_firmware_sha[2])
118905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            corrupt_FVMAINB = (current_sha[3] != self._backup_firmware_sha[3])
119005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info("Firmware changed:")
119105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('VBOOTA is changed: %s', corrupt_VBOOTA)
119205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('VBOOTB is changed: %s', corrupt_VBOOTB)
119305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('FVMAIN is changed: %s', corrupt_FVMAIN)
119405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            logging.info('FVMAINB is changed: %s', corrupt_FVMAINB)
119505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return True
119605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
119705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def backup_firmware(self, suffix='.original'):
119805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Backup firmware to file, and then send it to host.
119905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
120005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param suffix: a string appended to backup file name
120105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
120205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        remote_temp_dir = self.faft_client.system.create_temp_dir()
1203e1d5e66392a398106a5a384a2fa31b177c07b9ccTom Wai-Hong Tam        remote_bios_path = os.path.join(remote_temp_dir, 'bios')
1204e1d5e66392a398106a5a384a2fa31b177c07b9ccTom Wai-Hong Tam        self.faft_client.bios.dump_whole(remote_bios_path)
1205e1d5e66392a398106a5a384a2fa31b177c07b9ccTom Wai-Hong Tam        self._client.get_file(remote_bios_path,
120605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                              os.path.join(self.resultsdir, 'bios' + suffix))
1207e1d5e66392a398106a5a384a2fa31b177c07b9ccTom Wai-Hong Tam        self._client.run('rm -rf %s' % remote_temp_dir)
120805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Backup firmware stored in %s with suffix %s',
120905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.resultsdir, suffix)
121005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1211e1d5e66392a398106a5a384a2fa31b177c07b9ccTom Wai-Hong Tam        self._backup_firmware_sha = self.get_current_firmware_sha()
1212e1d5e66392a398106a5a384a2fa31b177c07b9ccTom Wai-Hong Tam
121305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def is_firmware_saved(self):
121405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check if a firmware saved (called backup_firmware before).
121505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
121605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: True if the firmware is backuped; otherwise False.
121705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
121805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return self._backup_firmware_sha != ()
121905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
122005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def clear_saved_firmware(self):
122105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Clear the firmware saved by the method backup_firmware."""
122205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._backup_firmware_sha = ()
122305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
122405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def restore_firmware(self, suffix='.original'):
122505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Restore firmware from host in resultsdir.
122605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
122705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param suffix: a string appended to backup file name
122805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
122905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not self.is_firmware_changed():
123005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
123105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
123205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Backup current corrupted firmware.
123305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.backup_firmware(suffix='.corrupt')
123405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
123505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Restore firmware.
123605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        remote_temp_dir = self.faft_client.system.create_temp_dir()
123705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._client.send_file(os.path.join(self.resultsdir, 'bios' + suffix),
123805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                               os.path.join(remote_temp_dir, 'bios'))
123905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
124005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.bios.write_whole(
124105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            os.path.join(remote_temp_dir, 'bios'))
1242a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam        self.switcher.mode_aware_reboot()
124305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Successfully restore firmware.')
124405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
124505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def setup_firmwareupdate_shellball(self, shellball=None):
124605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Deside a shellball to use in firmware update test.
124705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
124805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        Check if there is a given shellball, and it is a shell script. Then,
124905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        send it to the remote host. Otherwise, use
125005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        /usr/sbin/chromeos-firmwareupdate.
125105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
125205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param shellball: path of a shellball or default to None.
125305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
125405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: Path of shellball in remote host. If use default shellball,
125505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                 reutrn None.
125605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
125705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        updater_path = None
125805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if shellball:
125905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            # Determine the firmware file is a shellball or a raw binary.
126005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            is_shellball = (utils.system_output("file %s" % shellball).find(
126105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    "shell script") != -1)
126205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if is_shellball:
126305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                logging.info('Device will update firmware with shellball %s',
126405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                             shellball)
126505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                temp_dir = self.faft_client.system.create_temp_dir(
126605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                            'shellball_')
126705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                temp_shellball = os.path.join(temp_dir, 'updater.sh')
126805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                self._client.send_file(shellball, temp_shellball)
126905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                updater_path = temp_shellball
127005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            else:
127105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                raise error.TestFail(
127205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    'The given shellball is not a shell script.')
127305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return updater_path
127405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
127505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def is_kernel_changed(self):
127605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check if the current kernel is changed, by comparing its SHA1 hash.
127705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
127805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: True if it is changed; otherwise, False.
127905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
128005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        changed = False
128105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        for p in ('A', 'B'):
128205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            backup_sha = self._backup_kernel_sha.get(p, None)
128305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            current_sha = self.faft_client.kernel.get_sha(p)
128405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            if backup_sha != current_sha:
128505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                changed = True
128605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                logging.info('Kernel %s is changed', p)
128705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return changed
128805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
128905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def backup_kernel(self, suffix='.original'):
129005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Backup kernel to files, and the send them to host.
129105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
129205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param suffix: a string appended to backup file name.
129305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
129405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        remote_temp_dir = self.faft_client.system.create_temp_dir()
129505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        for p in ('A', 'B'):
129605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            remote_path = os.path.join(remote_temp_dir, 'kernel_%s' % p)
129705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.faft_client.kernel.dump(p, remote_path)
129805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._client.get_file(
129905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    remote_path,
130005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    os.path.join(self.resultsdir, 'kernel_%s%s' % (p, suffix)))
130105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._backup_kernel_sha[p] = self.faft_client.kernel.get_sha(p)
130205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Backup kernel stored in %s with suffix %s',
130305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.resultsdir, suffix)
130405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
130505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def is_kernel_saved(self):
130605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Check if kernel images are saved (backup_kernel called before).
130705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
130805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @return: True if the kernel is saved; otherwise, False.
130905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
131005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        return len(self._backup_kernel_sha) != 0
131105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
131205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def clear_saved_kernel(self):
131305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Clear the kernel saved by backup_kernel()."""
131405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._backup_kernel_sha = dict()
131505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
131605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def restore_kernel(self, suffix='.original'):
131705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Restore kernel from host in resultsdir.
131805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
131905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        @param suffix: a string appended to backup file name.
132005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """
132105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if not self.is_kernel_changed():
132205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
132305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
132405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Backup current corrupted kernel.
132505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.backup_kernel(suffix='.corrupt')
132605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
132705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        # Restore kernel.
132805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        remote_temp_dir = self.faft_client.system.create_temp_dir()
132905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        for p in ('A', 'B'):
133005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            remote_path = os.path.join(remote_temp_dir, 'kernel_%s' % p)
133105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self._client.send_file(
133205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    os.path.join(self.resultsdir, 'kernel_%s%s' % (p, suffix)),
133305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                    remote_path)
133405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            self.faft_client.kernel.write(p, remote_path)
133505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1336a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam        self.switcher.mode_aware_reboot()
133705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Successfully restored kernel.')
133805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
133905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def backup_cgpt_attributes(self):
134005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Backup CGPT partition table attributes."""
134105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self._backup_cgpt_attr = self.faft_client.cgpt.get_attributes()
134205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
134305c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally    def restore_cgpt_attributes(self):
134405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        """Restore CGPT partition table attributes."""
134505c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        current_table = self.faft_client.cgpt.get_attributes()
134605c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        if current_table == self._backup_cgpt_attr:
134705c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally            return
134805c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('CGPT table is changed. Original: %r. Current: %r.',
134905c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                     self._backup_cgpt_attr,
135005c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally                     current_table)
135105c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        self.faft_client.cgpt.set_attributes(self._backup_cgpt_attr)
135205c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally
1353a704f184b788093ddbde169f7120607af84271f7Tom Wai-Hong Tam        self.switcher.mode_aware_reboot()
135405c3c558c1dadb05195c84c10bf8e2c21048096fYusuf Mohsinally        logging.info('Successfully restored CGPT table.')
13553edea989126b84d38135371e780184694892a55aShelley Chen
13563edea989126b84d38135371e780184694892a55aShelley Chen    def try_fwb(self, count=0):
13573edea989126b84d38135371e780184694892a55aShelley Chen        """set to try booting FWB count # times
13583edea989126b84d38135371e780184694892a55aShelley Chen
13593edea989126b84d38135371e780184694892a55aShelley Chen        Wrapper to set fwb_tries for vboot1 and fw_try_count,fw_try_next for
13603edea989126b84d38135371e780184694892a55aShelley Chen        vboot2
13613edea989126b84d38135371e780184694892a55aShelley Chen
13623edea989126b84d38135371e780184694892a55aShelley Chen        @param count: an integer specifying value to program into
13633edea989126b84d38135371e780184694892a55aShelley Chen                      fwb_tries(vb1)/fw_try_next(vb2)
13643edea989126b84d38135371e780184694892a55aShelley Chen        """
13653edea989126b84d38135371e780184694892a55aShelley Chen        if self.fw_vboot2:
13663edea989126b84d38135371e780184694892a55aShelley Chen            self.faft_client.system.set_fw_try_next('B', count)
13673edea989126b84d38135371e780184694892a55aShelley Chen        else:
13683edea989126b84d38135371e780184694892a55aShelley Chen            # vboot1: we need to boot into fwb at least once
13693edea989126b84d38135371e780184694892a55aShelley Chen            if not count:
13703edea989126b84d38135371e780184694892a55aShelley Chen                count = count + 1
13713edea989126b84d38135371e780184694892a55aShelley Chen            self.faft_client.system.set_try_fw_b(count)
13723edea989126b84d38135371e780184694892a55aShelley Chen
1373