• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2021 - The Android Open Source Project
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14
15"""Utility functions that process goldfish images and arguments."""
16
17import os
18import shutil
19
20from acloud import errors
21from acloud.internal import constants
22from acloud.internal.lib import ota_tools
23
24
25# File names under working directory.
26_UNPACK_DIR_NAME = "unpacked_boot_img"
27_MIXED_RAMDISK_IMAGE_NAME = "mixed_ramdisk"
28# File names in unpacked boot image.
29_UNPACKED_KERNEL_IMAGE_NAME = "kernel"
30_UNPACKED_RAMDISK_IMAGE_NAME = "ramdisk"
31# File names in a build environment or an SDK repository.
32SYSTEM_QEMU_IMAGE_NAME = "system-qemu.img"
33_SDK_REPO_SYSTEM_IMAGE_NAME = "system.img"
34_MISC_INFO_FILE_NAME = "misc_info.txt"
35_SYSTEM_QEMU_CONFIG_FILE_NAME = "system-qemu-config.txt"
36# File names in the search order of emulator.
37_DISK_IMAGE_NAMES = (SYSTEM_QEMU_IMAGE_NAME, _SDK_REPO_SYSTEM_IMAGE_NAME)
38_KERNEL_IMAGE_NAMES = ("kernel-ranchu", "kernel-ranchu-64", "kernel")
39_RAMDISK_IMAGE_NAMES = ("ramdisk-qemu.img", "ramdisk.img")
40
41
42def _FindFileByNames(parent_dir, names):
43    """Find file under a directory by names.
44
45    Args:
46        parent_dir: The directory to find the file in.
47        names: A list of file names.
48
49    Returns:
50        The path to the first existing file in the list.
51
52    Raises:
53        errors.GetLocalImageError if none of the files exist.
54    """
55    for name in names:
56        path = os.path.join(parent_dir, name)
57        if os.path.isfile(path):
58            return path
59    raise errors.GetLocalImageError("No %s in %s." %
60                                    (", ".join(names), parent_dir))
61
62
63def _UnpackBootImage(output_dir, boot_image_path, ota):
64    """Unpack a boot image and find kernel images.
65
66    Args:
67        output_dir: The directory where the boot image is unpacked.
68        boot_image_path: The path to the boot image.
69        ota: An instance of ota_tools.OtaTools.
70
71    Returns:
72        The kernel image path and the ramdisk image path.
73
74    Raises:
75        errors.GetLocalImageError if the kernel or the ramdisk is not found.
76    """
77    ota.UnpackBootImg(output_dir, boot_image_path)
78
79    kernel_path = os.path.join(output_dir, _UNPACKED_KERNEL_IMAGE_NAME)
80    ramdisk_path = os.path.join(output_dir, _UNPACKED_RAMDISK_IMAGE_NAME)
81    if not os.path.isfile(kernel_path):
82        raise errors.GetLocalImageError("No kernel in %s." % boot_image_path)
83    if not os.path.isfile(ramdisk_path):
84        raise errors.GetLocalImageError("No ramdisk in %s." % boot_image_path)
85    return kernel_path, ramdisk_path
86
87
88def _MixRamdiskImages(output_path, original_ramdisk_path,
89                      boot_ramdisk_path):
90    """Mix an emulator ramdisk with a boot ramdisk.
91
92    An emulator ramdisk consists of a boot ramdisk and a vendor ramdisk.
93    This method overlays a new boot ramdisk on the emulator ramdisk by
94    concatenating them.
95
96    Args:
97        output_path: The path to the output ramdisk.
98        original_ramdisk_path: The path to the emulator ramdisk.
99        boot_ramdisk_path: The path to the boot ramdisk.
100    """
101    with open(output_path, "wb") as mixed_ramdisk:
102        with open(original_ramdisk_path, "rb") as ramdisk:
103            shutil.copyfileobj(ramdisk, mixed_ramdisk)
104        with open(boot_ramdisk_path, "rb") as ramdisk:
105            shutil.copyfileobj(ramdisk, mixed_ramdisk)
106
107
108def MixWithBootImage(output_dir, image_dir, boot_image_path, ota):
109    """Mix emulator kernel images with a boot image.
110
111    Args:
112        output_dir: The directory containing the output and intermediate files.
113        image_dir: The directory containing emulator kernel and ramdisk images.
114        boot_image_path: The path to the boot image.
115        ota: An instance of ota_tools.OtaTools.
116
117    Returns:
118        The paths to the kernel and ramdisk images in output_dir.
119
120    Raises:
121        errors.GetLocalImageError if any image is not found.
122    """
123    unpack_dir = os.path.join(output_dir, _UNPACK_DIR_NAME)
124    if os.path.exists(unpack_dir):
125        shutil.rmtree(unpack_dir)
126    os.makedirs(unpack_dir, exist_ok=True)
127
128    kernel_path, boot_ramdisk_path = _UnpackBootImage(
129        unpack_dir, boot_image_path, ota)
130    # The ramdisk unpacked from boot_image_path does not include emulator's
131    # kernel modules. The ramdisk in image_dir contains the modules. This
132    # method mixes the two ramdisks.
133    mixed_ramdisk_path = os.path.join(output_dir, _MIXED_RAMDISK_IMAGE_NAME)
134    original_ramdisk_path = _FindFileByNames(image_dir, _RAMDISK_IMAGE_NAMES)
135    _MixRamdiskImages(mixed_ramdisk_path, original_ramdisk_path,
136                      boot_ramdisk_path)
137    return kernel_path, mixed_ramdisk_path
138
139
140def FindKernelImages(image_dir):
141    """Find emulator kernel images in a directory.
142
143    Args:
144        image_dir: The directory to find the images in.
145
146    Returns:
147        The paths to the kernel image and the ramdisk image.
148
149    Raises:
150        errors.GetLocalImageError if any image is not found.
151    """
152    return (_FindFileByNames(image_dir, _KERNEL_IMAGE_NAMES),
153            _FindFileByNames(image_dir, _RAMDISK_IMAGE_NAMES))
154
155
156def FindDiskImage(image_dir):
157    """Find an emulator disk image in a directory.
158
159    Args:
160        image_dir: The directory to find the image in.
161
162    Returns:
163        The path to the disk image.
164
165    Raises:
166        errors.GetLocalImageError if the image is not found.
167    """
168    return _FindFileByNames(image_dir, _DISK_IMAGE_NAMES)
169
170
171def MixWithSystemImage(output_dir, image_dir, system_image_path, ota):
172    """Mix emulator images and a system image into a disk image.
173
174    Args:
175        output_dir: The path to the output directory.
176        image_dir: The input directory that provides images except
177                   system.img.
178        system_image_path: The path to the system image.
179        ota: An instance of ota_tools.OtaTools.
180
181    Returns:
182        The path to the mixed disk image in output_dir.
183
184    Raises:
185        errors.GetLocalImageError if any required file is not found.
186    """
187    os.makedirs(output_dir, exist_ok=True)
188
189    # Create the super image.
190    mixed_super_image_path = os.path.join(output_dir, "mixed_super.img")
191    ota.BuildSuperImage(
192        mixed_super_image_path,
193        _FindFileByNames(image_dir, [_MISC_INFO_FILE_NAME]),
194        lambda partition: ota_tools.GetImageForPartition(
195            partition, image_dir, system=system_image_path))
196
197    # Create the vbmeta image.
198    vbmeta_image_path = os.path.join(output_dir, "disabled_vbmeta.img")
199    ota.MakeDisabledVbmetaImage(vbmeta_image_path)
200
201    # Create the disk image.
202    disk_image = os.path.join(output_dir, "mixed_disk.img")
203    ota.MkCombinedImg(
204        disk_image,
205        _FindFileByNames(image_dir, [_SYSTEM_QEMU_CONFIG_FILE_NAME]),
206        lambda partition: ota_tools.GetImageForPartition(
207            partition, image_dir, super=mixed_super_image_path,
208            vbmeta=vbmeta_image_path))
209    return disk_image
210
211
212def ConvertAvdSpecToArgs(avd_spec):
213    """Convert hardware specification to emulator arguments.
214
215    Args:
216        avd_spec: The AvdSpec object.
217
218    Returns:
219        A list of strings, the arguments.
220    """
221    args = []
222    if avd_spec.gpu:
223        args.extend(("-gpu", avd_spec.gpu))
224
225    if not avd_spec.hw_customize:
226        return args
227
228    cores = avd_spec.hw_property.get(constants.HW_ALIAS_CPUS)
229    if cores:
230        args.extend(("-cores", cores))
231    x_res = avd_spec.hw_property.get(constants.HW_X_RES)
232    y_res = avd_spec.hw_property.get(constants.HW_Y_RES)
233    if x_res and y_res:
234        args.extend(("-skin", ("%sx%s" % (x_res, y_res))))
235    dpi = avd_spec.hw_property.get(constants.HW_ALIAS_DPI)
236    if dpi:
237        args.extend(("-dpi-device", dpi))
238    memory_size_mb = avd_spec.hw_property.get(constants.HW_ALIAS_MEMORY)
239    if memory_size_mb:
240        args.extend(("-memory", memory_size_mb))
241    userdata_size_mb = avd_spec.hw_property.get(constants.HW_ALIAS_DISK)
242    if userdata_size_mb:
243        args.extend(("-partition-size", userdata_size_mb))
244
245    return args
246