From 0e330f12bc7f693933b96ad729d296a92ffd80b7 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 3 Jan 2019 18:16:56 -0800 Subject: [PATCH] init: Add support for GSI installations in first-stage mount. Bug: 121209697 Test: gsi boots Change-Id: I69db0f8e999da366e46728b1008602f543cd79f6 --- fs_mgr/Android.bp | 6 +++- fs_mgr/fs_mgr_fstab.cpp | 51 +++++++++++++++++++++++++++++- fs_mgr/fs_mgr_overlayfs.cpp | 4 ++- fs_mgr/include_fstab/fstab/fstab.h | 3 ++ init/Android.bp | 1 + init/Android.mk | 1 + init/builtins.cpp | 7 +++- init/first_stage_mount.cpp | 48 ++++++++++++++++++++++++++++ 8 files changed, 117 insertions(+), 4 deletions(-) diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index d9f2837aa..974e13e44 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -59,6 +59,7 @@ cc_library { "libfs_avb", "libfstab", "libdm", + "libgsi", ], export_static_lib_headers: [ "libfs_avb", @@ -105,5 +106,8 @@ cc_library_static { }, }, export_include_dirs: ["include_fstab"], - header_libs: ["libbase_headers"], + header_libs: [ + "libbase_headers", + "libgsi_headers", + ], } diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 53b47be6d..257603537 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "fs_mgr_priv.h" @@ -638,6 +639,35 @@ static std::set extract_boot_devices(const Fstab& fstab) { return boot_devices; } +static void EraseFstabEntry(Fstab* fstab, const std::string& mount_point) { + auto iter = std::remove_if(fstab->begin(), fstab->end(), + [&](const auto& entry) { return entry.mount_point == mount_point; }); + fstab->erase(iter, fstab->end()); +} + +static void TransformFstabForGsi(Fstab* fstab) { + EraseFstabEntry(fstab, "/system"); + EraseFstabEntry(fstab, "/data"); + + fstab->emplace_back(BuildGsiSystemFstabEntry()); + + constexpr uint32_t kFlags = MS_NOATIME | MS_NOSUID | MS_NODEV; + + FstabEntry userdata = { + .blk_device = "userdata_gsi", + .mount_point = "/data", + .fs_type = "ext4", + .flags = kFlags, + .reserved_size = 128 * 1024 * 1024, + }; + userdata.fs_mgr_flags.wait = true; + userdata.fs_mgr_flags.check = true; + userdata.fs_mgr_flags.logical = true; + userdata.fs_mgr_flags.quota = true; + userdata.fs_mgr_flags.late_mount = true; + fstab->emplace_back(userdata); +} + bool ReadFstabFromFile(const std::string& path, Fstab* fstab) { auto fstab_file = std::unique_ptr{fopen(path.c_str(), "re"), fclose}; if (!fstab_file) { @@ -645,10 +675,15 @@ bool ReadFstabFromFile(const std::string& path, Fstab* fstab) { return false; } - if (!fs_mgr_read_fstab_file(fstab_file.get(), path == "/proc/mounts", fstab)) { + bool is_proc_mounts = path == "/proc/mounts"; + + if (!fs_mgr_read_fstab_file(fstab_file.get(), is_proc_mounts, fstab)) { LERROR << __FUNCTION__ << "(): failed to load fstab from : '" << path << "'"; return false; } + if (!is_proc_mounts && !access(android::gsi::kGsiBootedIndicatorFile, F_OK)) { + TransformFstabForGsi(fstab); + } return true; } @@ -1023,3 +1058,17 @@ int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab) { int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab) { return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK; } + +FstabEntry BuildGsiSystemFstabEntry() { + FstabEntry system = { + .blk_device = "system_gsi", + .mount_point = "/system", + .fs_type = "ext4", + .flags = MS_RDONLY, + .fs_options = "barrier=1", + }; + system.fs_mgr_flags.wait = true; + system.fs_mgr_flags.logical = true; + system.fs_mgr_flags.first_stage_mount = true; + return system; +} diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 6364ca9af..0f89467e5 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include #include @@ -802,8 +803,9 @@ bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device) bool fs_mgr_overlayfs_invalid() { if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return true; - // in recovery or fastbootd mode, not allowed! + // in recovery, fastbootd, or gsi mode, not allowed! if (fs_mgr_access("/system/bin/recovery")) return true; + if (android::gsi::IsGsiRunning()) return true; return false; } diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 099725463..6643c0d80 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -187,3 +187,6 @@ bool ReadDefaultFstab(Fstab* fstab); FstabEntry FstabRecToFstabEntry(const fstab_rec* fstab_rec); Fstab LegacyFstabToFstab(const struct fstab* legacy_fstab); fstab* FstabToLegacyFstab(const Fstab& fstab); + +// Helper method to build a GSI fstab entry for mounting /system. +FstabEntry BuildGsiSystemFstabEntry(); diff --git a/init/Android.bp b/init/Android.bp index c920dc2a0..3369fb981 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -77,6 +77,7 @@ cc_defaults { "libext4_utils", "libfs_mgr", "libfscrypt", + "libgsi", "libhidl-gen-utils", "libkeyutils", "liblog", diff --git a/init/Android.mk b/init/Android.mk index bdd03018a..69c63e1f3 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -91,6 +91,7 @@ LOCAL_STATIC_LIBRARIES := \ libz \ libselinux \ libcap \ + libgsi \ LOCAL_SANITIZE := signed-integer-overflow # First stage init is weird: it may start without stdout/stderr, and no /proc. diff --git a/init/builtins.cpp b/init/builtins.cpp index 4a66e46f1..0139317d4 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -54,6 +54,7 @@ #include #include #include +#include #include #include #include @@ -520,6 +521,9 @@ static Result queue_fs_event(int code) { return Success(); } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) { /* Setup a wipe via recovery, and reboot into recovery */ + if (android::gsi::IsGsiRunning()) { + return Error() << "cannot wipe within GSI"; + } PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery."; const std::vector options = {"--wipe_data", "--reason=fs_mgr_mount_all" }; return reboot_into_recovery(options); @@ -1022,7 +1026,8 @@ static Result ExecWithRebootOnFailure(const std::string& reboot_reason, } service->AddReapCallback([reboot_reason](const siginfo_t& siginfo) { if (siginfo.si_code != CLD_EXITED || siginfo.si_status != 0) { - if (fscrypt_is_native()) { + // TODO (b/122850122): support this in gsi + if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) { LOG(ERROR) << "Rebooting into recovery, reason: " << reboot_reason; if (auto result = reboot_into_recovery( {"--prompt_and_wipe_data", "--reason="s + reboot_reason}); diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 71fe4010d..affa39e72 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include "devices.h" @@ -79,6 +80,7 @@ class FirstStageMount { bool IsDmLinearEnabled(); bool GetDmLinearMetadataDevice(); bool InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata); + void UseGsiIfPresent(); ListenerAction UeventCallback(const Uevent& uevent); @@ -207,6 +209,8 @@ bool FirstStageMount::GetDmLinearMetadataDevice() { } required_devices_partition_names_.emplace(super_partition_name_); + // When booting from live GSI images, userdata is the super device. + required_devices_partition_names_.emplace("userdata"); return true; } @@ -410,6 +414,16 @@ bool FirstStageMount::MountPartition(FstabEntry* fstab_entry) { // this case, we mount system first then pivot to it. From that point on, // we are effectively identical to a system-as-root device. bool FirstStageMount::TrySwitchSystemAsRoot() { + auto metadata_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) { + return entry.mount_point == "/metadata"; + }); + if (metadata_partition != fstab_.end()) { + if (MountPartition(&(*metadata_partition))) { + fstab_.erase(metadata_partition); + UseGsiIfPresent(); + } + } + auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) { return entry.mount_point == "/system"; }); @@ -513,6 +527,40 @@ bool FirstStageMount::MountPartitions() { return true; } +void FirstStageMount::UseGsiIfPresent() { + std::string metadata_file, error; + + if (!android::gsi::CanBootIntoGsi(&metadata_file, &error)) { + LOG(INFO) << "GSI " << error << ", proceeding with normal boot"; + return; + } + + auto metadata = android::fs_mgr::ReadFromImageFile(metadata_file.c_str()); + if (!metadata) { + LOG(ERROR) << "GSI partition layout could not be read"; + return; + } + + if (!android::fs_mgr::CreateLogicalPartitions(*metadata.get(), "/dev/block/by-name/userdata")) { + LOG(ERROR) << "GSI partition layout could not be instantiated"; + return; + } + + if (!android::gsi::MarkSystemAsGsi()) { + PLOG(ERROR) << "GSI indicator file could not be written"; + return; + } + + // Replace the existing system fstab entry. + auto system_partition = std::find_if(fstab_.begin(), fstab_.end(), [](const auto& entry) { + return entry.mount_point == "/system"; + }); + if (system_partition != fstab_.end()) { + fstab_.erase(system_partition); + } + fstab_.emplace_back(BuildGsiSystemFstabEntry()); +} + bool FirstStageMountVBootV1::GetDmVerityDevices() { std::string verity_loc_device; need_dm_verity_ = false;