• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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