1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/commands/assemble_cvd/disk_flags.h"
18
19 #include <android-base/logging.h>
20 #include <android-base/parsebool.h>
21 #include <android-base/parseint.h>
22 #include <android-base/strings.h>
23 #include <fruit/fruit.h>
24 #include <gflags/gflags.h>
25 #include <sys/statvfs.h>
26
27 #include <fstream>
28
29 #include "common/libs/fs/shared_buf.h"
30 #include "common/libs/utils/files.h"
31 #include "common/libs/utils/size_utils.h"
32 #include "common/libs/utils/subprocess.h"
33 #include "host/commands/assemble_cvd/boot_config.h"
34 #include "host/commands/assemble_cvd/boot_image_utils.h"
35 #include "host/commands/assemble_cvd/disk_builder.h"
36 #include "host/commands/assemble_cvd/flags_defaults.h"
37 #include "host/commands/assemble_cvd/super_image_mixer.h"
38 #include "host/commands/assemble_cvd/vendor_dlkm_utils.h"
39 #include "host/libs/config/bootconfig_args.h"
40 #include "host/libs/config/cuttlefish_config.h"
41 #include "host/libs/config/data_image.h"
42 #include "host/libs/config/inject.h"
43 #include "host/libs/config/instance_nums.h"
44 #include "host/libs/vm_manager/gem5_manager.h"
45
46
47 // Taken from external/avb/avbtool.py; this define is not in the headers
48 #define MAX_AVB_METADATA_SIZE 69632ul
49
50 DECLARE_string(system_image_dir);
51
52 DEFINE_string(boot_image, CF_DEFAULTS_BOOT_IMAGE,
53 "Location of cuttlefish boot image. If empty it is assumed to be "
54 "boot.img in the directory specified by -system_image_dir.");
55 DEFINE_string(
56 init_boot_image, CF_DEFAULTS_INIT_BOOT_IMAGE,
57 "Location of cuttlefish init boot image. If empty it is assumed to "
58 "be init_boot.img in the directory specified by -system_image_dir.");
59 DEFINE_string(data_image, CF_DEFAULTS_DATA_IMAGE,
60 "Location of the data partition image.");
61 DEFINE_string(super_image, CF_DEFAULTS_SUPER_IMAGE,
62 "Location of the super partition image.");
63 DEFINE_string(misc_image, CF_DEFAULTS_MISC_IMAGE,
64 "Location of the misc partition image. If the image does not "
65 "exist, a blank new misc partition image is created.");
66 DEFINE_string(misc_info_txt, "", "Location of the misc_info.txt file.");
67 DEFINE_string(metadata_image, CF_DEFAULTS_METADATA_IMAGE,
68 "Location of the metadata partition image "
69 "to be generated.");
70 DEFINE_string(
71 vendor_boot_image, CF_DEFAULTS_VENDOR_BOOT_IMAGE,
72 "Location of cuttlefish vendor boot image. If empty it is assumed to "
73 "be vendor_boot.img in the directory specified by -system_image_dir.");
74 DEFINE_string(vbmeta_image, CF_DEFAULTS_VBMETA_IMAGE,
75 "Location of cuttlefish vbmeta image. If empty it is assumed to "
76 "be vbmeta.img in the directory specified by -system_image_dir.");
77 DEFINE_string(
78 vbmeta_system_image, CF_DEFAULTS_VBMETA_SYSTEM_IMAGE,
79 "Location of cuttlefish vbmeta_system image. If empty it is assumed to "
80 "be vbmeta_system.img in the directory specified by -system_image_dir.");
81 DEFINE_string(
82 vbmeta_vendor_dlkm_image, CF_DEFAULTS_VBMETA_VENDOR_DLKM_IMAGE,
83 "Location of cuttlefish vbmeta_vendor_dlkm image. If empty it is assumed "
84 "to "
85 "be vbmeta_vendor_dlkm.img in the directory specified by "
86 "-system_image_dir.");
87
88 DEFINE_string(linux_kernel_path, CF_DEFAULTS_LINUX_KERNEL_PATH,
89 "Location of linux kernel for cuttlefish otheros flow.");
90 DEFINE_string(linux_initramfs_path, CF_DEFAULTS_LINUX_INITRAMFS_PATH,
91 "Location of linux initramfs.img for cuttlefish otheros flow.");
92 DEFINE_string(linux_root_image, CF_DEFAULTS_LINUX_ROOT_IMAGE,
93 "Location of linux root filesystem image for cuttlefish otheros flow.");
94
95 DEFINE_string(fuchsia_zedboot_path, CF_DEFAULTS_FUCHSIA_ZEDBOOT_PATH,
96 "Location of fuchsia zedboot path for cuttlefish otheros flow.");
97 DEFINE_string(fuchsia_multiboot_bin_path, CF_DEFAULTS_FUCHSIA_MULTIBOOT_BIN_PATH,
98 "Location of fuchsia multiboot bin path for cuttlefish otheros flow.");
99 DEFINE_string(fuchsia_root_image, CF_DEFAULTS_FUCHSIA_ROOT_IMAGE,
100 "Location of fuchsia root filesystem image for cuttlefish otheros flow.");
101
102 DEFINE_string(custom_partition_path, CF_DEFAULTS_CUSTOM_PARTITION_PATH,
103 "Location of custom image that will be passed as a \"custom\" partition"
104 "to rootfs and can be used by /dev/block/by-name/custom");
105
106 DEFINE_string(blank_metadata_image_mb, CF_DEFAULTS_BLANK_METADATA_IMAGE_MB,
107 "The size of the blank metadata image to generate, MB.");
108 DEFINE_string(
109 blank_sdcard_image_mb, CF_DEFAULTS_BLANK_SDCARD_IMAGE_MB,
110 "If enabled, the size of the blank sdcard image to generate, MB.");
111
112 DECLARE_string(ap_rootfs_image);
113 DECLARE_string(bootloader);
114 DECLARE_string(initramfs_path);
115 DECLARE_string(kernel_path);
116 DECLARE_bool(resume);
117 DECLARE_bool(use_overlay);
118
119 namespace cuttlefish {
120
121 using APBootFlow = CuttlefishConfig::InstanceSpecific::APBootFlow;
122 using vm_manager::Gem5Manager;
123
ResolveInstanceFiles()124 Result<void> ResolveInstanceFiles() {
125 CF_EXPECT(!FLAGS_system_image_dir.empty(),
126 "--system_image_dir must be specified.");
127
128 std::vector<std::string> system_image_dir =
129 android::base::Split(FLAGS_system_image_dir, ",");
130 std::string default_boot_image = "";
131 std::string default_init_boot_image = "";
132 std::string default_data_image = "";
133 std::string default_metadata_image = "";
134 std::string default_super_image = "";
135 std::string default_misc_image = "";
136 std::string default_misc_info_txt = "";
137 std::string default_vendor_boot_image = "";
138 std::string default_vbmeta_image = "";
139 std::string default_vbmeta_system_image = "";
140 std::string default_vbmeta_vendor_dlkm_image = "";
141
142 std::string cur_system_image_dir;
143 std::string comma_str = "";
144 auto instance_nums =
145 CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
146 for (int instance_index = 0; instance_index < instance_nums.size(); instance_index++) {
147 if (instance_index < system_image_dir.size()) {
148 cur_system_image_dir = system_image_dir[instance_index];
149 } else {
150 // legacy variable or out of boundary. Vectorize by copy [0] to all instances
151 cur_system_image_dir = system_image_dir[0];
152 }
153 if (instance_index > 0) {
154 comma_str = ",";
155 }
156
157 // If user did not specify location of either of these files, expect them to
158 // be placed in --system_image_dir location.
159 default_boot_image += comma_str + cur_system_image_dir + "/boot.img";
160 default_init_boot_image += comma_str + cur_system_image_dir + "/init_boot.img";
161 default_data_image += comma_str + cur_system_image_dir + "/userdata.img";
162 default_metadata_image += comma_str + cur_system_image_dir + "/metadata.img";
163 default_super_image += comma_str + cur_system_image_dir + "/super.img";
164 default_misc_image += comma_str + cur_system_image_dir + "/misc.img";
165 default_misc_info_txt +=
166 comma_str + cur_system_image_dir + "/misc_info.txt";
167 default_vendor_boot_image += comma_str + cur_system_image_dir + "/vendor_boot.img";
168 default_vbmeta_image += comma_str + cur_system_image_dir + "/vbmeta.img";
169 default_vbmeta_system_image += comma_str + cur_system_image_dir + "/vbmeta_system.img";
170 default_vbmeta_vendor_dlkm_image +=
171 comma_str + cur_system_image_dir + "/vbmeta_vendor_dlkm.img";
172 }
173 SetCommandLineOptionWithMode("boot_image", default_boot_image.c_str(),
174 google::FlagSettingMode::SET_FLAGS_DEFAULT);
175 SetCommandLineOptionWithMode("init_boot_image",
176 default_init_boot_image.c_str(),
177 google::FlagSettingMode::SET_FLAGS_DEFAULT);
178 SetCommandLineOptionWithMode("data_image", default_data_image.c_str(),
179 google::FlagSettingMode::SET_FLAGS_DEFAULT);
180 SetCommandLineOptionWithMode("metadata_image", default_metadata_image.c_str(),
181 google::FlagSettingMode::SET_FLAGS_DEFAULT);
182 SetCommandLineOptionWithMode("super_image", default_super_image.c_str(),
183 google::FlagSettingMode::SET_FLAGS_DEFAULT);
184 SetCommandLineOptionWithMode("misc_image", default_misc_image.c_str(),
185 google::FlagSettingMode::SET_FLAGS_DEFAULT);
186 SetCommandLineOptionWithMode("misc_info_txt", default_misc_info_txt.c_str(),
187 google::FlagSettingMode::SET_FLAGS_DEFAULT);
188 SetCommandLineOptionWithMode("vendor_boot_image",
189 default_vendor_boot_image.c_str(),
190 google::FlagSettingMode::SET_FLAGS_DEFAULT);
191 SetCommandLineOptionWithMode("vbmeta_image", default_vbmeta_image.c_str(),
192 google::FlagSettingMode::SET_FLAGS_DEFAULT);
193 SetCommandLineOptionWithMode("vbmeta_system_image",
194 default_vbmeta_system_image.c_str(),
195 google::FlagSettingMode::SET_FLAGS_DEFAULT);
196 SetCommandLineOptionWithMode("vbmeta_vendor_dlkm_image",
197 default_vbmeta_vendor_dlkm_image.c_str(),
198 google::FlagSettingMode::SET_FLAGS_DEFAULT);
199
200 return {};
201 }
202
linux_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)203 std::vector<ImagePartition> linux_composite_disk_config(
204 const CuttlefishConfig::InstanceSpecific& instance) {
205 std::vector<ImagePartition> partitions;
206
207 partitions.push_back(ImagePartition{
208 .label = "linux_esp",
209 .image_file_path = AbsolutePath(instance.otheros_esp_image_path()),
210 .type = kEfiSystemPartition,
211 .read_only = FLAGS_use_overlay,
212 });
213 partitions.push_back(ImagePartition{
214 .label = "linux_root",
215 .image_file_path = AbsolutePath(instance.linux_root_image()),
216 .read_only = FLAGS_use_overlay,
217 });
218
219 return partitions;
220 }
221
fuchsia_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)222 std::vector<ImagePartition> fuchsia_composite_disk_config(
223 const CuttlefishConfig::InstanceSpecific& instance) {
224 std::vector<ImagePartition> partitions;
225
226 partitions.push_back(ImagePartition{
227 .label = "fuchsia_esp",
228 .image_file_path = AbsolutePath(instance.otheros_esp_image_path()),
229 .type = kEfiSystemPartition,
230 .read_only = FLAGS_use_overlay,
231 });
232
233 return partitions;
234 }
235
android_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)236 std::vector<ImagePartition> android_composite_disk_config(
237 const CuttlefishConfig::InstanceSpecific& instance) {
238 std::vector<ImagePartition> partitions;
239
240 partitions.push_back(ImagePartition{
241 .label = "misc",
242 .image_file_path = AbsolutePath(instance.new_misc_image()),
243 .read_only = FLAGS_use_overlay,
244 });
245 partitions.push_back(ImagePartition{
246 .label = "boot_a",
247 .image_file_path = AbsolutePath(instance.new_boot_image()),
248 .read_only = FLAGS_use_overlay,
249 });
250 partitions.push_back(ImagePartition{
251 .label = "boot_b",
252 .image_file_path = AbsolutePath(instance.new_boot_image()),
253 .read_only = FLAGS_use_overlay,
254 });
255 const auto init_boot_path = instance.init_boot_image();
256 if (FileExists(init_boot_path)) {
257 partitions.push_back(ImagePartition{
258 .label = "init_boot_a",
259 .image_file_path = AbsolutePath(init_boot_path),
260 .read_only = FLAGS_use_overlay,
261 });
262 partitions.push_back(ImagePartition{
263 .label = "init_boot_b",
264 .image_file_path = AbsolutePath(init_boot_path),
265 .read_only = FLAGS_use_overlay,
266 });
267 }
268 partitions.push_back(ImagePartition{
269 .label = "vendor_boot_a",
270 .image_file_path = AbsolutePath(instance.new_vendor_boot_image()),
271 .read_only = FLAGS_use_overlay,
272 });
273 partitions.push_back(ImagePartition{
274 .label = "vendor_boot_b",
275 .image_file_path = AbsolutePath(instance.new_vendor_boot_image()),
276 .read_only = FLAGS_use_overlay,
277 });
278 partitions.push_back(ImagePartition{
279 .label = "vbmeta_a",
280 .image_file_path = AbsolutePath(instance.vbmeta_image()),
281 .read_only = FLAGS_use_overlay,
282 });
283 partitions.push_back(ImagePartition{
284 .label = "vbmeta_b",
285 .image_file_path = AbsolutePath(instance.vbmeta_image()),
286 .read_only = FLAGS_use_overlay,
287 });
288 partitions.push_back(ImagePartition{
289 .label = "vbmeta_system_a",
290 .image_file_path = AbsolutePath(instance.vbmeta_system_image()),
291 .read_only = FLAGS_use_overlay,
292 });
293 partitions.push_back(ImagePartition{
294 .label = "vbmeta_system_b",
295 .image_file_path = AbsolutePath(instance.vbmeta_system_image()),
296 .read_only = FLAGS_use_overlay,
297 });
298 auto vbmeta_vendor_dlkm_img = instance.new_vbmeta_vendor_dlkm_image();
299 if (!FileExists(vbmeta_vendor_dlkm_img)) {
300 vbmeta_vendor_dlkm_img = instance.vbmeta_vendor_dlkm_image();
301 }
302 if (FileExists(vbmeta_vendor_dlkm_img)) {
303 partitions.push_back(ImagePartition{
304 .label = "vbmeta_vendor_dlkm_a",
305 .image_file_path = AbsolutePath(vbmeta_vendor_dlkm_img),
306 .read_only = FLAGS_use_overlay,
307 });
308 partitions.push_back(ImagePartition{
309 .label = "vbmeta_vendor_dlkm_b",
310 .image_file_path = AbsolutePath(vbmeta_vendor_dlkm_img),
311 .read_only = FLAGS_use_overlay,
312 });
313 }
314 auto super_image = instance.new_super_image();
315 if (!FileExists(super_image)) {
316 super_image = instance.super_image();
317 }
318 partitions.push_back(ImagePartition{
319 .label = "super",
320 .image_file_path = AbsolutePath(super_image),
321 .read_only = FLAGS_use_overlay,
322 });
323 partitions.push_back(ImagePartition{
324 .label = "userdata",
325 .image_file_path = AbsolutePath(instance.data_image()),
326 .read_only = FLAGS_use_overlay,
327 });
328 partitions.push_back(ImagePartition{
329 .label = "metadata",
330 .image_file_path = AbsolutePath(instance.new_metadata_image()),
331 .read_only = FLAGS_use_overlay,
332 });
333 const auto custom_partition_path = instance.custom_partition_path();
334 if (!custom_partition_path.empty()) {
335 partitions.push_back(ImagePartition{
336 .label = "custom",
337 .image_file_path = AbsolutePath(custom_partition_path),
338 .read_only = FLAGS_use_overlay,
339 });
340 }
341
342 return partitions;
343 }
344
GetApCompositeDiskConfig(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)345 std::vector<ImagePartition> GetApCompositeDiskConfig(const CuttlefishConfig& config,
346 const CuttlefishConfig::InstanceSpecific& instance) {
347 std::vector<ImagePartition> partitions;
348
349 if (instance.ap_boot_flow() == APBootFlow::Grub) {
350 partitions.push_back(ImagePartition{
351 .label = "ap_esp",
352 .image_file_path = AbsolutePath(instance.ap_esp_image_path()),
353 .read_only = FLAGS_use_overlay,
354 });
355 }
356
357 partitions.push_back(ImagePartition{
358 .label = "ap_rootfs",
359 .image_file_path = AbsolutePath(config.ap_rootfs_image()),
360 .read_only = FLAGS_use_overlay,
361 });
362
363 return partitions;
364 }
365
GetOsCompositeDiskConfig(const CuttlefishConfig::InstanceSpecific & instance)366 std::vector<ImagePartition> GetOsCompositeDiskConfig(
367 const CuttlefishConfig::InstanceSpecific& instance) {
368
369 switch (instance.boot_flow()) {
370 case CuttlefishConfig::InstanceSpecific::BootFlow::Android:
371 return android_composite_disk_config(instance);
372 break;
373 case CuttlefishConfig::InstanceSpecific::BootFlow::Linux:
374 return linux_composite_disk_config(instance);
375 break;
376 case CuttlefishConfig::InstanceSpecific::BootFlow::Fuchsia:
377 return fuchsia_composite_disk_config(instance);
378 break;
379 }
380 }
381
OsCompositeDiskBuilder(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)382 DiskBuilder OsCompositeDiskBuilder(const CuttlefishConfig& config,
383 const CuttlefishConfig::InstanceSpecific& instance) {
384 return DiskBuilder()
385 .Partitions(GetOsCompositeDiskConfig(instance))
386 .VmManager(config.vm_manager())
387 .CrosvmPath(instance.crosvm_binary())
388 .ConfigPath(instance.PerInstancePath("os_composite_disk_config.txt"))
389 .HeaderPath(instance.PerInstancePath("os_composite_gpt_header.img"))
390 .FooterPath(instance.PerInstancePath("os_composite_gpt_footer.img"))
391 .CompositeDiskPath(instance.os_composite_disk_path())
392 .ResumeIfPossible(FLAGS_resume);
393 }
394
ApCompositeDiskBuilder(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)395 DiskBuilder ApCompositeDiskBuilder(const CuttlefishConfig& config,
396 const CuttlefishConfig::InstanceSpecific& instance) {
397 return DiskBuilder()
398 .Partitions(GetApCompositeDiskConfig(config, instance))
399 .VmManager(config.vm_manager())
400 .CrosvmPath(instance.crosvm_binary())
401 .ConfigPath(instance.PerInstancePath("ap_composite_disk_config.txt"))
402 .HeaderPath(instance.PerInstancePath("ap_composite_gpt_header.img"))
403 .FooterPath(instance.PerInstancePath("ap_composite_gpt_footer.img"))
404 .CompositeDiskPath(instance.ap_composite_disk_path())
405 .ResumeIfPossible(FLAGS_resume);
406 }
407
persistent_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)408 std::vector<ImagePartition> persistent_composite_disk_config(
409 const CuttlefishConfig::InstanceSpecific& instance) {
410 std::vector<ImagePartition> partitions;
411
412 // Note that if the position of uboot_env changes, the environment for
413 // u-boot must be updated as well (see boot_config.cc and
414 // cuttlefish.fragment in external/u-boot).
415 partitions.push_back(ImagePartition{
416 .label = "uboot_env",
417 .image_file_path = AbsolutePath(instance.uboot_env_image_path()),
418 });
419 partitions.push_back(ImagePartition{
420 .label = "vbmeta",
421 .image_file_path = AbsolutePath(instance.vbmeta_path()),
422 });
423 if (!instance.protected_vm()) {
424 partitions.push_back(ImagePartition{
425 .label = "frp",
426 .image_file_path =
427 AbsolutePath(instance.factory_reset_protected_path()),
428 });
429 }
430 if (instance.bootconfig_supported()) {
431 partitions.push_back(ImagePartition{
432 .label = "bootconfig",
433 .image_file_path = AbsolutePath(instance.persistent_bootconfig_path()),
434 });
435 }
436 return partitions;
437 }
438
persistent_ap_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)439 std::vector<ImagePartition> persistent_ap_composite_disk_config(
440 const CuttlefishConfig::InstanceSpecific& instance) {
441 std::vector<ImagePartition> partitions;
442
443 // Note that if the position of uboot_env changes, the environment for
444 // u-boot must be updated as well (see boot_config.cc and
445 // cuttlefish.fragment in external/u-boot).
446 partitions.push_back(ImagePartition{
447 .label = "uboot_env",
448 .image_file_path = AbsolutePath(instance.ap_uboot_env_image_path()),
449 });
450 partitions.push_back(ImagePartition{
451 .label = "vbmeta",
452 .image_file_path = AbsolutePath(instance.ap_vbmeta_path()),
453 });
454
455 return partitions;
456 }
457
AvailableSpaceAtPath(const std::string & path)458 static uint64_t AvailableSpaceAtPath(const std::string& path) {
459 struct statvfs vfs {};
460 if (statvfs(path.c_str(), &vfs) != 0) {
461 int error_num = errno;
462 LOG(ERROR) << "Could not find space available at " << path << ", error was "
463 << strerror(error_num);
464 return 0;
465 }
466 // f_frsize (block size) * f_bavail (free blocks) for unprivileged users.
467 return static_cast<uint64_t>(vfs.f_frsize) * vfs.f_bavail;
468 }
469
470 class KernelRamdiskRepacker : public SetupFeature {
471 public:
INJECT(KernelRamdiskRepacker (const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance))472 INJECT(
473 KernelRamdiskRepacker(const CuttlefishConfig& config,
474 const CuttlefishConfig::InstanceSpecific& instance))
475 : config_(config), instance_(instance) {}
476
477 // SetupFeature
Name() const478 std::string Name() const override { return "KernelRamdiskRepacker"; }
Dependencies() const479 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
Enabled() const480 bool Enabled() const override {
481 // If we are booting a protected VM, for now, assume that image repacking
482 // isn't trusted. Repacking requires resigning the image and keys from an
483 // android host aren't trusted.
484 return !instance_.protected_vm();
485 }
486
487 protected:
RepackVendorDLKM(const std::string & superimg_build_dir,const std::string & vendor_dlkm_build_dir,const std::string & ramdisk_path)488 bool RepackVendorDLKM(const std::string& superimg_build_dir,
489 const std::string& vendor_dlkm_build_dir,
490 const std::string& ramdisk_path) {
491 const auto new_vendor_dlkm_img =
492 superimg_build_dir + "/vendor_dlkm_repacked.img";
493 const auto tmp_vendor_dlkm_img = new_vendor_dlkm_img + ".tmp";
494 if (!EnsureDirectoryExists(vendor_dlkm_build_dir).ok()) {
495 LOG(ERROR) << "Failed to create directory " << vendor_dlkm_build_dir;
496 return false;
497 }
498 const auto ramdisk_stage_dir = instance_.instance_dir() + "/ramdisk_staged";
499 if (!SplitRamdiskModules(ramdisk_path, ramdisk_stage_dir,
500 vendor_dlkm_build_dir)) {
501 LOG(ERROR) << "Failed to move ramdisk modules to vendor_dlkm";
502 return false;
503 }
504 // TODO(b/149866755) For now, we assume that vendor_dlkm is ext4. Add
505 // logic to handle EROFS once the feature stablizes.
506 if (!BuildVendorDLKM(vendor_dlkm_build_dir, false, tmp_vendor_dlkm_img)) {
507 LOG(ERROR) << "Failed to build vendor_dlkm image from "
508 << vendor_dlkm_build_dir;
509 return false;
510 }
511 if (ReadFile(tmp_vendor_dlkm_img) == ReadFile(new_vendor_dlkm_img)) {
512 LOG(INFO) << "vendor_dlkm unchanged, skip super image rebuilding.";
513 return true;
514 }
515 if (!RenameFile(tmp_vendor_dlkm_img, new_vendor_dlkm_img).ok()) {
516 return false;
517 }
518 const auto new_super_img = instance_.new_super_image();
519 if (!Copy(instance_.super_image(), new_super_img)) {
520 PLOG(ERROR) << "Failed to copy super image " << instance_.super_image()
521 << " to " << new_super_img;
522 return false;
523 }
524 if (!RepackSuperWithVendorDLKM(new_super_img, new_vendor_dlkm_img)) {
525 LOG(ERROR) << "Failed to repack super image with new vendor dlkm image.";
526 return false;
527 }
528 if (!RebuildVbmetaVendor(new_vendor_dlkm_img,
529 instance_.new_vbmeta_vendor_dlkm_image())) {
530 LOG(ERROR) << "Failed to rebuild vbmeta vendor.";
531 return false;
532 }
533 SetCommandLineOptionWithMode("super_image", new_super_img.c_str(),
534 google::FlagSettingMode::SET_FLAGS_DEFAULT);
535 SetCommandLineOptionWithMode(
536 "vbmeta_vendor_dlkm_image",
537 instance_.new_vbmeta_vendor_dlkm_image().c_str(),
538 google::FlagSettingMode::SET_FLAGS_DEFAULT);
539 return true;
540 }
Setup()541 bool Setup() override {
542 if (!FileHasContent(instance_.boot_image())) {
543 LOG(ERROR) << "File not found: " << instance_.boot_image();
544 return false;
545 }
546 // The init_boot partition is be optional for testing boot.img
547 // with the ramdisk inside.
548 if (!FileHasContent(instance_.init_boot_image())) {
549 LOG(WARNING) << "File not found: " << instance_.init_boot_image();
550 }
551
552 if (!FileHasContent(instance_.vendor_boot_image())) {
553 LOG(ERROR) << "File not found: " << instance_.vendor_boot_image();
554 return false;
555 }
556
557 // Repacking a boot.img doesn't work with Gem5 because the user must always
558 // specify a vmlinux instead of an arm64 Image, and that file can be too
559 // large to be repacked. Skip repack of boot.img on Gem5, as we need to be
560 // able to extract the ramdisk.img in a later stage and so this step must
561 // not fail (..and the repacked kernel wouldn't be used anyway).
562 if (instance_.kernel_path().size() &&
563 config_.vm_manager() != Gem5Manager::name()) {
564 const std::string new_boot_image_path = instance_.new_boot_image();
565 bool success =
566 RepackBootImage(instance_.kernel_path(), instance_.boot_image(),
567 new_boot_image_path, instance_.instance_dir());
568 if (!success) {
569 LOG(ERROR) << "Failed to regenerate the boot image with the new kernel";
570 return false;
571 }
572 SetCommandLineOptionWithMode("boot_image", new_boot_image_path.c_str(),
573 google::FlagSettingMode::SET_FLAGS_DEFAULT);
574 }
575
576 if (instance_.kernel_path().size() || instance_.initramfs_path().size()) {
577 const std::string new_vendor_boot_image_path =
578 instance_.new_vendor_boot_image();
579 // Repack the vendor boot images if kernels and/or ramdisks are passed in.
580 if (instance_.initramfs_path().size()) {
581 const auto superimg_build_dir = instance_.instance_dir() + "/superimg";
582 const auto ramdisk_repacked =
583 instance_.instance_dir() + "/ramdisk_repacked";
584 if (!Copy(instance_.initramfs_path(), ramdisk_repacked)) {
585 LOG(ERROR) << "Failed to copy " << instance_.initramfs_path()
586 << " to " << ramdisk_repacked;
587 return false;
588 }
589 const auto vendor_dlkm_build_dir = superimg_build_dir + "/vendor_dlkm";
590 if (!RepackVendorDLKM(superimg_build_dir, vendor_dlkm_build_dir,
591 ramdisk_repacked)) {
592 return false;
593 }
594 bool success = RepackVendorBootImage(
595 ramdisk_repacked, instance_.vendor_boot_image(),
596 new_vendor_boot_image_path, config_.assembly_dir(),
597 instance_.bootconfig_supported());
598 if (!success) {
599 LOG(ERROR) << "Failed to regenerate the vendor boot image with the "
600 "new ramdisk";
601 } else {
602 // This control flow implies a kernel with all configs built in.
603 // If it's just the kernel, repack the vendor boot image without a
604 // ramdisk.
605 bool success = RepackVendorBootImageWithEmptyRamdisk(
606 instance_.vendor_boot_image(), new_vendor_boot_image_path,
607 config_.assembly_dir(), instance_.bootconfig_supported());
608 if (!success) {
609 LOG(ERROR) << "Failed to regenerate the vendor boot image without "
610 "a ramdisk";
611 return false;
612 }
613 }
614 SetCommandLineOptionWithMode(
615 "vendor_boot_image", new_vendor_boot_image_path.c_str(),
616 google::FlagSettingMode::SET_FLAGS_DEFAULT);
617 }
618 }
619 return true;
620 }
621
622 private:
623 const CuttlefishConfig& config_;
624 const CuttlefishConfig::InstanceSpecific& instance_;
625 };
626
627 class Gem5ImageUnpacker : public SetupFeature {
628 public:
INJECT(Gem5ImageUnpacker (const CuttlefishConfig & config,KernelRamdiskRepacker & bir))629 INJECT(Gem5ImageUnpacker(const CuttlefishConfig& config,
630 KernelRamdiskRepacker& bir))
631 : config_(config), bir_(bir) {}
632
633 // SetupFeature
Name() const634 std::string Name() const override { return "Gem5ImageUnpacker"; }
635
Dependencies() const636 std::unordered_set<SetupFeature*> Dependencies() const override {
637 return {
638 static_cast<SetupFeature*>(&bir_),
639 };
640 }
641
Enabled() const642 bool Enabled() const override {
643 // Everything has a bootloader except gem5, so only run this for gem5
644 return config_.vm_manager() == Gem5Manager::name();
645 }
646
647 protected:
ResultSetup()648 Result<void> ResultSetup() override {
649 const CuttlefishConfig::InstanceSpecific& instance_ =
650 config_.ForDefaultInstance();
651
652 /* Unpack the original or repacked boot and vendor boot ramdisks, so that
653 * we have access to the baked bootconfig and raw compressed ramdisks.
654 * This allows us to emulate what a bootloader would normally do, which
655 * Gem5 can't support itself. This code also copies the kernel again
656 * (because Gem5 only supports raw vmlinux) and handles the bootloader
657 * binaries specially. This code is just part of the solution; it only
658 * does the parts which are instance agnostic.
659 */
660
661 CF_EXPECT(FileHasContent(instance_.boot_image()), instance_.boot_image());
662
663 const std::string unpack_dir = config_.assembly_dir();
664 // The init_boot partition is be optional for testing boot.img
665 // with the ramdisk inside.
666 if (!FileHasContent(instance_.init_boot_image())) {
667 LOG(WARNING) << "File not found: " << instance_.init_boot_image();
668 } else {
669 CF_EXPECT(UnpackBootImage(instance_.init_boot_image(), unpack_dir),
670 "Failed to extract the init boot image");
671 }
672
673 CF_EXPECT(FileHasContent(instance_.vendor_boot_image()),
674 instance_.vendor_boot_image());
675
676 CF_EXPECT(UnpackVendorBootImageIfNotUnpacked(instance_.vendor_boot_image(),
677 unpack_dir),
678 "Failed to extract the vendor boot image");
679
680 // Assume the user specified a kernel manually which is a vmlinux
681 CF_EXPECT(cuttlefish::Copy(instance_.kernel_path(), unpack_dir + "/kernel"));
682
683 // Gem5 needs the bootloader binary to be a specific directory structure
684 // to find it. Create a 'binaries' directory and copy it into there
685 const std::string binaries_dir = unpack_dir + "/binaries";
686 CF_EXPECT(mkdir(binaries_dir.c_str(),
687 S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == 0 ||
688 errno == EEXIST,
689 "\"" << binaries_dir << "\": " << strerror(errno));
690 CF_EXPECT(cuttlefish::Copy(instance_.bootloader(),
691 binaries_dir + "/" + cpp_basename(instance_.bootloader())));
692
693 // Gem5 also needs the ARM version of the bootloader, even though it
694 // doesn't use it. It'll even open it to check it's a valid ELF file.
695 // Work around this by copying such a named file from the same directory
696 CF_EXPECT(cuttlefish::Copy(
697 cpp_dirname(instance_.bootloader()) + "/boot.arm",
698 binaries_dir + "/boot.arm"));
699
700 return {};
701 }
702
703 private:
704 const CuttlefishConfig& config_;
705 KernelRamdiskRepacker& bir_;
706 };
707
708 class GeneratePersistentBootconfig : public SetupFeature {
709 public:
INJECT(GeneratePersistentBootconfig (const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance))710 INJECT(GeneratePersistentBootconfig(
711 const CuttlefishConfig& config,
712 const CuttlefishConfig::InstanceSpecific& instance))
713 : config_(config), instance_(instance) {}
714
715 // SetupFeature
Name() const716 std::string Name() const override {
717 return "GeneratePersistentBootconfig";
718 }
Enabled() const719 bool Enabled() const override {
720 return (!instance_.protected_vm());
721 }
722
723 private:
Dependencies() const724 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()725 Result<void> ResultSetup() override {
726 // Cuttlefish for the time being won't be able to support OTA from a
727 // non-bootconfig kernel to a bootconfig-kernel (or vice versa) IF the
728 // device is stopped (via stop_cvd). This is rarely an issue since OTA
729 // testing run on cuttlefish is done within one launch cycle of the device.
730 // If this ever becomes an issue, this code will have to be rewritten.
731 if(!instance_.bootconfig_supported()) {
732 return {};
733 }
734 const auto bootconfig_path = instance_.persistent_bootconfig_path();
735 if (!FileExists(bootconfig_path)) {
736 CF_EXPECT(CreateBlankImage(bootconfig_path, 1 /* mb */, "none"),
737 "Failed to create image at " << bootconfig_path);
738 }
739
740 auto bootconfig_fd = SharedFD::Open(bootconfig_path, O_RDWR);
741 CF_EXPECT(bootconfig_fd->IsOpen(),
742 "Unable to open bootconfig file: " << bootconfig_fd->StrError());
743
744 const auto bootconfig_args =
745 CF_EXPECT(BootconfigArgsFromConfig(config_, instance_));
746 const auto bootconfig =
747 CF_EXPECT(BootconfigArgsString(bootconfig_args, "\n")) + "\n";
748
749 LOG(DEBUG) << "bootconfig size is " << bootconfig.size();
750 ssize_t bytesWritten = WriteAll(bootconfig_fd, bootconfig);
751 CF_EXPECT(WriteAll(bootconfig_fd, bootconfig) == bootconfig.size(),
752 "Failed to write bootconfig to \"" << bootconfig_path << "\"");
753 LOG(DEBUG) << "Bootconfig parameters from vendor boot image and config are "
754 << ReadFile(bootconfig_path);
755
756 CF_EXPECT(bootconfig_fd->Truncate(bootconfig.size()) == 0,
757 "`truncate --size=" << bootconfig.size() << " bytes "
758 << bootconfig_path
759 << "` failed:" << bootconfig_fd->StrError());
760
761 if (config_.vm_manager() == Gem5Manager::name()) {
762 const off_t bootconfig_size_bytes_gem5 =
763 AlignToPowerOf2(bytesWritten, PARTITION_SIZE_SHIFT);
764 CF_EXPECT(bootconfig_fd->Truncate(bootconfig_size_bytes_gem5) == 0);
765 bootconfig_fd->Close();
766 } else {
767 bootconfig_fd->Close();
768 const off_t bootconfig_size_bytes = AlignToPowerOf2(
769 MAX_AVB_METADATA_SIZE + bootconfig.size(), PARTITION_SIZE_SHIFT);
770
771 auto avbtool_path = HostBinaryPath("avbtool");
772 Command bootconfig_hash_footer_cmd(avbtool_path);
773 bootconfig_hash_footer_cmd.AddParameter("add_hash_footer");
774 bootconfig_hash_footer_cmd.AddParameter("--image");
775 bootconfig_hash_footer_cmd.AddParameter(bootconfig_path);
776 bootconfig_hash_footer_cmd.AddParameter("--partition_size");
777 bootconfig_hash_footer_cmd.AddParameter(bootconfig_size_bytes);
778 bootconfig_hash_footer_cmd.AddParameter("--partition_name");
779 bootconfig_hash_footer_cmd.AddParameter("bootconfig");
780 bootconfig_hash_footer_cmd.AddParameter("--key");
781 bootconfig_hash_footer_cmd.AddParameter(
782 DefaultHostArtifactsPath("etc/cvd_avb_testkey.pem"));
783 bootconfig_hash_footer_cmd.AddParameter("--algorithm");
784 bootconfig_hash_footer_cmd.AddParameter("SHA256_RSA4096");
785 int success = bootconfig_hash_footer_cmd.Start().Wait();
786 CF_EXPECT(
787 success == 0,
788 "Unable to run append hash footer. Exited with status " << success);
789 }
790 return {};
791 }
792
793 const CuttlefishConfig& config_;
794 const CuttlefishConfig::InstanceSpecific& instance_;
795 };
796
797 class GeneratePersistentVbmeta : public SetupFeature {
798 public:
INJECT(GeneratePersistentVbmeta (const CuttlefishConfig::InstanceSpecific & instance,InitBootloaderEnvPartition & bootloader_env,GeneratePersistentBootconfig & bootconfig))799 INJECT(GeneratePersistentVbmeta(
800 const CuttlefishConfig::InstanceSpecific& instance,
801 InitBootloaderEnvPartition& bootloader_env,
802 GeneratePersistentBootconfig& bootconfig))
803 : instance_(instance),
804 bootloader_env_(bootloader_env),
805 bootconfig_(bootconfig) {}
806
807 // SetupFeature
Name() const808 std::string Name() const override {
809 return "GeneratePersistentVbmeta";
810 }
Enabled() const811 bool Enabled() const override {
812 return true;
813 }
814
815 private:
Dependencies() const816 std::unordered_set<SetupFeature*> Dependencies() const override {
817 return {
818 static_cast<SetupFeature*>(&bootloader_env_),
819 static_cast<SetupFeature*>(&bootconfig_),
820 };
821 }
822
Setup()823 bool Setup() override {
824 if (!instance_.protected_vm()) {
825 if (!PrepareVBMetaImage(instance_.vbmeta_path(), instance_.bootconfig_supported())) {
826 return false;
827 }
828 }
829
830 if (instance_.ap_boot_flow() == APBootFlow::Grub) {
831 if (!PrepareVBMetaImage(instance_.ap_vbmeta_path(), false)) {
832 return false;
833 }
834 }
835
836 return true;
837 }
838
PrepareVBMetaImage(const std::string & path,bool has_boot_config)839 bool PrepareVBMetaImage(const std::string& path, bool has_boot_config) {
840 auto avbtool_path = HostBinaryPath("avbtool");
841 Command vbmeta_cmd(avbtool_path);
842 vbmeta_cmd.AddParameter("make_vbmeta_image");
843 vbmeta_cmd.AddParameter("--output");
844 vbmeta_cmd.AddParameter(path);
845 vbmeta_cmd.AddParameter("--algorithm");
846 vbmeta_cmd.AddParameter("SHA256_RSA4096");
847 vbmeta_cmd.AddParameter("--key");
848 vbmeta_cmd.AddParameter(
849 DefaultHostArtifactsPath("etc/cvd_avb_testkey.pem"));
850
851 vbmeta_cmd.AddParameter("--chain_partition");
852 vbmeta_cmd.AddParameter("uboot_env:1:" +
853 DefaultHostArtifactsPath("etc/cvd.avbpubkey"));
854
855 if (has_boot_config) {
856 vbmeta_cmd.AddParameter("--chain_partition");
857 vbmeta_cmd.AddParameter("bootconfig:2:" +
858 DefaultHostArtifactsPath("etc/cvd.avbpubkey"));
859 }
860
861 bool success = vbmeta_cmd.Start().Wait();
862 if (success != 0) {
863 LOG(ERROR) << "Unable to create persistent vbmeta. Exited with status "
864 << success;
865 return false;
866 }
867
868 const auto vbmeta_size = FileSize(path);
869 if (vbmeta_size > VBMETA_MAX_SIZE) {
870 LOG(ERROR) << "Generated vbmeta - " << path
871 << " is larger than the expected " << VBMETA_MAX_SIZE
872 << ". Stopping.";
873 return false;
874 }
875 if (vbmeta_size != VBMETA_MAX_SIZE) {
876 auto fd = SharedFD::Open(path, O_RDWR);
877 if (!fd->IsOpen() || fd->Truncate(VBMETA_MAX_SIZE) != 0) {
878 LOG(ERROR) << "`truncate --size=" << VBMETA_MAX_SIZE << " "
879 << path << "` failed: " << fd->StrError();
880 return false;
881 }
882 }
883 return true;
884 }
885
886 const CuttlefishConfig::InstanceSpecific& instance_;
887 InitBootloaderEnvPartition& bootloader_env_;
888 GeneratePersistentBootconfig& bootconfig_;
889 };
890
891 class InitializeMetadataImage : public SetupFeature {
892 public:
INJECT(InitializeMetadataImage (const CuttlefishConfig::InstanceSpecific & instance))893 INJECT(InitializeMetadataImage(
894 const CuttlefishConfig::InstanceSpecific& instance))
895 : instance_(instance) {}
896
897 // SetupFeature
Name() const898 std::string Name() const override { return "InitializeMetadataImage"; }
Enabled() const899 bool Enabled() const override { return true; }
900
901 private:
Dependencies() const902 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()903 Result<void> ResultSetup() override {
904 if (FileExists(instance_.metadata_image()) &&
905 FileSize(instance_.metadata_image()) == instance_.blank_metadata_image_mb() << 20) {
906 return {};
907 }
908
909 CF_EXPECT(CreateBlankImage(instance_.new_metadata_image(),
910 instance_.blank_metadata_image_mb(), "none"),
911 "Failed to create \"" << instance_.new_metadata_image()
912 << "\" with size "
913 << instance_.blank_metadata_image_mb());
914 return {};
915 }
916 const CuttlefishConfig::InstanceSpecific& instance_;
917 };
918
919 class InitializeAccessKregistryImage : public SetupFeature {
920 public:
INJECT(InitializeAccessKregistryImage (const CuttlefishConfig::InstanceSpecific & instance))921 INJECT(InitializeAccessKregistryImage(
922 const CuttlefishConfig::InstanceSpecific& instance))
923 : instance_(instance) {}
924
925 // SetupFeature
Name() const926 std::string Name() const override { return "InitializeAccessKregistryImage"; }
Enabled() const927 bool Enabled() const override { return !instance_.protected_vm(); }
928
929 private:
Dependencies() const930 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()931 Result<void> ResultSetup() override {
932 auto access_kregistry = instance_.access_kregistry_path();
933 if (FileExists(access_kregistry)) {
934 return {};
935 }
936 CF_EXPECT(CreateBlankImage(access_kregistry, 2 /* mb */, "none"),
937 "Failed to create \"" << access_kregistry << "\"");
938 return {};
939 }
940
941 const CuttlefishConfig::InstanceSpecific& instance_;
942 };
943
944 class InitializeHwcomposerPmemImage : public SetupFeature {
945 public:
INJECT(InitializeHwcomposerPmemImage (const CuttlefishConfig::InstanceSpecific & instance))946 INJECT(InitializeHwcomposerPmemImage(
947 const CuttlefishConfig::InstanceSpecific& instance))
948 : instance_(instance) {}
949
950 // SetupFeature
Name() const951 std::string Name() const override { return "InitializeHwcomposerPmemImage"; }
Enabled() const952 bool Enabled() const override {
953 return instance_.hwcomposer() != kHwComposerNone &&
954 !instance_.protected_vm();
955 }
956
957 private:
Dependencies() const958 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()959 Result<void> ResultSetup() override {
960 if (FileExists(instance_.hwcomposer_pmem_path())) {
961 return {};
962 }
963 CF_EXPECT(
964 CreateBlankImage(instance_.hwcomposer_pmem_path(), 2 /* mb */, "none"),
965 "Failed creating \"" << instance_.hwcomposer_pmem_path() << "\"");
966 return {};
967 }
968
969 const CuttlefishConfig::InstanceSpecific& instance_;
970 };
971
972 class InitializePstore : public SetupFeature {
973 public:
INJECT(InitializePstore (const CuttlefishConfig::InstanceSpecific & instance))974 INJECT(InitializePstore(const CuttlefishConfig::InstanceSpecific& instance))
975 : instance_(instance) {}
976
977 // SetupFeature
Name() const978 std::string Name() const override { return "InitializePstore"; }
Enabled() const979 bool Enabled() const override { return !instance_.protected_vm(); }
980
981 private:
Dependencies() const982 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()983 Result<void> ResultSetup() override {
984 if (FileExists(instance_.pstore_path())) {
985 return {};
986 }
987
988 CF_EXPECT(CreateBlankImage(instance_.pstore_path(), 2 /* mb */, "none"),
989 "Failed to create \"" << instance_.pstore_path() << "\"");
990 return {};
991 }
992
993 const CuttlefishConfig::InstanceSpecific& instance_;
994 };
995
996 class InitializeSdCard : public SetupFeature {
997 public:
INJECT(InitializeSdCard (const CuttlefishConfig::InstanceSpecific & instance))998 INJECT(InitializeSdCard(const CuttlefishConfig::InstanceSpecific& instance))
999 : instance_(instance) {}
1000
1001 // SetupFeature
Name() const1002 std::string Name() const override { return "InitializeSdCard"; }
Enabled() const1003 bool Enabled() const override {
1004 return instance_.use_sdcard() && !instance_.protected_vm();
1005 }
1006
1007 private:
Dependencies() const1008 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()1009 Result<void> ResultSetup() override {
1010 if (FileExists(instance_.sdcard_path())) {
1011 return {};
1012 }
1013 CF_EXPECT(CreateBlankImage(instance_.sdcard_path(),
1014 instance_.blank_sdcard_image_mb(), "sdcard"),
1015 "Failed to create \"" << instance_.sdcard_path() << "\"");
1016 return {};
1017 }
1018
1019 const CuttlefishConfig::InstanceSpecific& instance_;
1020 };
1021
1022 class InitializeFactoryResetProtected : public SetupFeature {
1023 public:
INJECT(InitializeFactoryResetProtected (const CuttlefishConfig::InstanceSpecific & instance))1024 INJECT(InitializeFactoryResetProtected(
1025 const CuttlefishConfig::InstanceSpecific& instance))
1026 : instance_(instance) {}
1027
1028 // SetupFeature
Name() const1029 std::string Name() const override { return "InitializeSdCard"; }
Enabled() const1030 bool Enabled() const override { return !instance_.protected_vm(); }
1031
1032 private:
Dependencies() const1033 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()1034 Result<void> ResultSetup() override {
1035 auto frp = instance_.factory_reset_protected_path();
1036 if (FileExists(frp)) {
1037 return {};
1038 }
1039 CF_EXPECT(CreateBlankImage(frp, 1 /* mb */, "none"),
1040 "Failed to create \"" << frp << "\"");
1041 return {};
1042 }
1043
1044 const CuttlefishConfig::InstanceSpecific& instance_;
1045 };
1046
1047 class InitializeInstanceCompositeDisk : public SetupFeature {
1048 public:
INJECT(InitializeInstanceCompositeDisk (const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance,InitializeFactoryResetProtected & frp,GeneratePersistentVbmeta & vbmeta))1049 INJECT(InitializeInstanceCompositeDisk(
1050 const CuttlefishConfig& config,
1051 const CuttlefishConfig::InstanceSpecific& instance,
1052 InitializeFactoryResetProtected& frp,
1053 GeneratePersistentVbmeta& vbmeta))
1054 : config_(config),
1055 instance_(instance),
1056 frp_(frp),
1057 vbmeta_(vbmeta) {}
1058
Name() const1059 std::string Name() const override {
1060 return "InitializeInstanceCompositeDisk";
1061 }
Enabled() const1062 bool Enabled() const override { return true; }
1063
1064 private:
Dependencies() const1065 std::unordered_set<SetupFeature*> Dependencies() const override {
1066 return {
1067 static_cast<SetupFeature*>(&frp_),
1068 static_cast<SetupFeature*>(&vbmeta_),
1069 };
1070 }
ResultSetup()1071 Result<void> ResultSetup() override {
1072 const auto ipath = [this](const std::string& path) -> std::string {
1073 return instance_.PerInstancePath(path.c_str());
1074 };
1075 auto persistent_disk_builder =
1076 DiskBuilder()
1077 .Partitions(persistent_composite_disk_config(instance_))
1078 .VmManager(config_.vm_manager())
1079 .CrosvmPath(instance_.crosvm_binary())
1080 .ConfigPath(ipath("persistent_composite_disk_config.txt"))
1081 .HeaderPath(ipath("persistent_composite_gpt_header.img"))
1082 .FooterPath(ipath("persistent_composite_gpt_footer.img"))
1083 .CompositeDiskPath(instance_.persistent_composite_disk_path())
1084 .ResumeIfPossible(FLAGS_resume);
1085 CF_EXPECT(persistent_disk_builder.BuildCompositeDiskIfNecessary());
1086
1087 if (instance_.ap_boot_flow() == APBootFlow::Grub) {
1088 auto persistent_ap_disk_builder =
1089 DiskBuilder()
1090 .Partitions(persistent_ap_composite_disk_config(instance_))
1091 .VmManager(config_.vm_manager())
1092 .CrosvmPath(instance_.crosvm_binary())
1093 .ConfigPath(ipath("ap_persistent_composite_disk_config.txt"))
1094 .HeaderPath(ipath("ap_persistent_composite_gpt_header.img"))
1095 .FooterPath(ipath("ap_persistent_composite_gpt_footer.img"))
1096 .CompositeDiskPath(instance_.persistent_ap_composite_disk_path())
1097 .ResumeIfPossible(FLAGS_resume);
1098 CF_EXPECT(persistent_ap_disk_builder.BuildCompositeDiskIfNecessary());
1099 }
1100
1101 return {};
1102 }
1103
1104 const CuttlefishConfig& config_;
1105 const CuttlefishConfig::InstanceSpecific& instance_;
1106 InitializeFactoryResetProtected& frp_;
1107 GeneratePersistentVbmeta& vbmeta_;
1108 };
1109
1110 class VbmetaEnforceMinimumSize : public SetupFeature {
1111 public:
INJECT(VbmetaEnforceMinimumSize (const CuttlefishConfig::InstanceSpecific & instance))1112 INJECT(VbmetaEnforceMinimumSize(
1113 const CuttlefishConfig::InstanceSpecific& instance))
1114 : instance_(instance) {}
1115
Name() const1116 std::string Name() const override { return "VbmetaEnforceMinimumSize"; }
Enabled() const1117 bool Enabled() const override { return true; }
1118
1119 private:
Dependencies() const1120 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()1121 Result<void> ResultSetup() override {
1122 // libavb expects to be able to read the maximum vbmeta size, so we must
1123 // provide a partition which matches this or the read will fail
1124 for (const auto& vbmeta_image :
1125 {instance_.vbmeta_image(), instance_.vbmeta_system_image(),
1126 instance_.vbmeta_vendor_dlkm_image()}) {
1127 // In some configurations of cuttlefish, the vendor dlkm vbmeta image does
1128 // not exist
1129 if (FileExists(vbmeta_image) && FileSize(vbmeta_image) != VBMETA_MAX_SIZE) {
1130 auto fd = SharedFD::Open(vbmeta_image, O_RDWR);
1131 CF_EXPECT(fd->IsOpen(), "Could not open \"" << vbmeta_image << "\": "
1132 << fd->StrError());
1133 CF_EXPECT(fd->Truncate(VBMETA_MAX_SIZE) == 0,
1134 "`truncate --size=" << VBMETA_MAX_SIZE << " " << vbmeta_image
1135 << "` failed: " << fd->StrError());
1136 }
1137 }
1138 return {};
1139 }
1140
1141 const CuttlefishConfig::InstanceSpecific& instance_;
1142 };
1143
1144 class BootloaderPresentCheck : public SetupFeature {
1145 public:
INJECT(BootloaderPresentCheck (const CuttlefishConfig::InstanceSpecific & instance))1146 INJECT(BootloaderPresentCheck(
1147 const CuttlefishConfig::InstanceSpecific& instance))
1148 : instance_(instance) {}
1149
Name() const1150 std::string Name() const override { return "BootloaderPresentCheck"; }
Enabled() const1151 bool Enabled() const override { return true; }
1152
1153 private:
Dependencies() const1154 std::unordered_set<SetupFeature*> Dependencies() const override { return {}; }
ResultSetup()1155 Result<void> ResultSetup() override {
1156 CF_EXPECT(FileHasContent(instance_.bootloader()),
1157 "File not found: " << instance_.bootloader());
1158 return {};
1159 }
1160
1161 const CuttlefishConfig::InstanceSpecific& instance_;
1162 };
1163
DiskChangesComponent(const FetcherConfig * fetcher,const CuttlefishConfig * config,const CuttlefishConfig::InstanceSpecific * instance)1164 static fruit::Component<> DiskChangesComponent(
1165 const FetcherConfig* fetcher, const CuttlefishConfig* config,
1166 const CuttlefishConfig::InstanceSpecific* instance) {
1167 return fruit::createComponent()
1168 .bindInstance(*fetcher)
1169 .bindInstance(*config)
1170 .bindInstance(*instance)
1171 .addMultibinding<SetupFeature, InitializeMetadataImage>()
1172 .addMultibinding<SetupFeature, KernelRamdiskRepacker>()
1173 .addMultibinding<SetupFeature, VbmetaEnforceMinimumSize>()
1174 .addMultibinding<SetupFeature, BootloaderPresentCheck>()
1175 .addMultibinding<SetupFeature, Gem5ImageUnpacker>()
1176 .install(InitializeMiscImageComponent)
1177 // Create esp if necessary
1178 .install(InitializeEspImageComponent)
1179 .install(SuperImageRebuilderComponent);
1180 }
1181
DiskChangesPerInstanceComponent(const FetcherConfig * fetcher,const CuttlefishConfig * config,const CuttlefishConfig::InstanceSpecific * instance)1182 static fruit::Component<> DiskChangesPerInstanceComponent(
1183 const FetcherConfig* fetcher, const CuttlefishConfig* config,
1184 const CuttlefishConfig::InstanceSpecific* instance) {
1185 return fruit::createComponent()
1186 .bindInstance(*fetcher)
1187 .bindInstance(*config)
1188 .bindInstance(*instance)
1189 .addMultibinding<SetupFeature, InitializeAccessKregistryImage>()
1190 .addMultibinding<SetupFeature, InitializeHwcomposerPmemImage>()
1191 .addMultibinding<SetupFeature, InitializePstore>()
1192 .addMultibinding<SetupFeature, InitializeSdCard>()
1193 .addMultibinding<SetupFeature, InitializeFactoryResetProtected>()
1194 .addMultibinding<SetupFeature, GeneratePersistentBootconfig>()
1195 .addMultibinding<SetupFeature, GeneratePersistentVbmeta>()
1196 .addMultibinding<SetupFeature, InitializeInstanceCompositeDisk>()
1197 .install(InitializeDataImageComponent)
1198 .install(InitBootloaderEnvPartitionComponent);
1199 }
1200
DiskImageFlagsVectorization(CuttlefishConfig & config,const FetcherConfig & fetcher_config)1201 Result<void> DiskImageFlagsVectorization(CuttlefishConfig& config, const FetcherConfig& fetcher_config) {
1202 std::vector<std::string> boot_image =
1203 android::base::Split(FLAGS_boot_image, ",");
1204 std::vector<std::string> init_boot_image =
1205 android::base::Split(FLAGS_init_boot_image, ",");
1206 std::vector<std::string> data_image =
1207 android::base::Split(FLAGS_data_image, ",");
1208 std::vector<std::string> super_image =
1209 android::base::Split(FLAGS_super_image, ",");
1210 std::vector<std::string> misc_image =
1211 android::base::Split(FLAGS_misc_image, ",");
1212 std::vector<std::string> misc_info =
1213 android::base::Split(FLAGS_misc_info_txt, ",");
1214 std::vector<std::string> metadata_image =
1215 android::base::Split(FLAGS_metadata_image, ",");
1216 std::vector<std::string> vendor_boot_image =
1217 android::base::Split(FLAGS_vendor_boot_image, ",");
1218 std::vector<std::string> vbmeta_image =
1219 android::base::Split(FLAGS_vbmeta_image, ",");
1220 std::vector<std::string> vbmeta_system_image =
1221 android::base::Split(FLAGS_vbmeta_system_image, ",");
1222 auto vbmeta_vendor_dlkm_image =
1223 android::base::Split(FLAGS_vbmeta_vendor_dlkm_image, ",");
1224
1225 std::vector<std::string> linux_kernel_path =
1226 android::base::Split(FLAGS_linux_kernel_path, ",");
1227 std::vector<std::string> linux_initramfs_path =
1228 android::base::Split(FLAGS_linux_initramfs_path, ",");
1229 std::vector<std::string> linux_root_image =
1230 android::base::Split(FLAGS_linux_root_image, ",");
1231
1232 std::vector<std::string> fuchsia_zedboot_path =
1233 android::base::Split(FLAGS_fuchsia_zedboot_path, ",");
1234 std::vector<std::string> fuchsia_multiboot_bin_path =
1235 android::base::Split(FLAGS_fuchsia_multiboot_bin_path, ",");
1236 std::vector<std::string> fuchsia_root_image =
1237 android::base::Split(FLAGS_fuchsia_root_image, ",");
1238
1239 std::vector<std::string> custom_partition_path =
1240 android::base::Split(FLAGS_custom_partition_path, ",");
1241
1242 std::vector<std::string> bootloader =
1243 android::base::Split(FLAGS_bootloader, ",");
1244 std::vector<std::string> initramfs_path =
1245 android::base::Split(FLAGS_initramfs_path, ",");
1246 std::vector<std::string> kernel_path =
1247 android::base::Split(FLAGS_kernel_path, ",");
1248
1249 std::vector<std::string> blank_metadata_image_mb =
1250 android::base::Split(FLAGS_blank_metadata_image_mb, ",");
1251 std::vector<std::string> blank_sdcard_image_mb =
1252 android::base::Split(FLAGS_blank_sdcard_image_mb, ",");
1253
1254 std::string cur_kernel_path;
1255 std::string cur_initramfs_path;
1256 std::string cur_boot_image;
1257 std::string cur_vendor_boot_image;
1258 std::string cur_super_image;
1259 std::string cur_metadata_image;
1260 std::string cur_misc_image;
1261 int cur_blank_metadata_image_mb{};
1262 int value{};
1263 int instance_index = 0;
1264 auto instance_nums =
1265 CF_EXPECT(InstanceNumsCalculator().FromGlobalGflags().Calculate());
1266 for (const auto& num : instance_nums) {
1267 auto instance = config.ForInstance(num);
1268 if (instance_index >= misc_image.size()) {
1269 // legacy variable. Vectorize by copy [0] to all instances
1270 cur_misc_image = misc_image[0];
1271 } else {
1272 cur_misc_image = misc_image[instance_index];
1273 }
1274 instance.set_misc_image(cur_misc_image);
1275 if (instance_index >= misc_info.size()) {
1276 instance.set_misc_info_txt(misc_info[0]);
1277 } else {
1278 instance.set_misc_info_txt(misc_info[instance_index]);
1279 }
1280 if (instance_index >= boot_image.size()) {
1281 cur_boot_image = boot_image[0];
1282 } else {
1283 cur_boot_image = boot_image[instance_index];
1284 }
1285 instance.set_boot_image(cur_boot_image);
1286 instance.set_new_boot_image(cur_boot_image);
1287
1288 if (instance_index >= init_boot_image.size()) {
1289 instance.set_init_boot_image(init_boot_image[0]);
1290 } else {
1291 instance.set_init_boot_image(init_boot_image[instance_index]);
1292 }
1293 if (instance_index >= vendor_boot_image.size()) {
1294 cur_vendor_boot_image = vendor_boot_image[0];
1295 } else {
1296 cur_vendor_boot_image = vendor_boot_image[instance_index];
1297 }
1298 instance.set_vendor_boot_image(cur_vendor_boot_image);
1299 instance.set_new_vendor_boot_image(cur_vendor_boot_image);
1300
1301 if (instance_index >= vbmeta_image.size()) {
1302 instance.set_vbmeta_image(vbmeta_image[0]);
1303 } else {
1304 instance.set_vbmeta_image(vbmeta_image[instance_index]);
1305 }
1306 if (instance_index >= vbmeta_system_image.size()) {
1307 instance.set_vbmeta_system_image(vbmeta_system_image[0]);
1308 } else {
1309 instance.set_vbmeta_system_image(vbmeta_system_image[instance_index]);
1310 }
1311 if (instance_index >= vbmeta_system_image.size()) {
1312 instance.set_vbmeta_vendor_dlkm_image(vbmeta_vendor_dlkm_image[0]);
1313 } else {
1314 instance.set_vbmeta_vendor_dlkm_image(
1315 vbmeta_vendor_dlkm_image[instance_index]);
1316 }
1317 if (instance_index >= super_image.size()) {
1318 cur_super_image = super_image[0];
1319 } else {
1320 cur_super_image = super_image[instance_index];
1321 }
1322 instance.set_super_image(cur_super_image);
1323 if (instance_index >= data_image.size()) {
1324 instance.set_data_image(data_image[0]);
1325 } else {
1326 instance.set_data_image(data_image[instance_index]);
1327 }
1328 if (instance_index >= metadata_image.size()) {
1329 cur_metadata_image = metadata_image[0];
1330 } else {
1331 cur_metadata_image = metadata_image[instance_index];
1332 }
1333 instance.set_metadata_image(cur_metadata_image);
1334 if (instance_index >= linux_kernel_path.size()) {
1335 instance.set_linux_kernel_path(linux_kernel_path[0]);
1336 } else {
1337 instance.set_linux_kernel_path(linux_kernel_path[instance_index]);
1338 }
1339 if (instance_index >= linux_initramfs_path.size()) {
1340 instance.set_linux_initramfs_path(linux_initramfs_path[0]);
1341 } else {
1342 instance.set_linux_initramfs_path(linux_initramfs_path[instance_index]);
1343 }
1344 if (instance_index >= linux_root_image.size()) {
1345 instance.set_linux_root_image(linux_root_image[0]);
1346 } else {
1347 instance.set_linux_root_image(linux_root_image[instance_index]);
1348 }
1349 if (instance_index >= fuchsia_zedboot_path.size()) {
1350 instance.set_fuchsia_zedboot_path(fuchsia_zedboot_path[0]);
1351 } else {
1352 instance.set_fuchsia_zedboot_path(fuchsia_zedboot_path[instance_index]);
1353 }
1354 if (instance_index >= fuchsia_multiboot_bin_path.size()) {
1355 instance.set_fuchsia_multiboot_bin_path(fuchsia_multiboot_bin_path[0]);
1356 } else {
1357 instance.set_fuchsia_multiboot_bin_path(fuchsia_multiboot_bin_path[instance_index]);
1358 }
1359 if (instance_index >= fuchsia_root_image.size()) {
1360 instance.set_fuchsia_root_image(fuchsia_root_image[0]);
1361 } else {
1362 instance.set_fuchsia_root_image(fuchsia_root_image[instance_index]);
1363 }
1364 if (instance_index >= custom_partition_path.size()) {
1365 instance.set_custom_partition_path(custom_partition_path[0]);
1366 } else {
1367 instance.set_custom_partition_path(custom_partition_path[instance_index]);
1368 }
1369 if (instance_index >= bootloader.size()) {
1370 instance.set_bootloader(bootloader[0]);
1371 } else {
1372 instance.set_bootloader(bootloader[instance_index]);
1373 }
1374 if (instance_index >= kernel_path.size()) {
1375 cur_kernel_path = kernel_path[0];
1376 } else {
1377 cur_kernel_path = kernel_path[instance_index];
1378 }
1379 instance.set_kernel_path(cur_kernel_path);
1380 if (instance_index >= initramfs_path.size()) {
1381 cur_initramfs_path = initramfs_path[0];
1382 } else {
1383 cur_initramfs_path = initramfs_path[instance_index];
1384 }
1385 instance.set_initramfs_path(cur_initramfs_path);
1386
1387 if (instance_index >= blank_metadata_image_mb.size()) {
1388 CHECK(android::base::ParseInt(blank_metadata_image_mb[0],
1389 &value))
1390 << "Invalid 'blank_metadata_image_mb' "
1391 << blank_metadata_image_mb[0];
1392 } else {
1393 CHECK(android::base::ParseInt(blank_metadata_image_mb[instance_index],
1394 &value))
1395 << "Invalid 'blank_metadata_image_mb' "
1396 << blank_metadata_image_mb[instance_index];
1397 }
1398 instance.set_blank_metadata_image_mb(value);
1399 cur_blank_metadata_image_mb = value;
1400
1401 if (instance_index >= blank_sdcard_image_mb.size()) {
1402 CHECK(android::base::ParseInt(blank_sdcard_image_mb[0],
1403 &value))
1404 << "Invalid 'blank_sdcard_image_mb' "
1405 << blank_sdcard_image_mb[0];
1406 } else {
1407 CHECK(android::base::ParseInt(blank_sdcard_image_mb[instance_index],
1408 &value))
1409 << "Invalid 'blank_sdcard_image_mb' "
1410 << blank_sdcard_image_mb[instance_index];
1411 }
1412 instance.set_blank_sdcard_image_mb(value);
1413
1414 // Repacking a boot.img changes boot_image and vendor_boot_image paths
1415 const CuttlefishConfig& const_config = const_cast<const CuttlefishConfig&>(config);
1416 const CuttlefishConfig::InstanceSpecific const_instance = const_config.ForInstance(num);
1417 if (cur_kernel_path.size() &&
1418 config.vm_manager() != Gem5Manager::name()) {
1419 const std::string new_boot_image_path =
1420 const_instance.PerInstancePath("boot_repacked.img");
1421 // change the new flag value to corresponding instance
1422 instance.set_new_boot_image(new_boot_image_path.c_str());
1423 }
1424
1425 if (cur_kernel_path.size() || cur_initramfs_path.size()) {
1426 const std::string new_vendor_boot_image_path =
1427 const_instance.PerInstancePath("vendor_boot_repacked.img");
1428 // Repack the vendor boot images if kernels and/or ramdisks are passed in.
1429 if (cur_initramfs_path.size()) {
1430 // change the new flag value to corresponding instance
1431 instance.set_new_vendor_boot_image(new_vendor_boot_image_path.c_str());
1432 }
1433 }
1434
1435 // We will need to rebuild vendor_dlkm if custom ramdisk is specified, as a
1436 // result super image would need to be rebuilt as well.
1437 if (SuperImageNeedsRebuilding(fetcher_config) ||
1438 cur_initramfs_path.size()) {
1439 const std::string new_super_image_path =
1440 const_instance.PerInstancePath("super.img");
1441 instance.set_new_super_image(new_super_image_path);
1442 }
1443
1444 if (FileExists(cur_metadata_image) &&
1445 FileSize(cur_metadata_image) == cur_blank_metadata_image_mb << 20) {
1446 instance.set_new_metadata_image(cur_metadata_image);
1447 } else {
1448 const std::string new_metadata_image_path =
1449 const_instance.PerInstancePath("metadata.img");
1450 instance.set_new_metadata_image(new_metadata_image_path);
1451 }
1452 instance.set_new_vbmeta_vendor_dlkm_image(
1453 const_instance.PerInstancePath("vbmeta_vendor_dlkm_repacked.img"));
1454
1455 if (FileHasContent(cur_misc_image)) {
1456 instance.set_new_misc_image(cur_misc_image);
1457 } else {
1458 const std::string new_misc_image_path =
1459 const_instance.PerInstancePath("misc.img");
1460 instance.set_new_misc_image(new_misc_image_path);
1461 }
1462 instance_index++;
1463 }
1464 return {};
1465 }
1466
CreateDynamicDiskFiles(const FetcherConfig & fetcher_config,const CuttlefishConfig & config)1467 Result<void> CreateDynamicDiskFiles(const FetcherConfig& fetcher_config,
1468 const CuttlefishConfig& config) {
1469 for (const auto& instance : config.Instances()) {
1470 // TODO(schuffelen): Unify this with the other injector created in
1471 // assemble_cvd.cpp
1472 fruit::Injector<> injector(DiskChangesComponent, &fetcher_config, &config,
1473 &instance);
1474 for (auto& late_injected : injector.getMultibindings<LateInjected>()) {
1475 CF_EXPECT(late_injected->LateInject(injector));
1476 }
1477
1478 const auto& features = injector.getMultibindings<SetupFeature>();
1479 CF_EXPECT(SetupFeature::RunSetup(features));
1480 fruit::Injector<> instance_injector(DiskChangesPerInstanceComponent,
1481 &fetcher_config, &config, &instance);
1482 for (auto& late_injected :
1483 instance_injector.getMultibindings<LateInjected>()) {
1484 CF_EXPECT(late_injected->LateInject(instance_injector));
1485 }
1486
1487 const auto& instance_features =
1488 instance_injector.getMultibindings<SetupFeature>();
1489 CF_EXPECT(SetupFeature::RunSetup(instance_features),
1490 "instance = \"" << instance.instance_name() << "\"");
1491
1492 // Check if filling in the sparse image would run out of disk space.
1493 auto existing_sizes = SparseFileSizes(instance.data_image());
1494 CF_EXPECT(existing_sizes.sparse_size > 0 || existing_sizes.disk_size > 0,
1495 "Unable to determine size of \"" << instance.data_image()
1496 << "\". Does this file exist?");
1497 auto available_space = AvailableSpaceAtPath(instance.data_image());
1498 if (available_space <
1499 existing_sizes.sparse_size - existing_sizes.disk_size) {
1500 // TODO(schuffelen): Duplicate this check in run_cvd when it can run on a
1501 // separate machine
1502 return CF_ERR("Not enough space remaining in fs containing \""
1503 << instance.data_image() << "\", wanted "
1504 << (existing_sizes.sparse_size - existing_sizes.disk_size)
1505 << ", got " << available_space);
1506 } else {
1507 LOG(DEBUG) << "Available space: " << available_space;
1508 LOG(DEBUG) << "Sparse size of \"" << instance.data_image()
1509 << "\": " << existing_sizes.sparse_size;
1510 LOG(DEBUG) << "Disk size of \"" << instance.data_image()
1511 << "\": " << existing_sizes.disk_size;
1512 }
1513
1514 auto os_disk_builder = OsCompositeDiskBuilder(config, instance);
1515 const auto os_built_composite = CF_EXPECT(os_disk_builder.BuildCompositeDiskIfNecessary());
1516
1517 auto ap_disk_builder = ApCompositeDiskBuilder(config, instance);
1518 if (instance.ap_boot_flow() != APBootFlow::None) {
1519 CF_EXPECT(ap_disk_builder.BuildCompositeDiskIfNecessary());
1520 }
1521
1522 if (os_built_composite) {
1523 if (FileExists(instance.access_kregistry_path())) {
1524 CF_EXPECT(CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */,
1525 "none"),
1526 "Failed for \"" << instance.access_kregistry_path() << "\"");
1527 }
1528 if (FileExists(instance.hwcomposer_pmem_path())) {
1529 CF_EXPECT(CreateBlankImage(instance.hwcomposer_pmem_path(), 2 /* mb */,
1530 "none"),
1531 "Failed for \"" << instance.hwcomposer_pmem_path() << "\"");
1532 }
1533 if (FileExists(instance.pstore_path())) {
1534 CF_EXPECT(CreateBlankImage(instance.pstore_path(), 2 /* mb */, "none"),
1535 "Failed for\"" << instance.pstore_path() << "\"");
1536 }
1537 }
1538
1539 if (!instance.protected_vm()) {
1540 os_disk_builder.OverlayPath(instance.PerInstancePath("overlay.img"));
1541 CF_EXPECT(os_disk_builder.BuildOverlayIfNecessary());
1542 if (instance.ap_boot_flow() != APBootFlow::None) {
1543 ap_disk_builder.OverlayPath(instance.PerInstancePath("ap_overlay.img"));
1544 CF_EXPECT(ap_disk_builder.BuildOverlayIfNecessary());
1545 }
1546 }
1547 }
1548
1549 for (auto instance : config.Instances()) {
1550 // Check that the files exist
1551 for (const auto& file : instance.virtual_disk_paths()) {
1552 if (!file.empty()) {
1553 CF_EXPECT(FileHasContent(file), "File not found: \"" << file << "\"");
1554 }
1555 }
1556 // Gem5 Simulate per-instance what the bootloader would usually do
1557 // Since on other devices this runs every time, just do it here every time
1558 if (config.vm_manager() == Gem5Manager::name()) {
1559 RepackGem5BootImage(instance.PerInstancePath("initrd.img"),
1560 instance.persistent_bootconfig_path(),
1561 config.assembly_dir(), instance.initramfs_path());
1562 }
1563 }
1564
1565 return {};
1566 }
1567
1568 } // namespace cuttlefish
1569