Support per-partition timestamps
update_engine is heading toward supporting partial updates, which an OTA
update can update just a subset of all partitions. In this context, a
single max_timestamp in OTA manifest is insufficient for checking
potential downgrades, as different partitions can have different
timestamps. This CL adds per-partition timestamp support on
update_engine side. update_engine will accept a payload with
per-partition timestamps and reject the update if any partition has an
older timestamp.
Changes made:
1. Add new version field to PartitionUpdate protobuf message.
2. Add new methods to HardwareInterface for fetching/checking
timestamp of each partition.
3. Update delta_performer to invoke new APIs in 2 properly.
4. Add relevant testcases.
Test: unittest
Bug: 162553432
Change-Id: I767343e003fd35ce0d22197b15040488cf30be30
diff --git a/payload_consumer/delta_performer.cc b/payload_consumer/delta_performer.cc
index 19d1297..aa0b4f5 100644
--- a/payload_consumer/delta_performer.cc
+++ b/payload_consumer/delta_performer.cc
@@ -1628,17 +1628,15 @@
LOG(ERROR) << "Manifest contains deprecated fields.";
return ErrorCode::kPayloadMismatchedType;
}
-
- if (manifest_.max_timestamp() < hardware_->GetBuildTimestamp()) {
- LOG(ERROR) << "The current OS build timestamp ("
- << hardware_->GetBuildTimestamp()
- << ") is newer than the maximum timestamp in the manifest ("
- << manifest_.max_timestamp() << ")";
+ TimestampCheckResult result = CheckTimestampError();
+ if (result == TimestampCheckResult::DOWNGRADE) {
if (!hardware_->AllowDowngrade()) {
return ErrorCode::kPayloadTimestampError;
}
LOG(INFO) << "The current OS build allows downgrade, continuing to apply"
" the payload with an older timestamp.";
+ } else if (result == TimestampCheckResult::FAILURE) {
+ return ErrorCode::kPayloadTimestampError;
}
// TODO(crbug.com/37661) we should be adding more and more manifest checks,
@@ -1647,6 +1645,53 @@
return ErrorCode::kSuccess;
}
+TimestampCheckResult DeltaPerformer::CheckTimestampError() const {
+ bool is_partial_update =
+ manifest_.has_partial_update() && manifest_.partial_update();
+ const auto& partitions = manifest_.partitions();
+ auto&& timestamp_valid = [this](const PartitionUpdate& partition) {
+ return hardware_->IsPartitionUpdateValid(partition.partition_name(),
+ partition.version());
+ };
+ if (is_partial_update) {
+ // for partial updates, all partition MUST have valid timestamps
+ // But max_timestamp can be empty
+ for (const auto& partition : partitions) {
+ if (!partition.has_version()) {
+ LOG(ERROR)
+ << "PartitionUpdate " << partition.partition_name()
+ << " does ot have a version field. Not allowed in partial updates.";
+ return TimestampCheckResult::FAILURE;
+ }
+ if (!timestamp_valid(partition)) {
+ // Warning because the system might allow downgrade.
+ LOG(WARNING) << "PartitionUpdate " << partition.partition_name()
+ << " has an older version than partition on device.";
+ return TimestampCheckResult::DOWNGRADE;
+ }
+ }
+
+ return TimestampCheckResult::SUCCESS;
+ }
+ if (manifest_.max_timestamp() < hardware_->GetBuildTimestamp()) {
+ LOG(ERROR) << "The current OS build timestamp ("
+ << hardware_->GetBuildTimestamp()
+ << ") is newer than the maximum timestamp in the manifest ("
+ << manifest_.max_timestamp() << ")";
+ return TimestampCheckResult::DOWNGRADE;
+ }
+ // Otherwise... partitions can have empty timestamps.
+ for (const auto& partition : partitions) {
+ if (partition.has_version() && !timestamp_valid(partition)) {
+ // Warning because the system might allow downgrade.
+ LOG(WARNING) << "PartitionUpdate " << partition.partition_name()
+ << " has an older version than partition on device.";
+ return TimestampCheckResult::DOWNGRADE;
+ }
+ }
+ return TimestampCheckResult::SUCCESS;
+}
+
ErrorCode DeltaPerformer::ValidateOperationHash(
const InstallOperation& operation) {
if (!operation.data_sha256_hash().size()) {