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