• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2017 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import os
7import time
8
9from autotest_lib.client.bin import utils
10from autotest_lib.client.common_lib import error
11from autotest_lib.client.common_lib.cros import cr50_utils
12from autotest_lib.server.cros.faft.firmware_test import FirmwareTest
13from autotest_lib.server.cros import gsutil_wrapper
14
15
16class Cr50Test(FirmwareTest):
17    """
18    Base class that sets up helper objects/functions for cr50 tests.
19    """
20    version = 1
21
22    CR50_GS_URL = 'gs://chromeos-localmirror-private/distfiles/chromeos-cr50-%s/'
23    CR50_DEBUG_FILE = 'cr50_dbg_%s.bin'
24    CR50_PROD_FILE = 'cr50.%s.bin.prod'
25
26    def initialize(self, host, cmdline_args):
27        super(Cr50Test, self).initialize(host, cmdline_args)
28
29        if not hasattr(self, 'cr50'):
30            raise error.TestNAError('Test can only be run on devices with '
31                                    'access to the Cr50 console')
32
33        self._original_cr50_ver = self.cr50.get_version()
34        self.host = host
35
36
37    def cleanup(self):
38        """Make sure cr50 is running the same image"""
39        running_ver = self.cr50.get_version()
40        if (hasattr(self, '_original_cr50_ver') and
41            running_ver != self._original_cr50_ver):
42            raise error.TestError('Running %s not the original cr50 version '
43                                  '%s' % (running_ver,
44                                  self._original_cr50_ver))
45
46        super(Cr50Test, self).cleanup()
47
48
49    def find_cr50_gs_image(self, filename, image_type=None):
50        """Find the cr50 gs image name
51
52        Args:
53            filename: the cr50 filename to match to
54            image_type: release or debug. If it is not specified we will search
55                        both the release and debug directories
56        Returns:
57            a tuple of the gsutil bucket, filename
58        """
59        gs_url = self.CR50_GS_URL % (image_type if image_type else '*')
60        gs_filename = os.path.join(gs_url, filename)
61        bucket, gs_filename = utils.gs_ls(gs_filename)[0].rsplit('/', 1)
62        return bucket, gs_filename
63
64
65    def download_cr50_gs_image(self, filename, bucket=None, image_type=None):
66        """Get the image from gs and save it in the autotest dir
67
68        Returns:
69            the local path
70        """
71        if not bucket:
72            bucket, filename = self.find_cr50_gs_image(filename, image_type)
73
74        remote_temp_dir = '/tmp/'
75        src = os.path.join(remote_temp_dir, filename)
76        dest = os.path.join(self.resultsdir, filename)
77
78        # Copy the image to the dut
79        gsutil_wrapper.copy_private_bucket(host=self.host,
80                                           bucket=bucket,
81                                           filename=filename,
82                                           destination=remote_temp_dir)
83
84        self.host.get_file(src, dest)
85        return dest
86
87
88    def download_cr50_debug_image(self, devid, board_id_info=None):
89        """download the cr50 debug file
90
91        Get the file with the matching devid and board id info
92
93        Args:
94            devid: the cr50_devid string '${DEVID0} ${DEVID1}'
95            board_id_info: a list of [board id, board id mask, board id
96                                      flags]
97        Returns:
98            the local path to the debug image
99        """
100        filename = self.CR50_DEBUG_FILE % (devid.replace(' ', '_'))
101        if board_id_info:
102            filename += '.' + '.'.join(board_id_info)
103        return self.download_cr50_gs_image(filename, image_type='debug')
104
105
106    def download_cr50_release_image(self, rw_ver, board_id_info=None):
107        """download the cr50 release file
108
109        Get the file with the matching version and board id info
110
111        Args:
112            rw_ver: the rw version string
113            board_id_info: a list of strings [board id, board id mask, board id
114                          flags]
115        Returns:
116            the local path to the release image
117        """
118        filename = self.CR50_PROD_FILE % rw_ver
119        if board_id_info:
120            filename += '.' + '.'.join(board_id_info)
121        return self.download_cr50_gs_image(filename, image_type='release')
122
123
124    def _cr50_verify_update(self, expected_ver, expect_rollback):
125        """Verify the expected version is running on cr50
126
127        Args:
128            expect_ver: The RW version string we expect to be running
129            expect_rollback: True if cr50 should have rolled back during the
130                             update
131
132        Raises:
133            TestFail if there is any unexpected update state
134        """
135        running_ver = self.cr50.get_version()
136        if expected_ver != running_ver:
137            raise error.TestFail('Unexpected update ver running %s not %s' %
138                                 (running_ver, expected_ver))
139
140        if expect_rollback != self.cr50.rolledback():
141            raise error.TestFail('Unexpected rollback behavior: %srollback '
142                                 'detected' % 'no ' if expect_rollback else '')
143
144        logging.info('RUNNING %s after %s', expected_ver,
145                     'rollback' if expect_rollback else 'update')
146
147
148    def _cr50_run_update(self, path):
149        """Install the image at path onto cr50
150
151        Args:
152            path: the location of the image to update to
153
154        Returns:
155            the rw version of the image
156        """
157        tmp_dest = '/tmp/' + os.path.basename(path)
158
159        dest, image_ver = cr50_utils.InstallImage(self.host, path, tmp_dest)
160        cr50_utils.UsbUpdater(self.host, ['-s', dest])
161        return image_ver[1]
162
163
164    def cr50_update(self, path, rollback=False, erase_nvmem=False,
165                    expect_rollback=False):
166        """Attempt to update to the given image.
167
168        If rollback is True, we assume that cr50 is already running an image
169        that can rollback.
170
171        Args:
172            path: the location of the update image
173            rollback: True if we need to force cr50 to rollback to update to
174                      the given image
175            erase_nvmem: True if we need to erase nvmem during rollback
176            expect_rollback: True if cr50 should rollback on its own
177
178        Raises:
179            TestFail if the update failed
180        """
181        original_ver = self.cr50.get_version()
182
183        rw_ver = self._cr50_run_update(path)
184
185        # Running the update may cause cr50 to reboot. Wait for that before
186        # sending more commands
187        self.cr50.wait_for_reboot()
188
189        if erase_nvmem and rollback:
190            self.cr50.erase_nvmem()
191
192        # Don't erase flashinfo during rollback. That would mess with the board
193        # id
194        if rollback:
195            self.cr50.rollback()
196
197        expected_ver = original_ver if expect_rollback else rw_ver
198        # If we expect a rollback, the version should remain unchanged
199        self._cr50_verify_update(expected_ver, rollback or expect_rollback)
200