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 5 import logging 6 import random 7 import time 8 9 from autotest_lib.client.common_lib import error 10 from autotest_lib.client.common_lib.cros import tpm_utils 11 from autotest_lib.server.cros.update_engine import update_engine_test 12 13 class autoupdate_ForcedOOBEUpdate(update_engine_test.UpdateEngineTest): 14 """Runs a forced autoupdate during OOBE.""" 15 version = 1 16 17 18 def cleanup(self): 19 self._host.run('rm %s' % self._CUSTOM_LSB_RELEASE, ignore_status=True) 20 21 # Get the last two update_engine logs: before and after reboot. 22 self._save_extra_update_engine_logs() 23 self._change_cellular_setting_in_update_engine(False) 24 25 # Cancel any update still in progress. 26 if not self._is_update_engine_idle(): 27 logging.debug('Canceling the in-progress update.') 28 self._host.run('restart update-engine') 29 super(autoupdate_ForcedOOBEUpdate, self).cleanup() 30 31 32 def _wait_for_oobe_update_to_complete(self): 33 """Wait for the update that started to complete. 34 35 Repeated check status of update. It should move from DOWNLOADING to 36 FINALIZING to COMPLETE (then reboot) to IDLE. 37 """ 38 # 20 minute timeout. 39 timeout_minutes = 20 40 timeout = time.time() + 60 * timeout_minutes 41 while True: 42 status = self._get_update_engine_status(timeout=10) 43 44 # During reboot, status will be None 45 if status is not None: 46 if self._UPDATE_STATUS_IDLE == status[self._CURRENT_OP]: 47 break 48 time.sleep(1) 49 if time.time() > timeout: 50 raise error.TestFail('OOBE update did not finish in %d ' 51 'minutes.' % timeout_minutes) 52 53 54 def run_once(self, full_payload=True, cellular=False, 55 interrupt=False, max_updates=1, job_repo_url=None): 56 """ 57 Runs a forced autoupdate during ChromeOS OOBE. 58 59 @param full_payload: True for a full payload. False for delta. 60 @param cellular: True to do the update over a cellualar connection. 61 Requires that the DUT have a sim card slot. 62 @param interrupt: True to interrupt the update in the middle. 63 @param max_updates: Used to tell the test how many times it is 64 expected to ping its omaha server. 65 @param job_repo_url: Used for debugging locally. This is used to figure 66 out the current build and the devserver to use. 67 The test will read this from a host argument 68 when run in the lab. 69 70 """ 71 tpm_utils.ClearTPMOwnerRequest(self._host) 72 73 # veyron_rialto is a medical device with a different OOBE that auto 74 # completes so this test is not valid on that device. 75 if 'veyron_rialto' in self._host.get_board(): 76 raise error.TestNAError('Rialto has a custom OOBE. Skipping test.') 77 78 update_url = self.get_update_url_for_test(job_repo_url, 79 full_payload=full_payload, 80 critical_update=True, 81 public=cellular, 82 max_updates=max_updates) 83 before = self._get_chromeos_version() 84 payload_info = None 85 if cellular: 86 self._change_cellular_setting_in_update_engine(True) 87 # Get the payload's information (size, SHA256 etc) since we will be 88 # setting up our own omaha instance on the DUT. We pass this to 89 # the client test. 90 payload = self._get_payload_url(full_payload=full_payload) 91 staged_url = self._stage_payload_by_uri(payload) 92 payload_info = self._get_staged_file_info(staged_url) 93 94 # Call client test to start the forced OOBE update. 95 self._run_client_test_and_check_result('autoupdate_StartOOBEUpdate', 96 image_url=update_url, 97 cellular=cellular, 98 payload_info=payload_info, 99 full_payload=full_payload) 100 101 102 if interrupt: 103 # Choose a random downloaded progress to interrupt the update. 104 progress = random.uniform(0.1, 0.8) 105 logging.debug('Progress when we will interrupt: %f', progress) 106 self._wait_for_progress(progress) 107 logging.info('We will start interrupting the update.') 108 109 # Reboot the DUT during the update. 110 self._take_screenshot('before_reboot.png') 111 completed = self._get_update_progress() 112 self._host.reboot() 113 # Screenshot to check that if OOBE was not skipped by interruption. 114 self._take_screenshot('after_reboot.png') 115 if self._is_update_finished_downloading(): 116 raise error.TestError('Reboot interrupt: Update finished ' 117 'downloading before any more ' 118 'interruptions. Started interrupting ' 119 'at: %f' % progress) 120 if self._is_update_engine_idle(): 121 raise error.TestFail('The update was IDLE after reboot.') 122 123 # Disconnect / Reconnect network. 124 completed = self._get_update_progress() 125 self._disconnect_then_reconnect_network(update_url) 126 self._take_screenshot('after_network.png') 127 if self._is_update_finished_downloading(): 128 raise error.TestError('Network interrupt: Update finished ' 129 'downloading before any more ' 130 'interruptions. Started interrupting ' 131 'at: %f' % progress) 132 if not self._update_continued_where_it_left_off(completed): 133 raise error.TestFail('The update did not continue where it ' 134 'left off before disconnecting network.') 135 136 # Suspend / Resume. 137 completed = self._get_update_progress() 138 self._suspend_then_resume() 139 self._take_screenshot('after_suspend.png') 140 if self._is_update_finished_downloading(): 141 raise error.TestError('Suspend interrupt: Update finished ' 142 'downloading before any more ' 143 'interruptions. Started interrupting ' 144 'at: %f' % progress) 145 if not self._update_continued_where_it_left_off(completed): 146 raise error.TestFail('The update did not continue where it ' 147 'left off after suspend/resume.') 148 149 self._wait_for_oobe_update_to_complete() 150 151 if cellular: 152 # We didn't have a devserver so we cannot check the hostlog to 153 # ensure the update completed successfully. Instead we can check 154 # that the second-to-last update engine log has the successful 155 # update message. Second to last because its the one before OOBE 156 # rebooted. 157 before_reboot_file = self._get_second_last_update_engine_log() 158 self._check_for_cellular_entries_in_update_log(before_reboot_file) 159 success = 'Update successfully applied, waiting to reboot.' 160 self._check_update_engine_log_for_entry(success, 161 raise_error=True, 162 update_engine_log= 163 before_reboot_file) 164 return 165 166 # Verify that the update completed successfully by checking hostlog. 167 rootfs_hostlog, reboot_hostlog = self._create_hostlog_files() 168 self.verify_update_events(self._CUSTOM_LSB_VERSION, rootfs_hostlog) 169 self.verify_update_events(self._CUSTOM_LSB_VERSION, reboot_hostlog, 170 self._CUSTOM_LSB_VERSION) 171 172 after = self._get_chromeos_version() 173 logging.info('Successfully force updated from %s to %s.', before, after) 174