# Copyright 2020 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """Implements commands for running and interacting with Fuchsia generic build on devices.""" import boot_data import device_target import logging import os from common import SDK_ROOT, EnsurePathExists, \ GetHostToolPathFromPlatform, SubprocessCallWithTimeout def GetTargetType(): return GenericX64PavedDeviceTarget class GenericX64PavedDeviceTarget(device_target.DeviceTarget): """In addition to the functionality provided by DeviceTarget, this class automatically handles paving of x64 devices that use generic Fuchsia build. If there are no running devices, then search for a device running Zedboot and pave it. If there's only one running device, or |_node_name| is set, then the device's SDK version is checked unless --os-check=ignore is set. If --os-check=update is set, then the target device is repaved if the SDK version doesn't match.""" TARGET_HASH_FILE_PATH = '/data/.hash' def _SDKHashMatches(self): """Checks if /data/.hash on the device matches SDK_ROOT/.hash. Returns True if the files are identical, or False otherwise. """ with tempfile.NamedTemporaryFile() as tmp: # TODO: Avoid using an exception for when file is unretrievable. try: self.GetFile(TARGET_HASH_FILE_PATH, tmp.name) except subprocess.CalledProcessError: # If the file is unretrievable for whatever reason, assume mismatch. return False return filecmp.cmp(tmp.name, os.path.join(SDK_ROOT, '.hash'), False) def _ProvisionDeviceIfNecessary(self): should_provision = False if self._Discover(): self._WaitUntilReady() if self._os_check != 'ignore': if self._SDKHashMatches(): if self._os_check == 'update': logging.info('SDK hash does not match; rebooting and repaving.') self.RunCommand(['dm', 'reboot']) should_provision = True elif self._os_check == 'check': raise Exception('Target device SDK version does not match.') else: should_provision = True if should_provision: self._ProvisionDevice() def _ProvisionDevice(self): """Pave a device with a generic image of Fuchsia.""" bootserver_path = GetHostToolPathFromPlatform('bootserver') bootserver_command = [ bootserver_path, '-1', '--fvm', EnsurePathExists( boot_data.GetTargetFile('storage-sparse.blk', self._GetTargetSdkArch(), boot_data.TARGET_TYPE_GENERIC)), EnsurePathExists( boot_data.GetBootImage(self._out_dir, self._GetTargetSdkArch(), boot_data.TARGET_TYPE_GENERIC)) ] if self._node_name: bootserver_command += ['-n', self._node_name] bootserver_command += ['--'] bootserver_command += boot_data.GetKernelArgs(self._out_dir) logging.debug(' '.join(bootserver_command)) _, stdout = SubprocessCallWithTimeout(bootserver_command, silent=False, timeout_secs=300) self._ParseNodename(stdout) # Update the target's hash to match the current tree's. self.PutFile(os.path.join(SDK_ROOT, '.hash'), TARGET_HASH_FILE_PATH)