Add a sysprop to delay merge by fix duration
Merge is a power consuming process, some products might want to delay
merge after boot by some amount of time. Add a sysprop to configure how
many seconds the merge should be delayed. To prevent the device from
delaying merge indefinitely, this sysprop is capped at 10 minutes.
Bug: 311515963
Test: set ro.virtual_ab.merge_delay_seconds by PRODUCT_PROPERTY_OVERRIDES in mk files and run OTA
Change-Id: I2361dd47221552dbc774c00412c65a22f40bc11d
diff --git a/aosp/cleanup_previous_update_action.cc b/aosp/cleanup_previous_update_action.cc
index fb7bac1..b070ecd 100644
--- a/aosp/cleanup_previous_update_action.cc
+++ b/aosp/cleanup_previous_update_action.cc
@@ -15,6 +15,7 @@
//
#include "update_engine/aosp/cleanup_previous_update_action.h"
+#include <algorithm>
#include <chrono> // NOLINT(build/c++11) -- for merge times
#include <functional>
#include <string>
@@ -38,6 +39,8 @@
using brillo::MessageLoop;
constexpr char kBootCompletedProp[] = "sys.boot_completed";
+constexpr auto&& kMergeDelaySecondsProp = "ro.virtual_ab.merge_delay_seconds";
+constexpr size_t kMaxMergeDelaySeconds = 600;
// Interval to check sys.boot_completed.
constexpr auto kCheckBootCompletedInterval = base::TimeDelta::FromSeconds(2);
// Interval to check IBootControl::isSlotMarkedSuccessful
@@ -108,16 +111,15 @@
// future. This avoids StopActionInternal() from resetting task IDs in an
// unexpected way because task IDs could be reused.
void CleanupPreviousUpdateAction::AcknowledgeTaskExecuted() {
- if (scheduled_task_ != MessageLoop::kTaskIdNull) {
+ if (scheduled_task_.IsScheduled()) {
LOG(INFO) << "Executing task " << scheduled_task_;
}
- scheduled_task_ = MessageLoop::kTaskIdNull;
}
// Check that scheduled_task_ is a valid task ID. Otherwise, terminate the
// action.
void CleanupPreviousUpdateAction::CheckTaskScheduled(std::string_view name) {
- if (scheduled_task_ == MessageLoop::kTaskIdNull) {
+ if (!scheduled_task_.IsScheduled()) {
LOG(ERROR) << "Unable to schedule " << name;
processor_->ActionComplete(this, ErrorCode::kError);
} else {
@@ -130,8 +132,8 @@
LOG(INFO) << "Stopping/suspending/completing CleanupPreviousUpdateAction";
running_ = false;
- if (scheduled_task_ != MessageLoop::kTaskIdNull) {
- if (MessageLoop::current()->CancelTask(scheduled_task_)) {
+ if (scheduled_task_.IsScheduled()) {
+ if (scheduled_task_.Cancel()) {
LOG(INFO) << "CleanupPreviousUpdateAction cancelled pending task ID "
<< scheduled_task_;
} else {
@@ -139,7 +141,6 @@
<< scheduled_task_;
}
}
- scheduled_task_ = MessageLoop::kTaskIdNull;
}
void CleanupPreviousUpdateAction::StartActionInternal() {
@@ -164,12 +165,13 @@
void CleanupPreviousUpdateAction::ScheduleWaitBootCompleted() {
TEST_AND_RETURN(running_);
- scheduled_task_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule,
- base::Unretained(this)),
- kCheckBootCompletedInterval);
- CheckTaskScheduled("WaitBootCompleted");
+ if (!scheduled_task_.PostTask(
+ FROM_HERE,
+ base::Bind(&CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule,
+ base::Unretained(this)),
+ kCheckBootCompletedInterval)) {
+ CheckTaskScheduled("WaitBootCompleted");
+ }
}
void CleanupPreviousUpdateAction::WaitBootCompletedOrSchedule() {
@@ -192,13 +194,33 @@
void CleanupPreviousUpdateAction::ScheduleWaitMarkBootSuccessful() {
TEST_AND_RETURN(running_);
- scheduled_task_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(
- &CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule,
- base::Unretained(this)),
- kCheckSlotMarkedSuccessfulInterval);
- CheckTaskScheduled("WaitMarkBootSuccessful");
+ if (!scheduled_task_.PostTask(
+ FROM_HERE,
+ base::Bind(
+ &CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule,
+ base::Unretained(this)),
+ kCheckSlotMarkedSuccessfulInterval)) {
+ CheckTaskScheduled("WaitMarkBootSuccessful");
+ }
+}
+
+void CleanupPreviousUpdateAction::CheckForMergeDelay() {
+ const auto merge_delay_seconds =
+ std::clamp<int>(android::base::GetIntProperty(kMergeDelaySecondsProp, 0),
+ 0,
+ kMaxMergeDelaySeconds);
+ if (merge_delay_seconds != 0) {
+ LOG(INFO) << "Merge is ready to start, but " << kMergeDelaySecondsProp
+ << " is set, delaying merge by " << merge_delay_seconds
+ << " seconds";
+ }
+ if (!scheduled_task_.PostTask(
+ FROM_HERE,
+ [this]() { StartMerge(); },
+ base::TimeDelta::FromSeconds(merge_delay_seconds))) {
+ LOG(ERROR) << "Unable to schedule " << __FUNCTION__;
+ processor_->ActionComplete(this, ErrorCode::kError);
+ }
}
void CleanupPreviousUpdateAction::CheckSlotMarkedSuccessfulOrSchedule() {
@@ -209,7 +231,10 @@
ScheduleWaitMarkBootSuccessful();
return;
}
+ CheckForMergeDelay();
+}
+void CleanupPreviousUpdateAction::StartMerge() {
if (metadata_device_ == nullptr) {
metadata_device_ = snapshot_->EnsureMetadataMounted();
}
@@ -265,12 +290,13 @@
void CleanupPreviousUpdateAction::ScheduleWaitForMerge() {
TEST_AND_RETURN(running_);
- scheduled_task_ = MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CleanupPreviousUpdateAction::WaitForMergeOrSchedule,
- base::Unretained(this)),
- kWaitForMergeInterval);
- CheckTaskScheduled("WaitForMerge");
+ if (!scheduled_task_.PostTask(
+ FROM_HERE,
+ base::Bind(&CleanupPreviousUpdateAction::WaitForMergeOrSchedule,
+ base::Unretained(this)),
+ kWaitForMergeInterval)) {
+ CheckTaskScheduled("WaitForMerge");
+ }
}
void CleanupPreviousUpdateAction::WaitForMergeOrSchedule() {
diff --git a/aosp/cleanup_previous_update_action.h b/aosp/cleanup_previous_update_action.h
index b93c557..1d701b1 100644
--- a/aosp/cleanup_previous_update_action.h
+++ b/aosp/cleanup_previous_update_action.h
@@ -31,6 +31,7 @@
#include "update_engine/common/cleanup_previous_update_action_delegate.h"
#include "update_engine/common/error_code.h"
#include "update_engine/common/prefs_interface.h"
+#include "update_engine/common/scoped_task_id.h"
namespace chromeos_update_engine {
@@ -76,7 +77,7 @@
bool cancel_failed_{false};
unsigned int last_percentage_{0};
android::snapshot::ISnapshotMergeStats* merge_stats_;
- brillo::MessageLoop::TaskId scheduled_task_{brillo::MessageLoop::kTaskIdNull};
+ ScopedTaskId scheduled_task_;
// Helpers for task management.
void AcknowledgeTaskExecuted();
@@ -88,6 +89,8 @@
void WaitBootCompletedOrSchedule();
void ScheduleWaitMarkBootSuccessful();
void CheckSlotMarkedSuccessfulOrSchedule();
+ void CheckForMergeDelay();
+ void StartMerge();
void ScheduleWaitForMerge();
void WaitForMergeOrSchedule();
void InitiateMergeAndWait();
diff --git a/common/scoped_task_id.h b/common/scoped_task_id.h
index 91a2986..8127d37 100644
--- a/common/scoped_task_id.h
+++ b/common/scoped_task_id.h
@@ -17,6 +17,7 @@
#ifndef UPDATE_ENGINE_SCOPED_TASK_ID_H_
#define UPDATE_ENGINE_SCOPED_TASK_ID_H_
+#include <ostream>
#include <type_traits>
#include <utility>
@@ -35,6 +36,11 @@
ScopedTaskId(const ScopedTaskId&) = delete;
ScopedTaskId& operator=(const ScopedTaskId&) = delete;
+ friend std::ostream& operator<<(std::ostream& out, const ScopedTaskId& task) {
+ out << task.task_id_;
+ return out;
+ }
+
constexpr ScopedTaskId() = default;
constexpr ScopedTaskId(ScopedTaskId&& other) noexcept {
@@ -89,7 +95,6 @@
return task_id_ < other.task_id_;
}
- private:
template <typename Callable>
[[nodiscard]] bool PostTask(const base::Location& from_here,
Callable&& callback,
@@ -107,11 +112,16 @@
delay);
return task_id_ != MessageLoop::kTaskIdNull;
}
+
+ private:
template <typename Callable>
void ExecuteTask(Callable&& callback) {
task_id_ = MessageLoop::kTaskIdNull;
if constexpr (std::is_same_v<Callable&&, base::OnceClosure&&>) {
std::move(callback).Run();
+ } else if constexpr (std::is_same_v<Callable&&,
+ base::RepeatingCallback<void()>&&>) {
+ std::move(callback).Run();
} else {
std::move(callback)();
}