diff options
author | Hsin-Yi Chen <hsinyichen@google.com> | 2022-04-13 10:41:58 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2022-04-13 10:41:58 +0000 |
commit | 1ce4850f6b6cce08671f6e6a45b3baa82784460a (patch) | |
tree | e47c3e3e7542720fe7623a6d7fd5a563870c8c77 | |
parent | f5d75f9e4b602833370b75628d8f00db8fadd2c3 (diff) | |
parent | a589f388b20252416abfcc6dec1896bd6a334834 (diff) | |
download | acloud-1ce4850f6b6cce08671f6e6a45b3baa82784460a.tar.gz |
Merge "Support local cuttlefish instances with mixed vendor_boot.img" am: eb3c30ec2f am: a589f388b2
Original change: https://android-review.googlesource.com/c/platform/tools/acloud/+/2059349
Change-Id: Ie8a36233798aa7183862054de7adfc1b8814a6ee
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
-rw-r--r-- | create/create_common.py | 6 | ||||
-rw-r--r-- | create/create_common_test.py | 5 | ||||
-rw-r--r-- | create/local_image_local_instance.py | 56 | ||||
-rw-r--r-- | create/local_image_local_instance_test.py | 93 | ||||
-rw-r--r-- | create/remote_image_local_instance.py | 3 | ||||
-rw-r--r-- | internal/lib/cvd_utils.py | 34 | ||||
-rw-r--r-- | internal/lib/cvd_utils_test.py | 2 |
7 files changed, 120 insertions, 79 deletions
diff --git a/create/create_common.py b/create/create_common.py index 1d1a5212..a5694d7b 100644 --- a/create/create_common.py +++ b/create/create_common.py @@ -146,7 +146,7 @@ def GetCvdHostPackage(package_path=None): '\n'.join(dirs_to_check)) -def FindLocalImage(path, default_name_pattern): +def FindLocalImage(path, default_name_pattern, raise_error=True): """Find an image file in the given path. Args: @@ -165,7 +165,9 @@ def FindLocalImage(path, default_name_pattern): names = [name for name in os.listdir(path) if re.fullmatch(default_name_pattern, name)] if not names: - raise errors.GetLocalImageError("No image in %s." % path) + if raise_error: + raise errors.GetLocalImageError("No image in %s." % path) + return None if len(names) != 1: raise errors.GetLocalImageError("More than one image in %s: %s" % (path, " ".join(names))) diff --git a/create/create_common_test.py b/create/create_common_test.py index 0caa97a9..14503e6a 100644 --- a/create/create_common_test.py +++ b/create/create_common_test.py @@ -152,11 +152,14 @@ class CreateCommonTest(driver_test_lib.BaseDriverTest): self.assertEqual("/dir/name", create_common.FindLocalImage("/dir/", "name")) + + self.assertIsNone(create_common.FindLocalImage("/dir", "not_exist", + raise_error=False)) with self.assertRaises(errors.GetLocalImageError): create_common.FindLocalImage("/dir", "not_exist") with self.assertRaises(errors.GetLocalImageError): - create_common.FindLocalImage("/dir", "name.?") + create_common.FindLocalImage("/dir", "name.?", raise_error=False) @mock.patch.object(utils, "Decompress") def testDownloadRemoteArtifact(self, mock_decompress): diff --git a/create/local_image_local_instance.py b/create/local_image_local_instance.py index c4c585fb..c5913fb4 100644 --- a/create/local_image_local_instance.py +++ b/create/local_image_local_instance.py @@ -62,6 +62,7 @@ from acloud import errors from acloud.create import base_avd_create from acloud.create import create_common from acloud.internal import constants +from acloud.internal.lib import cvd_utils from acloud.internal.lib import ota_tools from acloud.internal.lib import utils from acloud.internal.lib.adb_tools import AdbTools @@ -73,13 +74,6 @@ from acloud.setup import mkcert logger = logging.getLogger(__name__) -# The boot image name pattern corresponds to the use cases: -# - In a cuttlefish build environment, ANDROID_PRODUCT_OUT conatins boot.img -# and boot-debug.img. The former is the default boot image. The latter is not -# useful for cuttlefish. -# - In an officially released GKI (Generic Kernel Image) package, the image -# name is boot-<kernel version>.img. -_BOOT_IMAGE_NAME_PATTERN = r"boot(-[\d.]+)?\.img" _SYSTEM_IMAGE_NAME_PATTERN = r"system\.img" _MISC_INFO_FILE_NAME = "misc_info.txt" _TARGET_FILES_IMAGES_DIR_NAME = "IMAGES" @@ -97,6 +91,7 @@ _CMD_LAUNCH_CVD_WEBRTC_ARGS = " -start_webrtc=true" _CMD_LAUNCH_CVD_VNC_ARG = " -start_vnc_server=true" _CMD_LAUNCH_CVD_SUPER_IMAGE_ARG = " -super_image=%s" _CMD_LAUNCH_CVD_BOOT_IMAGE_ARG = " -boot_image=%s" +_CMD_LAUNCH_CVD_VENDOR_BOOT_IMAGE_ARG = " -vendor_boot_image=%s" _CMD_LAUNCH_CVD_NO_ADB_ARG = " -run_adb_connector=false" # Connect the OpenWrt device via console file. _CMD_LAUNCH_CVD_CONSOLE_ARG = " -console=true" @@ -127,7 +122,7 @@ _CONFIRM_RELAUNCH = ("\nCuttlefish AVD[id:%d] is already running. \n" ArtifactPaths = collections.namedtuple( "ArtifactPaths", ["image_dir", "host_bins", "host_artifacts", "misc_info", "ota_tools_dir", - "system_image", "boot_image"]) + "system_image", "boot_image", "vendor_boot_image"]) class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): @@ -236,8 +231,6 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): runtime_dir = instance.GetLocalInstanceRuntimeDir(local_instance_id) # TODO(b/168171781): cvd_status of list/delete via the symbolic. self.PrepareLocalCvdToolsLink(cvd_home_dir, artifact_paths.host_bins) - cvd_path = os.path.join(artifact_paths.host_bins, "bin", - constants.CMD_CVD) if avd_spec.mkcert and avd_spec.connect_webrtc: self._TrustCertificatesForWebRTC(artifact_paths.host_artifacts) @@ -246,15 +239,13 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): hw_property = avd_spec.hw_property config = self._GetConfigFromAndroidInfo( os.path.join(artifact_paths.image_dir, constants.ANDROID_INFO_FILE)) - cmd = self.PrepareLaunchCVDCmd(cvd_path, - hw_property, + cmd = self.PrepareLaunchCVDCmd(hw_property, avd_spec.connect_adb, - artifact_paths.image_dir, + artifact_paths, runtime_dir, avd_spec.connect_webrtc, avd_spec.connect_vnc, super_image_path, - artifact_paths.boot_image, avd_spec.launch_args, config or avd_spec.flavor, avd_spec.openwrt, @@ -436,17 +427,19 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): system_image_path = None if avd_spec.local_kernel_image: - boot_image_path = create_common.FindLocalImage( - avd_spec.local_kernel_image, _BOOT_IMAGE_NAME_PATTERN) + boot_image_path, vendor_boot_image_path = cvd_utils.FindBootImages( + avd_spec.local_kernel_image) else: boot_image_path = None + vendor_boot_image_path = None return ArtifactPaths(image_dir, host_bins_path, host_artifacts=host_artifacts_path, misc_info=misc_info_path, ota_tools_dir=ota_tools_dir, system_image=system_image_path, - boot_image=boot_image_path) + boot_image=boot_image_path, + vendor_boot_image=vendor_boot_image_path) @staticmethod def _MixSuperImage(output_dir, artifact_paths): @@ -490,26 +483,23 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): return None @staticmethod - def PrepareLaunchCVDCmd(cvd_path, hw_property, connect_adb, - image_dir, runtime_dir, connect_webrtc, - connect_vnc, super_image_path, boot_image_path, - launch_args, config, openwrt=False, - use_launch_cvd=False): + def PrepareLaunchCVDCmd(hw_property, connect_adb, artifact_paths, + runtime_dir, connect_webrtc, connect_vnc, + super_image_path, launch_args, config, + openwrt=False, use_launch_cvd=False): """Prepare launch_cvd command. Create the launch_cvd commands with all the required args and add in the user groups to it if necessary. Args: - cvd_path: String of cvd path. hw_property: dict object of hw property. - image_dir: String of local images path. + artifact_paths: ArtifactPaths object. connect_adb: Boolean flag that enables adb_connector. runtime_dir: String of runtime directory path. connect_webrtc: Boolean of connect_webrtc. connect_vnc: Boolean of connect_vnc. super_image_path: String of non-default super image path. - boot_image_path: String of non-default boot image path. launch_args: String of launch args. config: String of config name. openwrt: Boolean of enable OpenWrt devices. @@ -518,12 +508,13 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): Returns: String, cvd start cmd. """ - start_cvd_cmd = cvd_path + _CMD_CVD_START + bin_dir = os.path.join(artifact_paths.host_bins, "bin") + start_cvd_cmd = (os.path.join(bin_dir, constants.CMD_CVD) + + _CMD_CVD_START) if use_launch_cvd: - bin_dir = os.path.dirname(cvd_path) start_cvd_cmd = os.path.join(bin_dir, constants.CMD_LAUNCH_CVD) launch_cvd_w_args = start_cvd_cmd + _CMD_LAUNCH_CVD_ARGS % ( - config, image_dir, runtime_dir) + config, artifact_paths.image_dir, runtime_dir) if hw_property: launch_cvd_w_args = launch_cvd_w_args + _CMD_LAUNCH_CVD_HW_ARGS % ( hw_property["cpu"], hw_property["x_res"], hw_property["y_res"], @@ -546,10 +537,15 @@ class LocalImageLocalInstance(base_avd_create.BaseAVDCreate): _CMD_LAUNCH_CVD_SUPER_IMAGE_ARG % super_image_path) - if boot_image_path: + if artifact_paths.boot_image: launch_cvd_w_args = (launch_cvd_w_args + _CMD_LAUNCH_CVD_BOOT_IMAGE_ARG % - boot_image_path) + artifact_paths.boot_image) + + if artifact_paths.vendor_boot_image: + launch_cvd_w_args = (launch_cvd_w_args + + _CMD_LAUNCH_CVD_VENDOR_BOOT_IMAGE_ARG % + artifact_paths.vendor_boot_image) if openwrt: launch_cvd_w_args = launch_cvd_w_args + _CMD_LAUNCH_CVD_CONSOLE_ARG diff --git a/create/local_image_local_instance_test.py b/create/local_image_local_instance_test.py index 16f5d7fa..7baf9711 100644 --- a/create/local_image_local_instance_test.py +++ b/create/local_image_local_instance_test.py @@ -37,37 +37,37 @@ class LocalImageLocalInstanceTest(driver_test_lib.BaseDriverTest): LAUNCH_CVD_CMD_WITH_DISK = """sg group1 <<EOF sg group2 -cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -blank_data_image_mb fake -data_policy always_create -start_vnc_server=true +bin/cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -blank_data_image_mb fake -data_policy always_create -start_vnc_server=true EOF""" LAUNCH_CVD_CMD_NO_DISK = """sg group1 <<EOF sg group2 -cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -start_vnc_server=true +bin/cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -start_vnc_server=true EOF""" LAUNCH_CVD_CMD_NO_DISK_WITH_GPU = """sg group1 <<EOF sg group2 -cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -start_vnc_server=true +bin/cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -cpus fake -x_res fake -y_res fake -dpi fake -memory_mb fake -start_vnc_server=true EOF""" LAUNCH_CVD_CMD_WITH_WEBRTC = """sg group1 <<EOF sg group2 -cvd start -daemon -config=auto -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_webrtc=true +bin/cvd start -daemon -config=auto -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_webrtc=true EOF""" LAUNCH_CVD_CMD_WITH_MIXED_IMAGES = """sg group1 <<EOF sg group2 -cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_vnc_server=true -super_image=fake_super_image -boot_image=fake_boot_image +bin/cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_vnc_server=true -super_image=fake_super_image -boot_image=fake_boot_image -vendor_boot_image=fake_vendor_boot_image EOF""" LAUNCH_CVD_CMD_WITH_ARGS = """sg group1 <<EOF sg group2 -cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_vnc_server=true -setupwizard_mode=REQUIRED +bin/cvd start -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_vnc_server=true -setupwizard_mode=REQUIRED EOF""" LAUNCH_CVD_CMD_WITH_OPENWRT = """sg group1 <<EOF sg group2 -launch_cvd -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_vnc_server=true -console=true +bin/launch_cvd -daemon -config=phone -system_image_dir fake_image_dir -instance_dir fake_cvd_dir -undefok=report_anonymous_usage_stats,config -report_anonymous_usage_stats=y -start_vnc_server=true -console=true EOF""" _EXPECTED_DEVICES_IN_REPORT = [ @@ -118,7 +118,8 @@ EOF""" """Test _CreateAVD.""" mock_utils.IsSupportedPlatform.return_value = True mock_get_image.return_value = local_image_local_instance.ArtifactPaths( - "/image/path", "/host/bin/path", "host/usr/path", None, None, None, None) + "/image/path", "/host/bin/path", "host/usr/path", + None, None, None, None, None) mock_check_running_cvd.return_value = True mock_avd_spec = mock.Mock() mock_lock = mock.Mock() @@ -199,7 +200,8 @@ EOF""" "/instances/cvd/config") artifact_paths = local_image_local_instance.ArtifactPaths( "/image/path", "/host/bin/path", "/host/usr/path", "/misc/info/path", - "/ota/tools/dir", "/system/image/path", "/boot/image/path") + "/ota/tools/dir", "/system/image/path", "/boot/image/path", + "/vendor_boot/image/path") mock_ota_tools_object = mock.Mock() mock_ota_tools.OtaTools.return_value = mock_ota_tools_object mock_avd_spec = mock.Mock( @@ -288,24 +290,29 @@ EOF""" mock_avd_spec) mock_ota_tools.FindOtaToolsDir.assert_not_called() - self.assertEqual(paths, (image_dir, cvd_dir, cvd_dir, None, None, None, None)) + self.assertEqual(paths, (image_dir, cvd_dir, cvd_dir, + None, None, None, None, None)) @mock.patch("acloud.create.local_image_local_instance.ota_tools") - def testGetImageFromBuildEnvironment(self, mock_ota_tools): + @mock.patch("acloud.create.local_image_local_instance.cvd_utils") + def testGetImageFromBuildEnvironment(self, mock_cvd_utils, mock_ota_tools): """Test GetImageArtifactsPath with files in build environment.""" + boot_image_path = "/mock/boot.img" + vendor_boot_image_path = "/mock/vendor_boot.img" + mock_cvd_utils.FindBootImages.return_value = (boot_image_path, + vendor_boot_image_path) + with tempfile.TemporaryDirectory() as temp_dir: image_dir = os.path.join(temp_dir, "image") cvd_dir = os.path.join(temp_dir, "cvd-host_package") mock_ota_tools.FindOtaToolsDir.return_value = cvd_dir extra_image_dir = os.path.join(temp_dir, "extra_image") system_image_path = os.path.join(extra_image_dir, "system.img") - boot_image_path = os.path.join(extra_image_dir, "boot.img") misc_info_path = os.path.join(image_dir, "misc_info.txt") self._CreateEmptyFile(os.path.join(image_dir, "vbmeta.img")) self._CreateEmptyFile(os.path.join(cvd_dir, "bin", "launch_cvd")) self._CreateEmptyFile(os.path.join(cvd_dir, "usr/share/webrtc/certs", "server.crt")) self._CreateEmptyFile(system_image_path) - self._CreateEmptyFile(boot_image_path) self._CreateEmptyFile(os.path.join(extra_image_dir, "boot-debug.img")) self._CreateEmptyFile(misc_info_path) @@ -325,29 +332,33 @@ EOF""" mock_avd_spec) mock_ota_tools.FindOtaToolsDir.assert_called_with([cvd_dir, "/cvd"]) + mock_cvd_utils.FindBootImages.asssert_called_with(extra_image_dir) self.assertEqual(paths, (image_dir, cvd_dir, cvd_dir, misc_info_path, cvd_dir, - system_image_path, boot_image_path)) + system_image_path, boot_image_path, + vendor_boot_image_path)) @mock.patch("acloud.create.local_image_local_instance.ota_tools") - def testGetImageFromTargetFiles(self, mock_ota_tools): + @mock.patch("acloud.create.local_image_local_instance.cvd_utils") + def testGetImageFromTargetFiles(self, mock_cvd_utils, mock_ota_tools): """Test GetImageArtifactsPath with extracted target files.""" ota_tools_dir = "/mock_ota_tools" mock_ota_tools.FindOtaToolsDir.return_value = ota_tools_dir + boot_image_path = "/mock/boot.img" + mock_cvd_utils.FindBootImages.return_value = (boot_image_path, None) with tempfile.TemporaryDirectory() as temp_dir: image_dir = os.path.join(temp_dir, "image") cvd_dir = os.path.join(temp_dir, "cvd-host_package") system_image_path = os.path.join(temp_dir, "system", "test.img") misc_info_path = os.path.join(image_dir, "META", "misc_info.txt") - boot_image_path = os.path.join(temp_dir, "boot", "test.img") + self._CreateEmptyFile(os.path.join(image_dir, "IMAGES", "vbmeta.img")) self._CreateEmptyFile(os.path.join(cvd_dir, "bin", "launch_cvd")) self._CreateEmptyFile(os.path.join(cvd_dir, "usr/share/webrtc/certs", "server.crt")) self._CreateEmptyFile(system_image_path) self._CreateEmptyFile(misc_info_path) - self._CreateEmptyFile(boot_image_path) mock_avd_spec = mock.Mock( local_image_dir=image_dir, @@ -363,10 +374,11 @@ EOF""" mock_ota_tools.FindOtaToolsDir.assert_called_with( [ota_tools_dir, cvd_dir]) + mock_cvd_utils.FindBootImages.assert_called_with(boot_image_path) self.assertEqual(paths, (os.path.join(image_dir, "IMAGES"), cvd_dir, cvd_dir, misc_info_path, ota_tools_dir, system_image_path, - boot_image_path)) + boot_image_path, None)) @mock.patch.object(utils, "CheckUserInGroups") def testPrepareLaunchCVDCmd(self, mock_usergroups): @@ -375,50 +387,61 @@ EOF""" hw_property = {"cpu": "fake", "x_res": "fake", "y_res": "fake", "dpi":"fake", "memory": "fake", "disk": "fake"} constants.LIST_CF_USER_GROUPS = ["group1", "group2"] + mock_artifact_paths = mock.Mock( + spec=[], + image_dir="fake_image_dir", + host_bins="", + host_artifacts="host_artifacts", + misc_info=None, + ota_tools_dir=None, + system_image=None, + boot_image=None, + vendor_boot_image=None) launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_CVD, hw_property, True, "fake_image_dir", - "fake_cvd_dir", False, True, None, None, None, "phone") + hw_property, True, mock_artifact_paths, "fake_cvd_dir", False, + True, None, None, "phone") self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_DISK) # "disk" doesn't exist in hw_property. hw_property = {"cpu": "fake", "x_res": "fake", "y_res": "fake", "dpi": "fake", "memory": "fake"} launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_CVD, hw_property, True, "fake_image_dir", - "fake_cvd_dir", False, True, None, None, None, "phone") + hw_property, True, mock_artifact_paths, "fake_cvd_dir", False, + True, None, None, "phone") self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_NO_DISK) # "gpu" is enabled with "default" launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_CVD, hw_property, True, "fake_image_dir", - "fake_cvd_dir", False, True, None, None, None, "phone") + hw_property, True, mock_artifact_paths, "fake_cvd_dir", False, + True, None, None, "phone") self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_NO_DISK_WITH_GPU) # Following test with hw_property is None. launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_CVD, None, True, "fake_image_dir", - "fake_cvd_dir", True, False, None, None, None, "auto") + None, True, mock_artifact_paths, "fake_cvd_dir", True, False, + None, None, "auto") self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_WEBRTC) + mock_artifact_paths.boot_image = "fake_boot_image" + mock_artifact_paths.vendor_boot_image = "fake_vendor_boot_image" launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_CVD, None, True, "fake_image_dir", - "fake_cvd_dir", False, True, "fake_super_image", "fake_boot_image", - None, "phone") + None, True, mock_artifact_paths, "fake_cvd_dir", False, True, + "fake_super_image", None, "phone") self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_MIXED_IMAGES) + mock_artifact_paths.boot_image = None + mock_artifact_paths.vendor_boot_image = None # Add args into launch command with "-setupwizard_mode=REQUIRED" launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_CVD, None, True, "fake_image_dir", - "fake_cvd_dir", False, True, None, None, - "-setupwizard_mode=REQUIRED", "phone") + None, True, mock_artifact_paths, "fake_cvd_dir", False, True, + None, "-setupwizard_mode=REQUIRED", "phone") self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_ARGS) # Test with "openwrt" and "use_launch_cvd" are enabled. launch_cmd = self.local_image_local_instance.PrepareLaunchCVDCmd( - constants.CMD_LAUNCH_CVD, None, True, "fake_image_dir", - "fake_cvd_dir", False, True, None, None, None, - "phone", openwrt=True, use_launch_cvd=True) + None, True, mock_artifact_paths, "fake_cvd_dir", False, True, + None, None, "phone", openwrt=True, use_launch_cvd=True) self.assertEqual(launch_cmd, self.LAUNCH_CVD_CMD_WITH_OPENWRT) @mock.patch.object(utils, "GetUserAnswerYes") diff --git a/create/remote_image_local_instance.py b/create/remote_image_local_instance.py index acde2cb6..d0d0958f 100644 --- a/create/remote_image_local_instance.py +++ b/create/remote_image_local_instance.py @@ -247,4 +247,5 @@ class RemoteImageLocalInstance(local_image_local_instance.LocalImageLocalInstanc misc_info=misc_info_path, ota_tools_dir=ota_tools_dir, system_image=system_image_path, - boot_image=None) + boot_image=None, + vendor_boot_image=None) diff --git a/internal/lib/cvd_utils.py b/internal/lib/cvd_utils.py index 42cbe8a8..20534efe 100644 --- a/internal/lib/cvd_utils.py +++ b/internal/lib/cvd_utils.py @@ -20,6 +20,7 @@ import os import posixpath as remote_path from acloud import errors +from acloud.create import create_common from acloud.internal import constants from acloud.internal.lib import ssh from acloud.internal.lib import utils @@ -31,11 +32,17 @@ logger = logging.getLogger(__name__) # bootloader and kernel are files required to launch AVD. _ARTIFACT_FILES = ["*.img", "bootloader", "kernel"] _REMOTE_IMAGE_DIR = "acloud_cf" -_BOOT_IMAGE_NAME = "boot.img" +# The boot image name pattern corresponds to the use cases: +# - In a cuttlefish build environment, ANDROID_PRODUCT_OUT conatins boot.img +# and boot-debug.img. The former is the default boot image. The latter is not +# useful for cuttlefish. +# - In an officially released GKI (Generic Kernel Image) package, the image +# name is boot-<kernel version>.img. +_BOOT_IMAGE_NAME_PATTERN = r"boot(-[\d.]+)?\.img" _VENDOR_BOOT_IMAGE_NAME = "vendor_boot.img" _KERNEL_IMAGE_NAMES = ("kernel", "bzImage", "Image") _INITRAMFS_IMAGE_NAME = "initramfs.img" -_REMOTE_BOOT_IMAGE_PATH = remote_path.join(_REMOTE_IMAGE_DIR, _BOOT_IMAGE_NAME) +_REMOTE_BOOT_IMAGE_PATH = remote_path.join(_REMOTE_IMAGE_DIR, "boot.img") _REMOTE_VENDOR_BOOT_IMAGE_PATH = remote_path.join( _REMOTE_IMAGE_DIR, _VENDOR_BOOT_IMAGE_NAME) _REMOTE_KERNEL_IMAGE_PATH = remote_path.join( @@ -139,7 +146,7 @@ def _IsBootImage(image_path): return image_file.read(8) == _ANDROID_BOOT_IMAGE_MAGIC -def _FindBootImages(search_path): +def FindBootImages(search_path): """Find boot and vendor_boot images in a path. Args: @@ -148,13 +155,22 @@ def _FindBootImages(search_path): Returns: The boot image path and the vendor_boot image path. Each value can be None if the path doesn't exist. + + Raises: + errors.GetLocalImageError if search_path contains more than one boot + image or the file format is not correct. """ - if _IsBootImage(search_path): - return search_path, None + boot_image_path = create_common.FindLocalImage( + search_path, _BOOT_IMAGE_NAME_PATTERN, raise_error=False) + if boot_image_path and not _IsBootImage(boot_image_path): + raise errors.GetLocalImageError( + f"{boot_image_path} is not a boot image.") + + vendor_boot_image_path = os.path.join(search_path, _VENDOR_BOOT_IMAGE_NAME) + if not os.path.isfile(vendor_boot_image_path): + vendor_boot_image_path = None - paths = [os.path.join(search_path, name) for name in - (_BOOT_IMAGE_NAME, _VENDOR_BOOT_IMAGE_NAME)] - return [(path if os.path.isfile(path) else None) for path in paths] + return boot_image_path, vendor_boot_image_path def _FindKernelImages(search_path): @@ -196,7 +212,7 @@ def _UploadKernelImages(ssh_obj, search_path): # Assume that the caller cleaned up the remote home directory. ssh_obj.Run("mkdir -p " + _REMOTE_IMAGE_DIR) - boot_image_path, vendor_boot_image_path = _FindBootImages(search_path) + boot_image_path, vendor_boot_image_path = FindBootImages(search_path) if boot_image_path: ssh_obj.ScpPushFile(boot_image_path, _REMOTE_BOOT_IMAGE_PATH) launch_cvd_args = ["-boot_image", _REMOTE_BOOT_IMAGE_PATH] diff --git a/internal/lib/cvd_utils_test.py b/internal/lib/cvd_utils_test.py index 14e79934..ab0e82ac 100644 --- a/internal/lib/cvd_utils_test.py +++ b/internal/lib/cvd_utils_test.py @@ -81,7 +81,7 @@ class CvdUtilsTest(unittest.TestCase): mock_ssh.Run.assert_called_with(expected_ssh_cmd) def testUploadBootImages(self): - """Test UploadExtraImages with boot images.""" + """Test FindBootImages and UploadExtraImages.""" mock_ssh = mock.Mock() with tempfile.TemporaryDirectory(prefix="cvd_utils") as image_dir: boot_image_path = os.path.join(image_dir, "boot.img") |