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