Support single command of using remote ab build mixed with local GSI system image by acloud.
Bug: 213494874
Test: acloud-dev create --branch git_sc-gsi-release --build-target aosp_cf_x86_64_phone-userdebug --local-system-image ${ANDROID_BUILD_TOP}/out/target/product/generic_x86_64 --local-instance -vv
Change-Id: Ibfd0103bc55d9734b324453c87068325b17b7ce7
diff --git a/create/avd_spec.py b/create/avd_spec.py
index 08972e1..8963e58 100644
--- a/create/avd_spec.py
+++ b/create/avd_spec.py
@@ -229,6 +229,9 @@
if args.local_image is None:
self._image_source = constants.IMAGE_SRC_REMOTE
self._ProcessRemoteBuildArgs(args)
+ if args.local_system_image is not None:
+ self._local_system_image = self._GetLocalImagePath(
+ args.local_system_image)
else:
self._image_source = constants.IMAGE_SRC_LOCAL
self._ProcessLocalImageArgs(args)
diff --git a/create/avd_spec_test.py b/create/avd_spec_test.py
index 62c2b8f..c5874b1 100644
--- a/create/avd_spec_test.py
+++ b/create/avd_spec_test.py
@@ -177,9 +177,18 @@
self.Patch(glob, "glob", return_value=["fake.img"])
# No specified local_image, image source is from remote
self.args.local_image = None
+ self.args.local_system_image = None
self.AvdSpec._ProcessImageArgs(self.args)
self.assertEqual(self.AvdSpec._image_source, constants.IMAGE_SRC_REMOTE)
self.assertEqual(self.AvdSpec._local_image_dir, None)
+ self.assertEqual(self.AvdSpec.local_system_image, None)
+
+ self.args.local_system_image = "/test_path/local_system_image"
+ fake_local_system_image = "/fake_path/fake_local_system_image_path"
+ self.Patch(self.AvdSpec, "_GetLocalImagePath",
+ return_value=fake_local_system_image)
+ self.AvdSpec._ProcessImageArgs(self.args)
+ self.assertEqual(self.AvdSpec.local_system_image, fake_local_system_image)
# Specified local_image with an arg for cf type
self.Patch(os.path, "isfile", return_value=True)
diff --git a/create/local_image_local_instance.py b/create/local_image_local_instance.py
index 52c5b8a..930bb8f 100644
--- a/create/local_image_local_instance.py
+++ b/create/local_image_local_instance.py
@@ -344,7 +344,7 @@
"set --local-tool to an extracted CVD host package.")
@staticmethod
- def _FindMiscInfo(image_dir):
+ def FindMiscInfo(image_dir):
"""Find misc info in build output dir or extracted target files.
Args:
@@ -369,7 +369,7 @@
"Cannot find %s in %s." % (_MISC_INFO_FILE_NAME, image_dir))
@staticmethod
- def _FindImageDir(image_dir):
+ def FindImageDir(image_dir):
"""Find images in build output dir or extracted target files.
Args:
@@ -419,8 +419,8 @@
host_artifacts_path = self._FindCvdHostArtifactsPath(tool_dirs)
if avd_spec.local_system_image:
- misc_info_path = self._FindMiscInfo(image_dir)
- image_dir = self._FindImageDir(image_dir)
+ misc_info_path = self.FindMiscInfo(image_dir)
+ image_dir = self.FindImageDir(image_dir)
ota_tools_dir = os.path.abspath(
ota_tools.FindOtaToolsDir(tool_dirs))
system_image_path = create_common.FindLocalImage(
diff --git a/create/remote_image_local_instance.py b/create/remote_image_local_instance.py
index 8d989a8..acde2cb 100644
--- a/create/remote_image_local_instance.py
+++ b/create/remote_image_local_instance.py
@@ -25,10 +25,12 @@
import sys
from acloud import errors
+from acloud.create import create_common
from acloud.create import local_image_local_instance
from acloud.internal import constants
from acloud.internal.lib import android_build_client
from acloud.internal.lib import auth
+from acloud.internal.lib import ota_tools
from acloud.internal.lib import utils
from acloud.setup import setup_common
@@ -50,6 +52,10 @@
# for the downloaded image artifacts.
_REQUIRED_SPACE = 10
+_SYSTEM_IMAGE_NAME_PATTERN = r"system\.img"
+_SYSTEM_MIX_IMAGE_DIR = "mix_image_{build_id}"
+_DOWNLOAD_MIX_IMAGE_NAME = "{build_target}-target_files-{build_id}.zip"
+
@utils.TimeExecute(function_description="Downloading Android Build image")
def DownloadAndProcessImageFiles(avd_spec):
@@ -154,6 +160,21 @@
return download_dir
+def GetMixBuildTargetFilename(build_target, build_id):
+ """Get the mix build target filename.
+
+ Args:
+ build_id: String, Build id, e.g. "2263051", "P2804227"
+ build_target: String, the build target, e.g. cf_x86_phone-userdebug
+
+ Returns:
+ String, a file name, e.g. "cf_x86_phone-target_files-2263051.zip"
+ """
+ return _DOWNLOAD_MIX_IMAGE_NAME.format(
+ build_target=build_target.split('-')[0],
+ build_id=build_id)
+
+
class RemoteImageLocalInstance(local_image_local_instance.LocalImageLocalInstance):
"""Create class for a remote image local instance AVD.
@@ -189,7 +210,41 @@
raise errors.GetCvdLocalHostPackageError(
"No launch_cvd found. Please check downloaded artifacts dir: %s"
% image_dir)
+
+ mix_image_dir = None
+ if avd_spec.local_system_image:
+ build_id = avd_spec.remote_image[constants.BUILD_ID]
+ build_target = avd_spec.remote_image[constants.BUILD_TARGET]
+ mix_image_dir =os.path.join(
+ image_dir, _SYSTEM_MIX_IMAGE_DIR.format(build_id=build_id))
+ if not os.path.exists(mix_image_dir):
+ os.makedirs(mix_image_dir)
+ create_common.DownloadRemoteArtifact(
+ avd_spec.cfg, build_target, build_id,
+ GetMixBuildTargetFilename(build_target, build_id),
+ mix_image_dir, decompress=True)
+ misc_info_path = super().FindMiscInfo(mix_image_dir)
+ mix_image_dir = super().FindImageDir(mix_image_dir)
+ tool_dirs = (avd_spec.local_tool_dirs +
+ create_common.GetNonEmptyEnvVars(
+ constants.ENV_ANDROID_SOONG_HOST_OUT,
+ constants.ENV_ANDROID_HOST_OUT))
+ ota_tools_dir = os.path.abspath(
+ ota_tools.FindOtaToolsDir(tool_dirs))
+ system_image_path = create_common.FindLocalImage(
+ avd_spec.local_system_image, _SYSTEM_IMAGE_NAME_PATTERN)
+ else:
+ misc_info_path = None
+ ota_tools_dir = None
+ system_image_path = None
+
# This method does not set the optional fields because launch_cvd loads
# the paths from the fetcher config in image_dir.
return local_image_local_instance.ArtifactPaths(
- image_dir, image_dir, image_dir, None, None, None, None)
+ image_dir=mix_image_dir or image_dir,
+ host_bins=image_dir,
+ host_artifacts=image_dir,
+ misc_info=misc_info_path,
+ ota_tools_dir=ota_tools_dir,
+ system_image=system_image_path,
+ boot_image=None)
diff --git a/create/remote_image_local_instance_test.py b/create/remote_image_local_instance_test.py
index 8eda639..135fafa 100644
--- a/create/remote_image_local_instance_test.py
+++ b/create/remote_image_local_instance_test.py
@@ -22,15 +22,18 @@
from unittest import mock
from acloud import errors
+from acloud.create import create_common
from acloud.create import remote_image_local_instance
+from acloud.create import local_image_local_instance
from acloud.internal.lib import android_build_client
from acloud.internal.lib import auth
from acloud.internal.lib import driver_test_lib
+from acloud.internal.lib import ota_tools
from acloud.internal.lib import utils
from acloud.setup import setup_common
-# pylint: disable=invalid-name, protected-access
+# pylint: disable=invalid-name, protected-access, no-member
class RemoteImageLocalInstanceTest(driver_test_lib.BaseDriverTest):
"""Test remote_image_local_instance methods."""
@@ -54,6 +57,7 @@
"""Test get image artifacts path."""
mock_proc.return_value = "/unit/test"
avd_spec = mock.MagicMock()
+ avd_spec.local_system_image = None
# raise errors.NoCuttlefishCommonInstalled
self.Patch(setup_common, "PackageInstalled", return_value=False)
self.assertRaises(errors.NoCuttlefishCommonInstalled,
@@ -70,6 +74,38 @@
self.assertEqual(paths.image_dir, "/unit/test")
self.assertEqual(paths.host_bins, "/unit/test")
+ # GSI
+ avd_spec.local_system_image = "/test_local_system_image_dir"
+ avd_spec.local_tool_dirs = "/test_local_tool_dirs"
+ avd_spec.cfg = None
+ avd_spec.remote_image = self._fake_remote_image
+ self.Patch(os, "makedirs")
+ self.Patch(create_common, "DownloadRemoteArtifact")
+ self.Patch(os.path, "exists", side_effect=[True, False])
+ self.Patch(create_common, "GetNonEmptyEnvVars")
+ self.Patch(local_image_local_instance.LocalImageLocalInstance,
+ "FindMiscInfo", return_value="/mix_image_1234/MISC")
+ self.Patch(local_image_local_instance.LocalImageLocalInstance,
+ "FindImageDir", return_value="/mix_image_1234/IMAGES")
+ self.Patch(ota_tools, "FindOtaToolsDir", return_value="/ota_tools_dir")
+ self.Patch(create_common, "FindLocalImage", return_value="/system_image_path")
+ paths = self.RemoteImageLocalInstance.GetImageArtifactsPath(avd_spec)
+ create_common.DownloadRemoteArtifact.assert_called_with(
+ avd_spec.cfg, "aosp_cf_x86_64_phone-userdebug", "1234",
+ "aosp_cf_x86_64_phone-target_files-1234.zip", "/unit/test/mix_image_1234",
+ decompress=True)
+ self.assertEqual(paths.image_dir, "/mix_image_1234/IMAGES")
+ self.assertEqual(paths.misc_info, "/mix_image_1234/MISC")
+ self.assertEqual(paths.host_bins, "/unit/test")
+ self.assertEqual(paths.ota_tools_dir, "/ota_tools_dir")
+ self.assertEqual(paths.system_image, "/system_image_path")
+ create_common.DownloadRemoteArtifact.reset_mock()
+
+ self.Patch(os.path, "exists", side_effect=[True, True])
+ self.RemoteImageLocalInstance.GetImageArtifactsPath(avd_spec)
+ create_common.DownloadRemoteArtifact.assert_not_called()
+
+
@mock.patch.object(shutil, "rmtree")
def testDownloadAndProcessImageFiles(self, mock_rmtree):
"""Test process remote cuttlefish image."""