diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp index 8db72679e..8efb72c7e 100644 --- a/init/persistent_properties.cpp +++ b/init/persistent_properties.cpp @@ -46,13 +46,6 @@ namespace { constexpr const char kLegacyPersistentPropertyDir[] = "/data/property"; -void AddPersistentProperty(const std::string& name, const std::string& value, - PersistentProperties* persistent_properties) { - auto persistent_property_record = persistent_properties->add_properties(); - persistent_property_record->set_name(name); - persistent_property_record->set_value(value); -} - Result LoadLegacyPersistentProperties() { std::unique_ptr dir(opendir(kLegacyPersistentPropertyDir), closedir); if (!dir) { @@ -161,9 +154,9 @@ Result ParsePersistentPropertyFile(const std::string& file return Error() << "Unable to parse persistent property file: Could not parse protobuf"; } for (auto& prop : persistent_properties.properties()) { - if (!StartsWith(prop.name(), "persist.")) { + if (!StartsWith(prop.name(), "persist.") && !StartsWith(prop.name(), "next_boot.")) { return Error() << "Unable to load persistent property file: property '" << prop.name() - << "' doesn't start with 'persist.'"; + << "' doesn't start with 'persist.' or 'next_boot.'"; } } return persistent_properties; @@ -171,6 +164,13 @@ Result ParsePersistentPropertyFile(const std::string& file } // namespace +void AddPersistentProperty(const std::string& name, const std::string& value, + PersistentProperties* persistent_properties) { + auto persistent_property_record = persistent_properties->add_properties(); + persistent_property_record->set_name(name); + persistent_property_record->set_value(value); +} + Result LoadPersistentPropertyFile() { auto file_contents = ReadPersistentPropertyFile(); if (!file_contents.ok()) return file_contents.error(); diff --git a/init/persistent_properties.h b/init/persistent_properties.h index 3845a0d86..a6f80e64f 100644 --- a/init/persistent_properties.h +++ b/init/persistent_properties.h @@ -25,6 +25,8 @@ namespace android { namespace init { +void AddPersistentProperty(const std::string& name, const std::string& value, + PersistentProperties* persistent_properties); PersistentProperties LoadPersistentProperties(); void WritePersistentProperty(const std::string& name, const std::string& value); diff --git a/init/property_service.cpp b/init/property_service.cpp index 2064fae8f..bf8680310 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -412,9 +412,8 @@ static std::optional PropertySet(const std::string& name, const std::s } } - // Don't write properties to disk until after we have read all default - // properties to prevent them from being overwritten by default values. - if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { + bool need_persist = StartsWith(name, "persist.") || StartsWith(name, "next_boot."); + if (socket && persistent_properties_loaded && need_persist) { if (persist_write_thread) { persist_write_thread->Write(name, value, std::move(*socket)); return {}; @@ -1398,11 +1397,43 @@ static void HandleInitSocket() { case InitMessage::kLoadPersistentProperties: { load_override_properties(); // Read persistent properties after all default values have been loaded. + // Apply staged and persistent properties + bool has_staged_prop = false; + auto const staged_prefix = std::string_view("next_boot."); + auto const staged_persist_prefix = std::string_view("next_boot.persist."); + auto persist_props_map = std::unordered_map(); + auto persistent_properties = LoadPersistentProperties(); - for (const auto& persistent_property_record : persistent_properties.properties()) { - InitPropertySet(persistent_property_record.name(), - persistent_property_record.value()); + for (const auto& property_record : persistent_properties.properties()) { + auto const& prop_name = property_record.name(); + auto const& prop_value = property_record.value(); + + if (StartsWith(prop_name, staged_prefix)) { + has_staged_prop = true; + auto actual_prop_name = prop_name.substr(staged_prefix.size()); + InitPropertySet(actual_prop_name, prop_value); + if (StartsWith(prop_name, staged_persist_prefix)) { + persist_props_map[actual_prop_name] = prop_value; + } + } else if (!persist_props_map.count(prop_name)) { + InitPropertySet(prop_name, prop_value); + } } + + // Update persist prop file if there are staged props + if (has_staged_prop) { + PersistentProperties updated_persist_props; + for (auto const& [prop_name, prop_value] : persist_props_map) { + AddPersistentProperty(prop_name, prop_value, &updated_persist_props); + } + + // write current updated persist prop file + auto result = WritePersistentPropertyFile(updated_persist_props); + if (!result.ok()) { + LOG(ERROR) << "Could not store persistent property: " << result.error(); + } + } + // Apply debug ramdisk special settings after persistent properties are loaded. if (android::base::GetBoolProperty("ro.force.debuggable", false)) { // Always enable usb adb if device is booted with debug ramdisk.