diff options
31 files changed, 252 insertions, 63 deletions
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 1efe793a5..6952cdf96 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -2203,7 +2203,8 @@ std::string fs_mgr_get_super_partition_name(int slot) { // Devices upgrading to dynamic partitions are allowed to specify a super // partition name. This includes cuttlefish, which is a non-A/B device. std::string super_partition; - if (fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) { + if (fs_mgr_get_boot_config_from_bootconfig_source("super_partition", &super_partition) || + fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) { if (fs_mgr_get_slot_suffix().empty()) { return super_partition; } diff --git a/fs_mgr/fs_mgr_boot_config.cpp b/fs_mgr/fs_mgr_boot_config.cpp index 75d1e0db6..e3ef2321a 100644 --- a/fs_mgr/fs_mgr_boot_config.cpp +++ b/fs_mgr/fs_mgr_boot_config.cpp @@ -91,6 +91,12 @@ bool fs_mgr_get_boot_config_from_bootconfig(const std::string& bootconfig, if (key == bootconfig_key) { *out_val = value; return true; + } else if (android_key == "hardware" && android_key == key) { + // bootconfig doesn't allow subkeys and values to coexist, so + // "androidboot.hardware" cannot be used. It is replaced in + // bootconfig with "hardware" + *out_val = value; + return true; } } diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 785a8e08a..0c0862edb 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -299,7 +299,8 @@ void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { std::string InitAndroidDtDir() { std::string android_dt_dir; // The platform may specify a custom Android DT path in kernel cmdline - if (!fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) { + if (!fs_mgr_get_boot_config_from_bootconfig_source("android_dt_dir", &android_dt_dir) && + !fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) { // Fall back to the standard procfs-based path android_dt_dir = kDefaultAndroidDtDir; } @@ -842,9 +843,22 @@ std::vector<FstabEntry*> GetEntriesForMountPoint(Fstab* fstab, const std::string } std::set<std::string> GetBootDevices() { - // First check the kernel commandline, then try the device tree otherwise + // First check bootconfig, then kernel commandline, then the device tree std::string dt_file_name = get_android_dt_dir() + "/boot_devices"; std::string value; + if (fs_mgr_get_boot_config_from_bootconfig_source("boot_devices", &value) || + fs_mgr_get_boot_config_from_bootconfig_source("boot_device", &value)) { + std::set<std::string> boot_devices; + // remove quotes and split by spaces + auto boot_device_strings = base::Split(base::StringReplace(value, "\"", "", true), " "); + for (std::string_view device : boot_device_strings) { + // trim the trailing comma, keep the rest. + base::ConsumeSuffix(&device, ","); + boot_devices.emplace(device); + } + return boot_devices; + } + if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) || ReadDtFile(dt_file_name, &value)) { auto boot_devices = Split(value, ","); diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp index 623293eb2..6cb2c5172 100644 --- a/fs_mgr/liblp/builder.cpp +++ b/fs_mgr/liblp/builder.cpp @@ -383,11 +383,6 @@ static bool VerifyDeviceProperties(const BlockDeviceInfo& device_info) { << " partition alignment is not sector-aligned."; return false; } - if (device_info.alignment_offset > device_info.alignment) { - LERROR << "Block device " << device_info.partition_name - << " partition alignment offset is greater than its alignment."; - return false; - } return true; } @@ -489,7 +484,7 @@ bool MetadataBuilder::Init(const std::vector<BlockDeviceInfo>& block_devices, // Compute the first free sector, factoring in alignment. uint64_t free_area_start = total_reserved; bool ok; - if (super.alignment || super.alignment_offset) { + if (super.alignment) { ok = AlignTo(free_area_start, super.alignment, &free_area_start); } else { ok = AlignTo(free_area_start, logical_block_size, &free_area_start); diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp index e4b617a51..72827eb6c 100644 --- a/fs_mgr/liblp/builder_test.cpp +++ b/fs_mgr/liblp/builder_test.cpp @@ -176,10 +176,10 @@ TEST_F(BuilderTest, InternalAlignment) { ASSERT_NE(super_device, nullptr); EXPECT_EQ(super_device->first_logical_sector, 1536); - // Alignment offset without alignment doesn't mean anything. + // Alignment offset without alignment is ignored. device_info.alignment = 0; builder = MetadataBuilder::New(device_info, 1024, 2); - ASSERT_EQ(builder, nullptr); + ASSERT_NE(builder, nullptr); // Test a small alignment with an alignment offset. device_info.alignment = 12 * 1024; @@ -444,11 +444,6 @@ TEST_F(BuilderTest, MetadataTooLarge) { device_info.alignment = 131072; builder = MetadataBuilder::New(device_info, kMetadataSize, 1); EXPECT_EQ(builder, nullptr); - - device_info.alignment = 0; - device_info.alignment_offset = 32768 - LP_SECTOR_SIZE; - builder = MetadataBuilder::New(device_info, kMetadataSize, 1); - EXPECT_EQ(builder, nullptr); } TEST_F(BuilderTest, UpdateBlockDeviceInfo) { diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto index b4e92a275..e902fa4dd 100644 --- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto +++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto @@ -46,7 +46,7 @@ enum MergePhase { SECOND_PHASE = 2; } -// Next: 12 +// Next: 13 message SnapshotStatus { // Name of the snapshot. This is usually the name of the snapshotted // logical partition; for example, "system_b". @@ -105,6 +105,9 @@ message SnapshotStatus { // Compression algorithm (none, gz, or brotli). string compression_algorithm = 11; + + // Estimated COW size from OTA manifest. + uint64 estimated_cow_size = 12; } // Next: 8 @@ -159,7 +162,7 @@ message SnapshotUpdateStatus { MergePhase merge_phase = 6; } -// Next: 5 +// Next: 7 message SnapshotMergeReport { // Status of the update after the merge attempts. UpdateState state = 1; @@ -173,4 +176,10 @@ message SnapshotMergeReport { // Whether compression/dm-user was used for any snapshots. bool compression_enabled = 4; + + // Total size used by COWs, including /data and the super partition. + uint64 total_cow_size_bytes = 5; + + // Sum of the estimated COW fields in the OTA manifest. + uint64 estimated_cow_size_bytes = 6; } diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h index 1e420cbbe..1cb966bd4 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h @@ -26,7 +26,8 @@ class MockSnapshotManager : public ISnapshotManager { MOCK_METHOD(bool, BeginUpdate, (), (override)); MOCK_METHOD(bool, CancelUpdate, (), (override)); MOCK_METHOD(bool, FinishedSnapshotWrites, (bool wipe), (override)); - MOCK_METHOD(bool, InitiateMerge, (uint64_t * cow_file_size), (override)); + MOCK_METHOD(void, UpdateCowStats, (ISnapshotMergeStats * stats), (override)); + MOCK_METHOD(bool, InitiateMerge, (), (override)); MOCK_METHOD(UpdateState, ProcessUpdateState, (const std::function<bool()>& callback, const std::function<bool()>& before_cancel), diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index a79a86ddd..7e74facf3 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -127,9 +127,14 @@ class ISnapshotManager { // may need to be merged before wiping. virtual bool FinishedSnapshotWrites(bool wipe) = 0; + // Update an ISnapshotMergeStats object with statistics about COW usage. + // This should be called before the merge begins as otherwise snapshots + // may be deleted. + virtual void UpdateCowStats(ISnapshotMergeStats* stats) = 0; + // Initiate a merge on all snapshot devices. This should only be used after an // update has been marked successful after booting. - virtual bool InitiateMerge(uint64_t* cow_file_size = nullptr) = 0; + virtual bool InitiateMerge() = 0; // Perform any necessary post-boot actions. This should be run soon after // /data is mounted. @@ -326,7 +331,8 @@ class SnapshotManager final : public ISnapshotManager { bool BeginUpdate() override; bool CancelUpdate() override; bool FinishedSnapshotWrites(bool wipe) override; - bool InitiateMerge(uint64_t* cow_file_size = nullptr) override; + void UpdateCowStats(ISnapshotMergeStats* stats) override; + bool InitiateMerge() override; UpdateState ProcessUpdateState(const std::function<bool()>& callback = {}, const std::function<bool()>& before_cancel = {}) override; UpdateState GetUpdateState(double* progress = nullptr) override; @@ -491,7 +497,8 @@ class SnapshotManager final : public ISnapshotManager { bool RemoveAllSnapshots(LockedFile* lock); // List the known snapshot names. - bool ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots); + bool ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots, + const std::string& suffix = ""); // Check for a cancelled or rolled back merge, returning true if such a // condition was detected and handled. @@ -679,6 +686,9 @@ class SnapshotManager final : public ISnapshotManager { friend std::ostream& operator<<(std::ostream& os, SnapshotManager::Slot slot); Slot GetCurrentSlot(); + // Return the suffix we expect snapshots to have. + std::string GetSnapshotSlotSuffix(); + std::string ReadUpdateSourceSlotSuffix(); // Helper for RemoveAllSnapshots. diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h index 96d2deb0c..3eeae64fe 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stats.h @@ -30,7 +30,11 @@ class ISnapshotMergeStats { virtual bool Start() = 0; virtual void set_state(android::snapshot::UpdateState state, bool using_compression) = 0; virtual void set_cow_file_size(uint64_t cow_file_size) = 0; + virtual void set_total_cow_size_bytes(uint64_t bytes) = 0; + virtual void set_estimated_cow_size_bytes(uint64_t bytes) = 0; virtual uint64_t cow_file_size() = 0; + virtual uint64_t total_cow_size_bytes() = 0; + virtual uint64_t estimated_cow_size_bytes() = 0; // Called when merge ends. Properly clean up permanent storage. class Result { @@ -54,6 +58,10 @@ class SnapshotMergeStats : public ISnapshotMergeStats { void set_state(android::snapshot::UpdateState state, bool using_compression) override; void set_cow_file_size(uint64_t cow_file_size) override; uint64_t cow_file_size() override; + void set_total_cow_size_bytes(uint64_t bytes) override; + void set_estimated_cow_size_bytes(uint64_t bytes) override; + uint64_t total_cow_size_bytes() override; + uint64_t estimated_cow_size_bytes() override; std::unique_ptr<Result> Finish() override; private: diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h index 3365ceb73..cc75db840 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h @@ -28,7 +28,8 @@ class SnapshotManagerStub : public ISnapshotManager { bool BeginUpdate() override; bool CancelUpdate() override; bool FinishedSnapshotWrites(bool wipe) override; - bool InitiateMerge(uint64_t* cow_file_size = nullptr) override; + void UpdateCowStats(ISnapshotMergeStats* stats) override; + bool InitiateMerge() override; UpdateState ProcessUpdateState(const std::function<bool()>& callback = {}, const std::function<bool()>& before_cancel = {}) override; UpdateState GetUpdateState(double* progress = nullptr) override; diff --git a/fs_mgr/libsnapshot/partition_cow_creator.cpp b/fs_mgr/libsnapshot/partition_cow_creator.cpp index 6002043ab..5569da038 100644 --- a/fs_mgr/libsnapshot/partition_cow_creator.cpp +++ b/fs_mgr/libsnapshot/partition_cow_creator.cpp @@ -202,6 +202,10 @@ std::optional<PartitionCowCreator::Return> PartitionCowCreator::Run() { ret.snapshot_status.set_device_size(target_partition->size()); ret.snapshot_status.set_snapshot_size(target_partition->size()); + if (update && update->has_estimate_cow_size()) { + ret.snapshot_status.set_estimated_cow_size(update->estimate_cow_size()); + } + if (ret.snapshot_status.snapshot_size() == 0) { LOG(INFO) << "Not creating snapshot for partition " << ret.snapshot_status.name(); ret.snapshot_status.set_cow_partition_size(0); diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index a8a144636..bd1e284da 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -230,6 +230,15 @@ SnapshotManager::Slot SnapshotManager::GetCurrentSlot() { return Slot::Target; } +std::string SnapshotManager::GetSnapshotSlotSuffix() { + switch (GetCurrentSlot()) { + case Slot::Target: + return device_->GetSlotSuffix(); + default: + return device_->GetOtherSlotSuffix(); + } +} + static bool RemoveFileIfExists(const std::string& path) { std::string message; if (!android::base::RemoveFileIfExists(path, &message)) { @@ -624,7 +633,7 @@ bool SnapshotManager::DeleteSnapshot(LockedFile* lock, const std::string& name) return true; } -bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) { +bool SnapshotManager::InitiateMerge() { auto lock = LockExclusive(); if (!lock) return false; @@ -691,7 +700,6 @@ bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) { std::vector<std::string> first_merge_group; - uint64_t total_cow_file_size = 0; DmTargetSnapshot::Status initial_target_values = {}; for (const auto& snapshot : snapshots) { DmTargetSnapshot::Status current_status; @@ -706,7 +714,6 @@ bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) { if (!ReadSnapshotStatus(lock.get(), snapshot, &snapshot_status)) { return false; } - total_cow_file_size += snapshot_status.cow_file_size(); compression_enabled |= snapshot_status.compression_enabled(); if (DecideMergePhase(snapshot_status) == MergePhase::FIRST_PHASE) { @@ -714,10 +721,6 @@ bool SnapshotManager::InitiateMerge(uint64_t* cow_file_size) { } } - if (cow_file_size) { - *cow_file_size = total_cow_file_size; - } - SnapshotUpdateStatus initial_status; initial_status.set_state(UpdateState::Merging); initial_status.set_sectors_allocated(initial_target_values.sectors_allocated); @@ -1732,7 +1735,8 @@ bool SnapshotManager::UpdateUsesCompression(LockedFile* lock) { return update_status.compression_enabled(); } -bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots) { +bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* snapshots, + const std::string& suffix) { CHECK(lock); auto dir_path = metadata_dir_ + "/snapshots"s; @@ -1745,7 +1749,12 @@ bool SnapshotManager::ListSnapshots(LockedFile* lock, std::vector<std::string>* struct dirent* dp; while ((dp = readdir(dir.get())) != nullptr) { if (dp->d_type != DT_REG) continue; - snapshots->emplace_back(dp->d_name); + + std::string name(dp->d_name); + if (!suffix.empty() && !android::base::EndsWith(name, suffix)) { + continue; + } + snapshots->emplace_back(std::move(name)); } return true; } @@ -3565,5 +3574,34 @@ MergePhase SnapshotManager::DecideMergePhase(const SnapshotStatus& status) { return MergePhase::SECOND_PHASE; } +void SnapshotManager::UpdateCowStats(ISnapshotMergeStats* stats) { + auto lock = LockExclusive(); + if (!lock) return; + + std::vector<std::string> snapshots; + if (!ListSnapshots(lock.get(), &snapshots, GetSnapshotSlotSuffix())) { + LOG(ERROR) << "Could not list snapshots"; + return; + } + + uint64_t cow_file_size = 0; + uint64_t total_cow_size = 0; + uint64_t estimated_cow_size = 0; + for (const auto& snapshot : snapshots) { + SnapshotStatus status; + if (!ReadSnapshotStatus(lock.get(), snapshot, &status)) { + return; + } + + cow_file_size += status.cow_file_size(); + total_cow_size += status.cow_file_size() + status.cow_partition_size(); + estimated_cow_size += status.estimated_cow_size(); + } + + stats->set_cow_file_size(cow_file_size); + stats->set_total_cow_size_bytes(total_cow_size); + stats->set_estimated_cow_size_bytes(estimated_cow_size); +} + } // namespace snapshot } // namespace android diff --git a/fs_mgr/libsnapshot/snapshot_stats.cpp b/fs_mgr/libsnapshot/snapshot_stats.cpp index 513700ddc..35e2d92de 100644 --- a/fs_mgr/libsnapshot/snapshot_stats.cpp +++ b/fs_mgr/libsnapshot/snapshot_stats.cpp @@ -98,6 +98,22 @@ uint64_t SnapshotMergeStats::cow_file_size() { return report_.cow_file_size(); } +void SnapshotMergeStats::set_total_cow_size_bytes(uint64_t bytes) { + report_.set_total_cow_size_bytes(bytes); +} + +void SnapshotMergeStats::set_estimated_cow_size_bytes(uint64_t bytes) { + report_.set_estimated_cow_size_bytes(bytes); +} + +uint64_t SnapshotMergeStats::total_cow_size_bytes() { + return report_.total_cow_size_bytes(); +} + +uint64_t SnapshotMergeStats::estimated_cow_size_bytes() { + return report_.estimated_cow_size_bytes(); +} + class SnapshotMergeStatsResultImpl : public SnapshotMergeStats::Result { public: SnapshotMergeStatsResultImpl(const SnapshotMergeReport& report, diff --git a/fs_mgr/libsnapshot/snapshot_stub.cpp b/fs_mgr/libsnapshot/snapshot_stub.cpp index 8a254c99e..079e606c4 100644 --- a/fs_mgr/libsnapshot/snapshot_stub.cpp +++ b/fs_mgr/libsnapshot/snapshot_stub.cpp @@ -43,7 +43,7 @@ bool SnapshotManagerStub::FinishedSnapshotWrites(bool) { return false; } -bool SnapshotManagerStub::InitiateMerge(uint64_t*) { +bool SnapshotManagerStub::InitiateMerge() { LOG(ERROR) << __FUNCTION__ << " should never be called."; return false; } @@ -127,6 +127,10 @@ class SnapshotMergeStatsStub : public ISnapshotMergeStats { void set_cow_file_size(uint64_t) override {} uint64_t cow_file_size() override { return 0; } std::unique_ptr<Result> Finish() override { return nullptr; } + void set_total_cow_size_bytes(uint64_t) override {} + void set_estimated_cow_size_bytes(uint64_t) override {} + uint64_t total_cow_size_bytes() override { return 0; } + uint64_t estimated_cow_size_bytes() override { return 0; } }; ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() { @@ -151,4 +155,8 @@ bool SnapshotManagerStub::UnmapAllSnapshots() { return false; } +void SnapshotManagerStub::UpdateCowStats(ISnapshotMergeStats*) { + LOG(ERROR) << __FUNCTION__ << " should never be called."; +} + } // namespace android::snapshot diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 62a8d3b8f..5887641e3 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -121,12 +121,13 @@ const std::vector<std::pair<std::string, std::string>> result_space = { const std::string bootconfig = "androidboot.bootdevice = \" \"1d84000.ufshc\"\n" + "androidboot.boot_devices = \"dev1\", \"dev2,withcomma\", \"dev3\"\n" "androidboot.baseband = \"sdy\"\n" "androidboot.keymaster = \"1\"\n" "androidboot.serialno = \"BLAHBLAHBLAH\"\n" "androidboot.slot_suffix = \"_a\"\n" "androidboot.hardware.platform = \"sdw813\"\n" - "androidboot.hardware = \"foo\"\n" + "hardware = \"foo\"\n" "androidboot.revision = \"EVT1.0\"\n" "androidboot.bootloader = \"burp-0.1-7521\"\n" "androidboot.hardware.sku = \"mary\"\n" @@ -152,12 +153,13 @@ const std::string bootconfig = const std::vector<std::pair<std::string, std::string>> bootconfig_result_space = { {"androidboot.bootdevice", "1d84000.ufshc"}, + {"androidboot.boot_devices", "dev1, dev2,withcomma, dev3"}, {"androidboot.baseband", "sdy"}, {"androidboot.keymaster", "1"}, {"androidboot.serialno", "BLAHBLAHBLAH"}, {"androidboot.slot_suffix", "_a"}, {"androidboot.hardware.platform", "sdw813"}, - {"androidboot.hardware", "foo"}, + {"hardware", "foo"}, {"androidboot.revision", "EVT1.0"}, {"androidboot.bootloader", "burp-0.1-7521"}, {"androidboot.hardware.sku", "mary"}, diff --git a/init/Android.bp b/init/Android.bp index 3ff17672c..1381c1d25 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -143,6 +143,7 @@ cc_defaults { "libcgrouprc_format", "liblmkd_utils", "libmodprobe", + "libprocinfo", "libprotobuf-cpp-lite", "libpropertyinfoserializer", "libpropertyinfoparser", @@ -308,6 +309,7 @@ cc_binary { "libsnapshot_cow", "libsnapshot_init", "update_metadata-protos", + "libprocinfo", ], static_executable: true, diff --git a/init/Android.mk b/init/Android.mk index 65ee385de..3c7d95acf 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -130,6 +130,7 @@ LOCAL_STATIC_LIBRARIES := \ libsnapshot_cow \ libsnapshot_init \ update_metadata-protos \ + libprocinfo \ 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 dcc9582e2..035038f32 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1278,6 +1278,14 @@ static Result<void> GenerateLinkerConfiguration() { return ErrnoError() << "failed to execute linkerconfig"; } + auto current_mount_ns = GetCurrentMountNamespace(); + if (!current_mount_ns.ok()) { + return current_mount_ns.error(); + } + if (*current_mount_ns == NS_DEFAULT) { + SetDefaultMountNamespaceReady(); + } + LOG(INFO) << "linkerconfig generated " << linkerconfig_target << " with mounted APEX modules info"; diff --git a/init/first_stage_console.cpp b/init/first_stage_console.cpp index 0f0116659..e2ea0ab40 100644 --- a/init/first_stage_console.cpp +++ b/init/first_stage_console.cpp @@ -105,8 +105,20 @@ void StartConsole(const std::string& cmdline) { _exit(127); } -int FirstStageConsole(const std::string& cmdline) { - auto pos = cmdline.find("androidboot.first_stage_console="); +int FirstStageConsole(const std::string& cmdline, const std::string& bootconfig) { + auto pos = bootconfig.find("androidboot.first_stage_console ="); + if (pos != std::string::npos) { + int val = 0; + if (sscanf(bootconfig.c_str() + pos, "androidboot.first_stage_console = \"%d\"", &val) != + 1) { + return FirstStageConsoleParam::DISABLED; + } + if (val <= FirstStageConsoleParam::MAX_PARAM_VALUE && val >= 0) { + return val; + } + } + + pos = cmdline.find("androidboot.first_stage_console="); if (pos != std::string::npos) { int val = 0; if (sscanf(cmdline.c_str() + pos, "androidboot.first_stage_console=%d", &val) != 1) { diff --git a/init/first_stage_console.h b/init/first_stage_console.h index d5744df49..4a30d35ed 100644 --- a/init/first_stage_console.h +++ b/init/first_stage_console.h @@ -29,7 +29,7 @@ enum FirstStageConsoleParam { }; void StartConsole(const std::string& cmdline); -int FirstStageConsole(const std::string& cmdline); +int FirstStageConsole(const std::string& cmdline, const std::string& bootconfig); } // namespace init } // namespace android diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index ff75aa3c8..b2ab55082 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -102,8 +102,9 @@ void FreeRamdisk(DIR* dir, dev_t dev) { } } -bool ForceNormalBoot(const std::string& cmdline) { - return cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; +bool ForceNormalBoot(const std::string& cmdline, const std::string& bootconfig) { + return bootconfig.find("androidboot.force_normal_boot = \"1\"") != std::string::npos || + cmdline.find("androidboot.force_normal_boot=1") != std::string::npos; } } // namespace @@ -211,6 +212,8 @@ int FirstStageMain(int argc, char** argv) { android::base::ReadFileToString("/proc/cmdline", &cmdline); // Don't expose the raw bootconfig to unprivileged processes. chmod("/proc/bootconfig", 0440); + std::string bootconfig; + android::base::ReadFileToString("/proc/bootconfig", &bootconfig); gid_t groups[] = {AID_READPROC}; CHECKCALL(setgroups(arraysize(groups), groups)); CHECKCALL(mount("sysfs", "/sys", "sysfs", 0, NULL)); @@ -278,11 +281,11 @@ int FirstStageMain(int argc, char** argv) { old_root_dir.reset(); } - auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline) : 0; + auto want_console = ALLOW_FIRST_STAGE_CONSOLE ? FirstStageConsole(cmdline, bootconfig) : 0; boot_clock::time_point module_start_time = boot_clock::now(); int module_count = 0; - if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline), want_console, + if (!LoadKernelModules(IsRecoveryMode() && !ForceNormalBoot(cmdline, bootconfig), want_console, module_count)) { if (want_console != FirstStageConsoleParam::DISABLED) { LOG(ERROR) << "Failed to load kernel modules, starting console"; @@ -324,7 +327,7 @@ int FirstStageMain(int argc, char** argv) { LOG(INFO) << "Copied ramdisk prop to " << dest; } - if (ForceNormalBoot(cmdline)) { + if (ForceNormalBoot(cmdline, bootconfig)) { mkdir("/first_stage_ramdisk", 0755); // SwitchRoot() must be called with a mount point as the target, so we bind mount the // target directory to itself here. diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index ec48cde02..15252a622 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -301,5 +301,20 @@ Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespac return {}; } +base::Result<MountNamespace> GetCurrentMountNamespace() { + std::string current_namespace_id = GetMountNamespaceId(); + if (current_namespace_id == "") { + return Error() << "Failed to get current mount namespace ID"; + } + + if (current_namespace_id == bootstrap_ns_id) { + return NS_BOOTSTRAP; + } else if (current_namespace_id == default_ns_id) { + return NS_DEFAULT; + } + + return Error() << "Failed to find current mount namespace"; +} + } // namespace init } // namespace android diff --git a/init/mount_namespace.h b/init/mount_namespace.h index d4d6f82da..5e3dab241 100644 --- a/init/mount_namespace.h +++ b/init/mount_namespace.h @@ -26,5 +26,7 @@ enum MountNamespace { NS_BOOTSTRAP, NS_DEFAULT }; bool SetupMountNamespaces(); base::Result<void> SwitchToMountNamespaceIfNeeded(MountNamespace target_mount_namespace); +base::Result<MountNamespace> GetCurrentMountNamespace(); + } // namespace init } // namespace android diff --git a/init/property_service.cpp b/init/property_service.cpp index b7227020d..404a99c4c 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -1184,6 +1184,10 @@ static void ProcessBootconfig() { ImportBootconfig([&](const std::string& key, const std::string& value) { if (StartsWith(key, "androidboot.")) { InitPropertySet("ro.boot." + key.substr(12), value); + } else if (key == "hardware") { + // "hardware" in bootconfig replaces "androidboot.hardware" kernel + // cmdline parameter + InitPropertySet("ro.boot." + key, value); } }); } diff --git a/init/service.cpp b/init/service.cpp index cfb82842d..836dc4722 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -125,11 +125,6 @@ static bool ExpandArgsAndExecv(const std::vector<std::string>& args, bool sigsto return execv(c_strings[0], c_strings.data()) == 0; } -static bool AreRuntimeApexesReady() { - struct stat buf; - return stat("/apex/com.android.runtime/", &buf) == 0; -} - unsigned long Service::next_start_order_ = 1; bool Service::is_exec_service_running_ = false; @@ -312,7 +307,7 @@ void Service::Reap(const siginfo_t& siginfo) { #else static bool is_apex_updatable = false; #endif - const bool is_process_updatable = !pre_apexd_ && is_apex_updatable; + const bool is_process_updatable = !use_bootstrap_ns_ && is_apex_updatable; // If we crash > 4 times in 'fatal_crash_window_' minutes or before boot_completed, // reboot into bootloader or set crashing property @@ -465,12 +460,12 @@ Result<void> Service::Start() { scon = *result; } - if (!AreRuntimeApexesReady() && !pre_apexd_) { - // If this service is started before the Runtime and ART APEXes get - // available, mark it as pre-apexd one. Note that this marking is + if (!IsDefaultMountNamespaceReady() && name_ != "apexd") { + // If this service is started before APEXes and corresponding linker configuration + // get available, mark it as pre-apexd one. Note that this marking is // permanent. So for example, if the service is re-launched (e.g., due // to crash), it is still recognized as pre-apexd... for consistency. - pre_apexd_ = true; + use_bootstrap_ns_ = true; } // For pre-apexd services, override mount namespace as "bootstrap" one before starting. @@ -479,7 +474,7 @@ Result<void> Service::Start() { std::optional<MountNamespace> override_mount_namespace; if (name_ == "ueventd") { override_mount_namespace = NS_DEFAULT; - } else if (pre_apexd_) { + } else if (use_bootstrap_ns_) { override_mount_namespace = NS_BOOTSTRAP; } diff --git a/init/service.h b/init/service.h index aee1e5dfa..043555fa4 100644 --- a/init/service.h +++ b/init/service.h @@ -207,7 +207,7 @@ class Service { std::vector<std::function<void(const siginfo_t& siginfo)>> reap_callbacks_; - bool pre_apexd_ = false; + bool use_bootstrap_ns_ = false; bool post_data_ = false; diff --git a/init/snapuserd_transition.cpp b/init/snapuserd_transition.cpp index 19b5c57a0..40467b7d3 100644 --- a/init/snapuserd_transition.cpp +++ b/init/snapuserd_transition.cpp @@ -24,6 +24,7 @@ #include <filesystem> #include <string> +#include <string_view> #include <android-base/file.h> #include <android-base/logging.h> @@ -34,6 +35,7 @@ #include <libsnapshot/snapshot.h> #include <libsnapshot/snapuserd_client.h> #include <private/android_filesystem_config.h> +#include <procinfo/process_map.h> #include <selinux/android.h> #include "block_dev_initializer.h" @@ -157,6 +159,33 @@ SnapuserdSelinuxHelper::SnapuserdSelinuxHelper(std::unique_ptr<SnapshotManager>& }); } +static void LockAllSystemPages() { + bool ok = true; + auto callback = [&](const android::procinfo::MapInfo& map) -> void { + if (!ok || android::base::StartsWith(map.name, "/dev/") || + !android::base::StartsWith(map.name, "/")) { + return; + } + auto start = reinterpret_cast<const void*>(map.start); + auto len = map.end - map.start; + if (!len) { + return; + } + if (mlock(start, len) < 0) { + LOG(ERROR) << "mlock failed, " << start << " for " << len << " bytes."; + ok = false; + } + }; + + if (!android::procinfo::ReadProcessMaps(getpid(), callback) || !ok) { + LOG(FATAL) << "Could not process /proc/" << getpid() << "/maps file for init, " + << "falling back to mlockall()."; + if (mlockall(MCL_CURRENT) < 0) { + LOG(FATAL) << "mlockall failed"; + } + } +} + void SnapuserdSelinuxHelper::StartTransition() { LOG(INFO) << "Starting SELinux transition of snapuserd"; @@ -170,9 +199,7 @@ void SnapuserdSelinuxHelper::StartTransition() { // We cannot access /system after the transition, so make sure init is // pinned in memory. - if (mlockall(MCL_CURRENT) < 0) { - LOG(FATAL) << "mlockall failed"; - } + LockAllSystemPages(); argv_.emplace_back("snapuserd"); argv_.emplace_back("-no_socket"); diff --git a/init/util.cpp b/init/util.cpp index e69b43f8c..eab99d4e3 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -735,5 +735,16 @@ bool IsRecoveryMode() { return access("/system/bin/recovery", F_OK) == 0; } +// Check if default mount namespace is ready to be used with APEX modules +static bool is_default_mount_namespace_ready = false; + +bool IsDefaultMountNamespaceReady() { + return is_default_mount_namespace_ready; +} + +void SetDefaultMountNamespaceReady() { + is_default_mount_namespace_ready = true; +} + } // namespace init } // namespace android diff --git a/init/util.h b/init/util.h index 7745d775a..daba85247 100644 --- a/init/util.h +++ b/init/util.h @@ -100,5 +100,8 @@ Result<std::string> ParseUmountAll(const std::vector<std::string>& args); void SetStdioToDevNull(char** argv); void InitKernelLogging(char** argv); bool IsRecoveryMode(); + +bool IsDefaultMountNamespaceReady(); +void SetDefaultMountNamespaceReady(); } // namespace init } // namespace android diff --git a/libcutils/Android.bp b/libcutils/Android.bp index b38818a4b..0d9f2c79a 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -170,14 +170,10 @@ cc_library { linux_bionic: { enabled: true, }, - linux: { - srcs: [ - "fs_config.cpp", - ], - }, not_windows: { srcs: libcutils_nonwindows_sources + [ "ashmem-host.cpp", + "fs_config.cpp", "trace-host.cpp", ], }, @@ -197,6 +193,7 @@ cc_library { srcs: libcutils_nonwindows_sources + [ "android_reboot.cpp", "ashmem-dev.cpp", + "fs_config.cpp", "klog.cpp", "partition_utils.cpp", "qtaguid.cpp", diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 54eeeace7..d69c038bc 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -35,6 +35,7 @@ #include <string> #include <android-base/strings.h> +#include <cutils/fs.h> #include <log/log.h> #include <private/android_filesystem_config.h> |