Schedule a warm_reset after an OTA

The property is set to inform kernel to do a warm_reset on the next
reboot. This is useful to persist the logs to debug device boot
failures. More details in http://go/rvc-ota-persist-logs.

Bug: 143489994
Test: check the property sets after an update
Change-Id: I776a6996e3b3ef77514da0acc91585d28e5cdf15
diff --git a/common/fake_hardware.h b/common/fake_hardware.h
index 8da5326..0b232da 100644
--- a/common/fake_hardware.h
+++ b/common/fake_hardware.h
@@ -191,6 +191,8 @@
     build_timestamp_ = build_timestamp;
   }
 
+  void SetWarmReset(bool warm_reset) { warm_reset_ = warm_reset; }
+
   // Getters to verify state.
   int GetMaxKernelKeyRollforward() const { return kernel_max_rollforward_; }
 
@@ -218,6 +220,7 @@
   bool is_rollback_powerwash_{false};
   int64_t build_timestamp_{0};
   bool first_active_omaha_ping_sent_{false};
+  bool warm_reset_{false};
 
   DISALLOW_COPY_AND_ASSIGN(FakeHardware);
 };
diff --git a/common/hardware_interface.h b/common/hardware_interface.h
index 4a64c3e..d92a6fc 100644
--- a/common/hardware_interface.h
+++ b/common/hardware_interface.h
@@ -134,6 +134,10 @@
   // Persist the fact that first active ping was sent to omaha and returns false
   // if failed to persist it.
   virtual bool SetFirstActiveOmahaPingSent() = 0;
+
+  // If |warm_reset| is true, sets the warm reset to indicate a warm reset is
+  // needed on the next reboot. Otherwise, clears the flag.
+  virtual void SetWarmReset(bool warm_reset) = 0;
 };
 
 }  // namespace chromeos_update_engine
diff --git a/hardware_android.cc b/hardware_android.cc
index 9611ba6..068468b 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -210,4 +210,11 @@
   return true;
 }
 
+void HardwareAndroid::SetWarmReset(bool warm_reset) {
+  constexpr char warm_reset_prop[] = "ota.warm_reset";
+  if (!android::base::SetProperty(warm_reset_prop, warm_reset ? "1" : "0")) {
+    LOG(WARNING) << "Failed to set prop " << warm_reset_prop;
+  }
+}
+
 }  // namespace chromeos_update_engine
diff --git a/hardware_android.h b/hardware_android.h
index 2a8f669..145a936 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -56,6 +56,7 @@
   bool AllowDowngrade() const override;
   bool GetFirstActiveOmahaPingSent() const override;
   bool SetFirstActiveOmahaPingSent() override;
+  void SetWarmReset(bool warm_reset) override;
 
  private:
   DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
diff --git a/hardware_chromeos.cc b/hardware_chromeos.cc
index 8ef05b2..a49375e 100644
--- a/hardware_chromeos.cc
+++ b/hardware_chromeos.cc
@@ -333,4 +333,6 @@
   return true;
 }
 
+void HardwareChromeOS::SetWarmReset(bool warm_reset) {}
+
 }  // namespace chromeos_update_engine
diff --git a/hardware_chromeos.h b/hardware_chromeos.h
index 57be3b0..2bea989 100644
--- a/hardware_chromeos.h
+++ b/hardware_chromeos.h
@@ -61,6 +61,7 @@
   bool AllowDowngrade() const override { return false; }
   bool GetFirstActiveOmahaPingSent() const override;
   bool SetFirstActiveOmahaPingSent() override;
+  void SetWarmReset(bool warm_reset) override;
 
  private:
   friend class HardwareChromeOSTest;
diff --git a/payload_consumer/postinstall_runner_action.cc b/payload_consumer/postinstall_runner_action.cc
index 1367649..c0c3956 100644
--- a/payload_consumer/postinstall_runner_action.cc
+++ b/payload_consumer/postinstall_runner_action.cc
@@ -342,6 +342,9 @@
       if (!boot_control_->GetDynamicPartitionControl()->FinishUpdate() ||
           !boot_control_->SetActiveBootSlot(install_plan_.target_slot)) {
         error_code = ErrorCode::kPostinstallRunnerError;
+      } else {
+        // Schedules warm reset on next reboot, ignores the error.
+        hardware_->SetWarmReset(true);
       }
     } else {
       error_code = ErrorCode::kUpdatedButNotActive;
diff --git a/update_attempter_android.cc b/update_attempter_android.cc
index b76e05b..bc97a11 100644
--- a/update_attempter_android.cc
+++ b/update_attempter_android.cc
@@ -351,6 +351,9 @@
       if (!boot_control_->MarkBootSuccessfulAsync(Bind([](bool successful) {})))
         ret_value = false;
 
+      // Resets the warm reset property since we won't switch the slot.
+      hardware_->SetWarmReset(false);
+
       if (!ret_value) {
         return LogAndSetError(
             error, FROM_HERE, "Failed to reset the status to ");