• 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 <sys/statvfs.h>
20 
21 #include <fstream>
22 
23 #include <android-base/logging.h>
24 #include <android-base/strings.h>
25 #include <gflags/gflags.h>
26 
27 #include "common/libs/fs/shared_buf.h"
28 #include "common/libs/utils/environment.h"
29 #include "common/libs/utils/files.h"
30 #include "common/libs/utils/size_utils.h"
31 #include "common/libs/utils/subprocess.h"
32 #include "host/commands/assemble_cvd/boot_config.h"
33 #include "host/commands/assemble_cvd/boot_image_utils.h"
34 #include "host/commands/assemble_cvd/super_image_mixer.h"
35 #include "host/libs/config/bootconfig_args.h"
36 #include "host/libs/config/cuttlefish_config.h"
37 #include "host/libs/config/data_image.h"
38 #include "host/libs/image_aggregator/image_aggregator.h"
39 #include "host/libs/vm_manager/crosvm_manager.h"
40 
41 // Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the headers
42 #define VBMETA_MAX_SIZE 65536ul
43 
44 DEFINE_string(system_image_dir, cuttlefish::DefaultGuestImagePath(""),
45               "Location of the system partition images.");
46 
47 DEFINE_string(boot_image, "",
48               "Location of cuttlefish boot image. If empty it is assumed to be "
49               "boot.img in the directory specified by -system_image_dir.");
50 DEFINE_string(data_image, "", "Location of the data partition image.");
51 DEFINE_string(super_image, "", "Location of the super partition image.");
52 DEFINE_string(misc_image, "",
53               "Location of the misc partition image. If the image does not "
54               "exist, a blank new misc partition image is created.");
55 DEFINE_string(metadata_image, "", "Location of the metadata partition image "
56               "to be generated.");
57 DEFINE_string(vendor_boot_image, "",
58               "Location of cuttlefish vendor boot image. If empty it is assumed to "
59               "be vendor_boot.img in the directory specified by -system_image_dir.");
60 DEFINE_string(vbmeta_image, "",
61               "Location of cuttlefish vbmeta image. If empty it is assumed to "
62               "be vbmeta.img in the directory specified by -system_image_dir.");
63 DEFINE_string(vbmeta_system_image, "",
64               "Location of cuttlefish vbmeta_system image. If empty it is assumed to "
65               "be vbmeta_system.img in the directory specified by -system_image_dir.");
66 DEFINE_string(esp, "", "Path to ESP partition image (FAT formatted)");
67 
68 DEFINE_int32(blank_metadata_image_mb, 16,
69              "The size of the blank metadata image to generate, MB.");
70 DEFINE_int32(blank_sdcard_image_mb, 2048,
71              "If enabled, the size of the blank sdcard image to generate, MB.");
72 
73 DECLARE_string(bootloader);
74 DECLARE_bool(use_sdcard);
75 DECLARE_string(initramfs_path);
76 DECLARE_string(kernel_path);
77 DECLARE_bool(resume);
78 DECLARE_bool(protected_vm);
79 
80 namespace cuttlefish {
81 
82 using vm_manager::CrosvmManager;
83 
ResolveInstanceFiles()84 bool ResolveInstanceFiles() {
85   if (FLAGS_system_image_dir.empty()) {
86     LOG(ERROR) << "--system_image_dir must be specified.";
87     return false;
88   }
89 
90   // If user did not specify location of either of these files, expect them to
91   // be placed in --system_image_dir location.
92   std::string default_boot_image = FLAGS_system_image_dir + "/boot.img";
93   SetCommandLineOptionWithMode("boot_image", default_boot_image.c_str(),
94                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
95   std::string default_data_image = FLAGS_system_image_dir + "/userdata.img";
96   SetCommandLineOptionWithMode("data_image", default_data_image.c_str(),
97                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
98   std::string default_metadata_image = FLAGS_system_image_dir + "/metadata.img";
99   SetCommandLineOptionWithMode("metadata_image", default_metadata_image.c_str(),
100                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
101   std::string default_super_image = FLAGS_system_image_dir + "/super.img";
102   SetCommandLineOptionWithMode("super_image", default_super_image.c_str(),
103                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
104   std::string default_misc_image = FLAGS_system_image_dir + "/misc.img";
105   SetCommandLineOptionWithMode("misc_image", default_misc_image.c_str(),
106                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
107   std::string default_vendor_boot_image = FLAGS_system_image_dir
108                                         + "/vendor_boot.img";
109   SetCommandLineOptionWithMode("vendor_boot_image",
110                                default_vendor_boot_image.c_str(),
111                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
112   std::string default_vbmeta_image = FLAGS_system_image_dir + "/vbmeta.img";
113   SetCommandLineOptionWithMode("vbmeta_image", default_vbmeta_image.c_str(),
114                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
115   std::string default_vbmeta_system_image = FLAGS_system_image_dir
116                                           + "/vbmeta_system.img";
117   SetCommandLineOptionWithMode("vbmeta_system_image",
118                                default_vbmeta_system_image.c_str(),
119                                google::FlagSettingMode::SET_FLAGS_DEFAULT);
120 
121   return true;
122 }
123 
os_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)124 std::vector<ImagePartition> os_composite_disk_config(
125     const CuttlefishConfig::InstanceSpecific& instance) {
126   std::vector<ImagePartition> partitions;
127   partitions.push_back(ImagePartition {
128     .label = "misc",
129     .image_file_path = FLAGS_misc_image,
130   });
131   if (!FLAGS_esp.empty()) {
132     partitions.push_back(ImagePartition {
133       .label = "esp",
134       .image_file_path = FLAGS_esp,
135       .type = kEfiSystemPartition,
136     });
137   }
138   partitions.push_back(ImagePartition {
139     .label = "boot_a",
140     .image_file_path = FLAGS_boot_image,
141   });
142   partitions.push_back(ImagePartition {
143     .label = "boot_b",
144     .image_file_path = FLAGS_boot_image,
145   });
146   // Boot image repacking is not supported on protected VMs. Repacking requires
147   // resigning the image and keys on android hosts aren't trusted.
148   if (!FLAGS_protected_vm) {
149     partitions.push_back(ImagePartition{
150         .label = "vendor_boot_a",
151         .image_file_path = instance.vendor_boot_image_path(),
152     });
153     partitions.push_back(ImagePartition{
154         .label = "vendor_boot_b",
155         .image_file_path = instance.vendor_boot_image_path(),
156     });
157   } else {
158     partitions.push_back(ImagePartition{
159         .label = "vendor_boot_a",
160         .image_file_path = FLAGS_vendor_boot_image,
161     });
162     partitions.push_back(ImagePartition{
163         .label = "vendor_boot_b",
164         .image_file_path = FLAGS_vendor_boot_image,
165     });
166   }
167   partitions.push_back(ImagePartition {
168     .label = "vbmeta_a",
169     .image_file_path = FLAGS_vbmeta_image,
170   });
171   partitions.push_back(ImagePartition {
172     .label = "vbmeta_b",
173     .image_file_path = FLAGS_vbmeta_image,
174   });
175   partitions.push_back(ImagePartition {
176     .label = "vbmeta_system_a",
177     .image_file_path = FLAGS_vbmeta_system_image,
178   });
179   partitions.push_back(ImagePartition {
180     .label = "vbmeta_system_b",
181     .image_file_path = FLAGS_vbmeta_system_image,
182   });
183   partitions.push_back(ImagePartition {
184     .label = "super",
185     .image_file_path = FLAGS_super_image,
186   });
187   partitions.push_back(ImagePartition {
188     .label = "userdata",
189     .image_file_path = FLAGS_data_image,
190   });
191   partitions.push_back(ImagePartition {
192     .label = "metadata",
193     .image_file_path = FLAGS_metadata_image,
194   });
195   return partitions;
196 }
197 
persistent_composite_disk_config(const CuttlefishConfig::InstanceSpecific & instance)198 std::vector<ImagePartition> persistent_composite_disk_config(
199     const CuttlefishConfig::InstanceSpecific& instance) {
200   std::vector<ImagePartition> partitions;
201 
202   // Note that if the position of uboot_env changes, the environment for
203   // u-boot must be updated as well (see boot_config.cc and
204   // cuttlefish.fragment in external/u-boot).
205   partitions.push_back(ImagePartition{
206       .label = "uboot_env",
207       .image_file_path = instance.uboot_env_image_path(),
208   });
209   if (!FLAGS_protected_vm) {
210     partitions.push_back(ImagePartition{
211         .label = "frp",
212         .image_file_path = instance.factory_reset_protected_path(),
213     });
214   }
215   partitions.push_back(ImagePartition{
216       .label = "bootconfig",
217       .image_file_path = instance.persistent_bootconfig_path(),
218   });
219   return partitions;
220 }
221 
LastUpdatedInputDisk(const std::vector<ImagePartition> & partitions)222 static std::chrono::system_clock::time_point LastUpdatedInputDisk(
223     const std::vector<ImagePartition>& partitions) {
224   std::chrono::system_clock::time_point ret;
225   for (auto& partition : partitions) {
226     if (partition.label == "frp") {
227       continue;
228     }
229 
230     auto partition_mod_time = FileModificationTime(partition.image_file_path);
231     if (partition_mod_time > ret) {
232       ret = partition_mod_time;
233     }
234   }
235   return ret;
236 }
237 
ShouldCreateAllCompositeDisks(const CuttlefishConfig & config)238 bool ShouldCreateAllCompositeDisks(const CuttlefishConfig& config) {
239   std::chrono::system_clock::time_point youngest_disk_img;
240   for (auto& partition :
241        os_composite_disk_config(config.ForDefaultInstance())) {
242     auto partition_mod_time = FileModificationTime(partition.image_file_path);
243     if (partition_mod_time > youngest_disk_img) {
244       youngest_disk_img = partition_mod_time;
245     }
246   }
247 
248   // If the youngest partition img is younger than any composite disk, this fact implies that
249   // the composite disks are all out of date and need to be reinitialized.
250   for (auto& instance : config.Instances()) {
251     if (!FileExists(instance.os_composite_disk_path())) {
252       continue;
253     }
254     if (youngest_disk_img >
255         FileModificationTime(instance.os_composite_disk_path())) {
256       return true;
257     }
258   }
259 
260   return false;
261 }
262 
DoesCompositeMatchCurrentDiskConfig(const std::string & prior_disk_config_path,const std::vector<ImagePartition> & partitions)263 bool DoesCompositeMatchCurrentDiskConfig(
264     const std::string& prior_disk_config_path,
265     const std::vector<ImagePartition>& partitions) {
266   std::string current_disk_config_path = prior_disk_config_path + ".tmp";
267   std::ostringstream disk_conf;
268   for (auto& partition : partitions) {
269     disk_conf << partition.image_file_path << "\n";
270   }
271 
272   {
273     // This file acts as a descriptor of the cuttlefish disk contents in a VMM agnostic way (VMMs
274     // used are QEMU and CrosVM at the time of writing). This file is used to determine if the
275     // disk config for the pending boot matches the disk from the past boot.
276     std::ofstream file_out(current_disk_config_path.c_str(), std::ios::binary);
277     file_out << disk_conf.str();
278     CHECK(file_out.good()) << "Disk config verification failed.";
279   }
280 
281   if (!FileExists(prior_disk_config_path) ||
282       ReadFile(prior_disk_config_path) != ReadFile(current_disk_config_path)) {
283     CHECK(cuttlefish::RenameFile(current_disk_config_path, prior_disk_config_path))
284         << "Unable to delete the old disk config descriptor";
285     LOG(DEBUG) << "Disk Config has changed since last boot. Regenerating composite disk.";
286     return false;
287   } else {
288     RemoveFile(current_disk_config_path);
289     return true;
290   }
291 }
292 
ShouldCreateCompositeDisk(const std::string & composite_disk_path,const std::vector<ImagePartition> & partitions)293 bool ShouldCreateCompositeDisk(const std::string& composite_disk_path,
294                                const std::vector<ImagePartition>& partitions) {
295   if (!FileExists(composite_disk_path)) {
296     return true;
297   }
298 
299   auto composite_age = FileModificationTime(composite_disk_path);
300   return composite_age < LastUpdatedInputDisk(partitions);
301 }
302 
AvailableSpaceAtPath(const std::string & path)303 static uint64_t AvailableSpaceAtPath(const std::string& path) {
304   struct statvfs vfs;
305   if (statvfs(path.c_str(), &vfs) != 0) {
306     int error_num = errno;
307     LOG(ERROR) << "Could not find space available at " << path << ", error was "
308                << strerror(error_num);
309     return 0;
310   }
311   // f_frsize (block size) * f_bavail (free blocks) for unprivileged users.
312   return static_cast<uint64_t>(vfs.f_frsize) * vfs.f_bavail;
313 }
314 
CreateCompositeDisk(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)315 bool CreateCompositeDisk(const CuttlefishConfig& config,
316                          const CuttlefishConfig::InstanceSpecific& instance) {
317   if (!SharedFD::Open(instance.os_composite_disk_path().c_str(),
318                       O_WRONLY | O_CREAT, 0644)
319            ->IsOpen()) {
320     LOG(ERROR) << "Could not ensure " << instance.os_composite_disk_path()
321                << " exists";
322     return false;
323   }
324   if (config.vm_manager() == CrosvmManager::name()) {
325     // Check if filling in the sparse image would run out of disk space.
326     auto existing_sizes = SparseFileSizes(FLAGS_data_image);
327     if (existing_sizes.sparse_size == 0 && existing_sizes.disk_size == 0) {
328       LOG(ERROR) << "Unable to determine size of \"" << FLAGS_data_image
329                  << "\". Does this file exist?";
330     }
331     auto available_space = AvailableSpaceAtPath(FLAGS_data_image);
332     if (available_space < existing_sizes.sparse_size - existing_sizes.disk_size) {
333       // TODO(schuffelen): Duplicate this check in run_cvd when it can run on a separate machine
334       LOG(ERROR) << "Not enough space remaining in fs containing " << FLAGS_data_image;
335       LOG(ERROR) << "Wanted " << (existing_sizes.sparse_size - existing_sizes.disk_size);
336       LOG(ERROR) << "Got " << available_space;
337       return false;
338     } else {
339       LOG(DEBUG) << "Available space: " << available_space;
340       LOG(DEBUG) << "Sparse size of \"" << FLAGS_data_image << "\": "
341                  << existing_sizes.sparse_size;
342       LOG(DEBUG) << "Disk size of \"" << FLAGS_data_image << "\": "
343                  << existing_sizes.disk_size;
344     }
345     std::string header_path =
346         instance.PerInstancePath("os_composite_gpt_header.img");
347     std::string footer_path =
348         instance.PerInstancePath("os_composite_gpt_footer.img");
349     CreateCompositeDisk(os_composite_disk_config(instance), header_path,
350                         footer_path, instance.os_composite_disk_path());
351   } else {
352     // If this doesn't fit into the disk, it will fail while aggregating. The
353     // aggregator doesn't maintain any sparse attributes.
354     AggregateImage(os_composite_disk_config(instance),
355                    instance.os_composite_disk_path());
356   }
357   return true;
358 }
359 
CreatePersistentCompositeDisk(const CuttlefishConfig & config,const CuttlefishConfig::InstanceSpecific & instance)360 bool CreatePersistentCompositeDisk(
361     const CuttlefishConfig& config,
362     const CuttlefishConfig::InstanceSpecific& instance) {
363   if (!SharedFD::Open(instance.persistent_composite_disk_path().c_str(),
364                       O_WRONLY | O_CREAT, 0644)
365            ->IsOpen()) {
366     LOG(ERROR) << "Could not ensure "
367                << instance.persistent_composite_disk_path() << " exists";
368     return false;
369   }
370   if (config.vm_manager() == CrosvmManager::name()) {
371     std::string header_path =
372         instance.PerInstancePath("persistent_composite_gpt_header.img");
373     std::string footer_path =
374         instance.PerInstancePath("persistent_composite_gpt_footer.img");
375     CreateCompositeDisk(persistent_composite_disk_config(instance), header_path,
376                         footer_path, instance.persistent_composite_disk_path());
377   } else {
378     AggregateImage(persistent_composite_disk_config(instance),
379                    instance.persistent_composite_disk_path());
380   }
381   return true;
382 }
383 
RepackAllBootImages(const CuttlefishConfig * config)384 static void RepackAllBootImages(const CuttlefishConfig* config) {
385   CHECK(FileHasContent(FLAGS_boot_image))
386       << "File not found: " << FLAGS_boot_image;
387 
388   CHECK(FileHasContent(FLAGS_vendor_boot_image))
389       << "File not found: " << FLAGS_vendor_boot_image;
390 
391   if (FLAGS_kernel_path.size()) {
392     const std::string new_boot_image_path =
393         config->AssemblyPath("boot_repacked.img");
394     bool success = RepackBootImage(FLAGS_kernel_path, FLAGS_boot_image,
395                                    new_boot_image_path, config->assembly_dir());
396     CHECK(success) << "Failed to regenerate the boot image with the new kernel";
397     SetCommandLineOptionWithMode("boot_image", new_boot_image_path.c_str(),
398                                  google::FlagSettingMode::SET_FLAGS_DEFAULT);
399   }
400 
401   for (auto instance : config->Instances()) {
402     const std::string new_vendor_boot_image_path =
403         instance.vendor_boot_image_path();
404     const std::vector<std::string> boot_config_vector =
405         BootconfigArgsFromConfig(*config, instance);
406     if (FLAGS_kernel_path.size() || FLAGS_initramfs_path.size()) {
407       // Repack the vendor boot images if kernels and/or ramdisks are passed in.
408       if (FLAGS_initramfs_path.size()) {
409         bool success = RepackVendorBootImage(
410             FLAGS_initramfs_path, FLAGS_vendor_boot_image,
411             new_vendor_boot_image_path, config->assembly_dir(),
412             instance.instance_dir(), boot_config_vector,
413             config->bootconfig_supported());
414         CHECK(success) << "Failed to regenerate the vendor boot image with the "
415                           "new ramdisk";
416       } else {
417         // This control flow implies a kernel with all configs built in.
418         // If it's just the kernel, repack the vendor boot image without a
419         // ramdisk.
420         bool success = RepackVendorBootImageWithEmptyRamdisk(
421             FLAGS_vendor_boot_image, new_vendor_boot_image_path,
422             config->assembly_dir(), instance.instance_dir(), boot_config_vector,
423             config->bootconfig_supported());
424         CHECK(success)
425             << "Failed to regenerate the vendor boot image without a ramdisk";
426       }
427     } else {
428       // Repack the vendor boot image to add the instance specific bootconfig
429       // parameters
430       bool success = RepackVendorBootImage(
431           std::string(), FLAGS_vendor_boot_image, new_vendor_boot_image_path,
432           config->assembly_dir(), instance.instance_dir(), boot_config_vector,
433           config->bootconfig_supported());
434       CHECK(success) << "Failed to regenerate the vendor boot image";
435     }
436   }
437 }
438 
CreateDynamicDiskFiles(const FetcherConfig & fetcher_config,const CuttlefishConfig * config)439 void CreateDynamicDiskFiles(const FetcherConfig& fetcher_config,
440                             const CuttlefishConfig* config) {
441   // Create misc if necessary
442   CHECK(InitializeMiscImage(FLAGS_misc_image)) << "Failed to create misc image";
443 
444   // Create data if necessary
445   DataImageResult dataImageResult = ApplyDataImagePolicy(*config, FLAGS_data_image);
446   CHECK(dataImageResult != DataImageResult::Error) << "Failed to set up userdata";
447 
448   if (!FileExists(FLAGS_metadata_image)) {
449     CreateBlankImage(FLAGS_metadata_image, FLAGS_blank_metadata_image_mb, "none");
450   }
451 
452   // If we are booting a protected VM, for now, assume we want a super minimal
453   // environment with no userdata encryption, limited debug, no FRP emulation, a
454   // static env for the bootloader, no SD-Card and no resume-on-reboot HAL
455   // support. We can also assume that image repacking isn't trusted. Repacking
456   // requires resigning the image and keys from an android host aren't trusted.
457   if (!FLAGS_protected_vm) {
458     RepackAllBootImages(config);
459 
460     for (const auto& instance : config->Instances()) {
461       if (!FileExists(instance.access_kregistry_path())) {
462         CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
463       }
464 
465       if (!FileExists(instance.pstore_path())) {
466         CreateBlankImage(instance.pstore_path(), 2 /* mb */, "none");
467       }
468 
469       if (FLAGS_use_sdcard && !FileExists(instance.sdcard_path())) {
470         CreateBlankImage(instance.sdcard_path(),
471                          FLAGS_blank_sdcard_image_mb, "sdcard");
472       }
473 
474       CHECK(InitBootloaderEnvPartition(*config, instance))
475           << "Failed to create bootloader environment partition";
476 
477       const auto frp = instance.factory_reset_protected_path();
478       if (!FileExists(frp)) {
479         CreateBlankImage(frp, 1 /* mb */, "none");
480       }
481 
482       const auto bootconfig_path = instance.persistent_bootconfig_path();
483       if (!FileExists(bootconfig_path)) {
484         CreateBlankImage(bootconfig_path, 1 /* mb */, "none");
485       }
486 
487       auto bootconfig_fd = SharedFD::Open(bootconfig_path, O_RDWR);
488       CHECK(bootconfig_fd->IsOpen())
489           << "Unable to open bootconfig file: " << bootconfig_fd->StrError();
490 
491       const std::string bootconfig =
492           android::base::Join(BootconfigArgsFromConfig(*config, instance),
493                               "\n") +
494           "\n";
495       ssize_t bytesWritten = WriteAll(bootconfig_fd, bootconfig);
496       CHECK(bytesWritten == bootconfig.size());
497       LOG(DEBUG)
498           << "Bootconfig parameters from vendor boot image and config are "
499           << ReadFile(bootconfig_path);
500 
501       const off_t bootconfig_size_bytes =
502           AlignToPowerOf2(bootconfig.size(), PARTITION_SIZE_SHIFT);
503       CHECK(bootconfig_fd->Truncate(bootconfig_size_bytes) == 0)
504           << "`truncate --size=" << bootconfig_size_bytes << " bytes "
505           << bootconfig_path << "` failed:" << bootconfig_fd->StrError();
506     }
507   }
508 
509   for (const auto& instance : config->Instances()) {
510     bool compositeMatchesDiskConfig = DoesCompositeMatchCurrentDiskConfig(
511         instance.PerInstancePath("persistent_composite_disk_config.txt"),
512         persistent_composite_disk_config(instance));
513     bool oldCompositeDisk =
514         ShouldCreateCompositeDisk(instance.persistent_composite_disk_path(),
515                                   persistent_composite_disk_config(instance));
516 
517     if (!compositeMatchesDiskConfig || oldCompositeDisk) {
518       CHECK(CreatePersistentCompositeDisk(*config, instance))
519           << "Failed to create persistent composite disk";
520     }
521   }
522 
523   // libavb expects to be able to read the maximum vbmeta size, so we must
524   // provide a partition which matches this or the read will fail
525   for (const auto& vbmeta_image : { FLAGS_vbmeta_image, FLAGS_vbmeta_system_image }) {
526     if (FileSize(vbmeta_image) != VBMETA_MAX_SIZE) {
527       auto fd = SharedFD::Open(vbmeta_image, O_RDWR);
528       CHECK(fd->Truncate(VBMETA_MAX_SIZE) == 0)
529         << "`truncate --size=" << VBMETA_MAX_SIZE << " " << vbmeta_image << "` "
530         << "failed: " << fd->StrError();
531     }
532   }
533 
534   CHECK(FileHasContent(FLAGS_bootloader))
535       << "File not found: " << FLAGS_bootloader;
536 
537   if (!FLAGS_esp.empty()) {
538     CHECK(FileHasContent(FLAGS_esp))
539         << "File not found: " << FLAGS_esp;
540   }
541 
542   if (SuperImageNeedsRebuilding(fetcher_config, *config)) {
543     bool success = RebuildSuperImage(fetcher_config, *config, FLAGS_super_image);
544     CHECK(success) << "Super image rebuilding requested but could not be completed.";
545   }
546 
547   bool newDataImage = dataImageResult == DataImageResult::FileUpdated;
548 
549   for (auto instance : config->Instances()) {
550     bool compositeMatchesDiskConfig = DoesCompositeMatchCurrentDiskConfig(
551         instance.PerInstancePath("os_composite_disk_config.txt"),
552         os_composite_disk_config(instance));
553     bool oldCompositeDisk = ShouldCreateCompositeDisk(
554         instance.os_composite_disk_path(), os_composite_disk_config(instance));
555     if (!compositeMatchesDiskConfig || oldCompositeDisk || !FLAGS_resume || newDataImage) {
556       if (FLAGS_resume) {
557         LOG(INFO) << "Requested to continue an existing session, (the default) "
558                   << "but the disk files have become out of date. Wiping the "
559                   << "old session files and starting a new session for device "
560                   << instance.serial_number();
561       }
562       CHECK(CreateCompositeDisk(*config, instance))
563           << "Failed to create composite disk";
564       if (FileExists(instance.access_kregistry_path())) {
565         CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
566       }
567       if (FileExists(instance.pstore_path())) {
568         CreateBlankImage(instance.pstore_path(), 2 /* mb */, "none");
569       }
570     }
571   }
572 
573   if (!FLAGS_protected_vm) {
574     for (auto instance : config->Instances()) {
575       auto overlay_path = instance.PerInstancePath("overlay.img");
576       bool missingOverlay = !FileExists(overlay_path);
577       bool newOverlay = FileModificationTime(overlay_path) <
578                         FileModificationTime(instance.os_composite_disk_path());
579       if (missingOverlay || !FLAGS_resume || newOverlay) {
580         CreateQcowOverlay(config->crosvm_binary(),
581                           instance.os_composite_disk_path(), overlay_path);
582       }
583     }
584   }
585 
586   for (auto instance : config->Instances()) {
587     // Check that the files exist
588     for (const auto& file : instance.virtual_disk_paths()) {
589       if (!file.empty()) {
590         CHECK(FileHasContent(file)) << "File not found: " << file;
591       }
592     }
593   }
594 }
595 
596 } // namespace cuttlefish
597