apply staged property value when loading persistent props

Bug: b/300111812
Change-Id: I81b6bd984aad8f7ddec93ce74f4543e4f71be508
Ignore-AOSP-First: see cherry pick to aosp/2781147
diff --git a/init/persistent_properties.cpp b/init/persistent_properties.cpp
index 8db7267..8efb72c 100644
--- a/init/persistent_properties.cpp
+++ b/init/persistent_properties.cpp
@@ -46,13 +46,6 @@
 
 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<PersistentProperties> LoadLegacyPersistentProperties() {
     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(kLegacyPersistentPropertyDir), closedir);
     if (!dir) {
@@ -161,9 +154,9 @@
         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 @@
 
 }  // 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<PersistentProperties> 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 3845a0d..a6f80e6 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 a1b0b8e..ec18694 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -420,7 +420,8 @@
 
         // 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 {};
@@ -1405,11 +1406,43 @@
         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<std::string, std::string>();
+
             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.