init: Add support for GSI installations in first-stage mount.

Bug: 121209697
Test: gsi boots
Change-Id: I69db0f8e999da366e46728b1008602f543cd79f6
This commit is contained in:
David Anderson 2019-01-03 18:16:56 -08:00
parent a0ca0191d6
commit 0e330f12bc
8 changed files with 117 additions and 4 deletions

View file

@ -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",
],
}

View file

@ -30,6 +30,7 @@
#include <android-base/file.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <libgsi/libgsi.h>
#include "fs_mgr_priv.h"
@ -638,6 +639,35 @@ static std::set<std::string> 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<FILE, decltype(&fclose)>{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;
}

View file

@ -48,6 +48,7 @@
#include <fs_mgr_overlayfs.h>
#include <fstab/fstab.h>
#include <libdm/dm.h>
#include <libgsi/libgsi.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
@ -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;
}

View file

@ -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();

View file

@ -77,6 +77,7 @@ cc_defaults {
"libext4_utils",
"libfs_mgr",
"libfscrypt",
"libgsi",
"libhidl-gen-utils",
"libkeyutils",
"liblog",

View file

@ -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.

View file

@ -54,6 +54,7 @@
#include <fs_mgr.h>
#include <fscrypt/fscrypt.h>
#include <fscrypt/fscrypt_init_extensions.h>
#include <libgsi/libgsi.h>
#include <selinux/android.h>
#include <selinux/label.h>
#include <selinux/selinux.h>
@ -520,6 +521,9 @@ static Result<Success> 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<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" };
return reboot_into_recovery(options);
@ -1022,7 +1026,8 @@ static Result<Success> 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});

View file

@ -34,6 +34,7 @@
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
#include <fs_mgr_overlayfs.h>
#include <libgsi/libgsi.h>
#include <liblp/liblp.h>
#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;