# Copyright 2018 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import time from autotest_lib.client.common_lib import error from autotest_lib.client.common_lib.cros import cr50_utils from autotest_lib.server.cros.faft.cr50_test import Cr50Test class firmware_Cr50RejectUpdate(Cr50Test): """Verify cr50 rejects certain updates.""" version = 1 OLD_IMAGE_VER = '0.0.18' # We dont care that it actually matches the device devid. It will be # rejected before the update. This is just one that I picked from google # storage IMAGE_DEVID = '0x1000d059 0x04657208' # No boards use the bid TEST. Use this image to verify cr50 rejects images # with the wrong board id. BID = 'TEST:0000ffff:0000ff00' TEST_PATH = '/tmp/test_image.bin' def initialize(self, host, cmdline_args): """Initialize servo and download images""" super(firmware_Cr50RejectUpdate, self).initialize(host, cmdline_args, restore_cr50_state=True) if not hasattr(self, 'cr50'): raise error.TestNAError('Test can only be run on devices with ' 'access to the Cr50 console') if 'DBG' in self.cr50.get_version(): raise error.TestNAError('Update rules are wonky on DBG images') if cr50_utils.GetChipBoardId(host) == cr50_utils.ERASED_CHIP_BID: raise error.TestNAError('Set Cr50 board id to run test') self.bid_path = self.download_cr50_debug_image(self.IMAGE_DEVID, self.BID)[0] self.old_path = self.download_cr50_release_image(self.OLD_IMAGE_VER)[0] self.original_path = self.get_saved_cr50_original_path() self.host = host def cleanup(self): """Reboot the device to restart trunksd""" self.host.reboot() super(firmware_Cr50RejectUpdate, self).cleanup() def try_update(self, arg, path, err=0, stdout='', wait=True): """Run gsctool with the given image and args. Verify the result Args: arg: strings with the gsctool args path: local path to the test image err: The error number stdout: a string that must be included in the cmd stdout wait: Wait for cr50 to have been up for 60 seconds before attempting the update. Raises: TestFail if there is an unexpected result. """ # Copy the image to the DUT self.host.send_file(path, self.TEST_PATH) # Wait for cr50 to have been up for 60 seconds, so it won't # automatically reject the image. if wait: self.cr50.wait_until_update_is_allowed() # Try to update result = self.host.run('gsctool -a %s %s' % (arg, self.TEST_PATH), ignore_status=True, ignore_timeout=True, timeout=60) # Check the result stderr = 'Error %d' % err if err and stderr not in result.stderr: raise error.TestFail('"%s" not in "%s"' % (stderr, result.stderr)) if stdout and stdout not in result.stdout: raise error.TestFail('"%s" not in "%s"' % (stdout, result.stdout)) def run_once(self): """Verify cr50 rejects certain updates""" # Cr50 rejects a mismatched board id no matter what self.try_update('-u', self.bid_path, err=12) self.try_update('', self.bid_path, err=12) # With the '-u' option cr50 rejects any images with old/same header # with 'nothing to do' self.try_update('-u', self.old_path, stdout='nothing to do') self.try_update('-u', self.original_path, stdout='nothing to do') # Without '-u' cr50 rejects old headers self.try_update('', self.old_path, err=8) # Cr50 will accept images with the same header version if -u is omitted. # original_path is the image already on cr50, so this won't have any # real effect. It will just reboot the device. self.try_update('', self.original_path, stdout='image updated') # Wait a bit for the reboot time.sleep(5) # After any reboot, cr50 will reject images for 60 seconds self.try_update('', self.original_path, err=9, wait=False)