Only prevent boot image downgrade if sysprop set.
Only return timestamp error if ro.build.ab_update.gki.prevent_downgrade_version is set.
Otherwise, log warning message and continue the update.
This allows devices that does not support GKI updates to install OTA packages where
the boot image has a lower version than the existing, which is supported before.
Bug: 162623577
Test: apply OTA on devices with and without sysprop set
Change-Id: Ie98fb49ffaae1aa60fc94766f53a6fbbae519a5b
diff --git a/Android.bp b/Android.bp
index 6585ea2..193928b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -260,6 +260,7 @@
],
static_libs: [
+ "gkiprops",
"libkver",
"libpayload_consumer",
"libupdate_engine_boot_control",
@@ -383,6 +384,7 @@
// We add the static versions of the shared libraries that are not installed to
// recovery image due to size concerns. Need to include all the static library
// dependencies of these static libraries.
+ "gkiprops",
"libevent",
"libmodpb64",
"libgtest_prod",
diff --git a/hardware_android.cc b/hardware_android.cc
index 4894522..fc6e1dc 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -23,6 +23,7 @@
#include <string>
#include <string_view>
+#include <android/sysprop/GkiProperties.sysprop.h>
#include <android-base/parseint.h>
#include <android-base/properties.h>
#include <base/files/file_util.h>
@@ -261,7 +262,10 @@
PLOG(ERROR) << "Unable to call uname()";
return ErrorCode::kError;
}
- return IsKernelUpdateValid(buf.release, new_version);
+ bool prevent_downgrade =
+ android::sysprop::GkiProperties::prevent_downgrade_version().value_or(
+ false);
+ return IsKernelUpdateValid(buf.release, new_version, prevent_downgrade);
}
const auto old_version = GetPartitionBuildDate(partition_name);
@@ -278,7 +282,8 @@
}
ErrorCode HardwareAndroid::IsKernelUpdateValid(const string& old_release,
- const string& new_release) {
+ const string& new_release,
+ bool prevent_downgrade) {
// Check that the package either contain an empty version (indicating that the
// new build does not use GKI), or a valid GKI kernel release.
std::optional<KernelRelease> new_kernel_release;
@@ -296,10 +301,17 @@
auto old_kernel_release =
KernelRelease::Parse(old_release, true /* allow_suffix */);
- return android::kver::IsKernelUpdateValid(old_kernel_release,
- new_kernel_release)
- ? ErrorCode::kSuccess
- : ErrorCode::kPayloadTimestampError;
+ bool is_update_valid = android::kver::IsKernelUpdateValid(old_kernel_release,
+ new_kernel_release);
+
+ if (!is_update_valid) {
+ if (prevent_downgrade) {
+ return ErrorCode::kPayloadTimestampError;
+ }
+ LOG(WARNING) << "Boot version downgrade detected, allowing update because "
+ << "prevent_downgrade_version sysprop is not set.";
+ }
+ return ErrorCode::kSuccess;
}
} // namespace chromeos_update_engine
diff --git a/hardware_android.h b/hardware_android.h
index b670447..552cb53 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -70,9 +70,15 @@
private:
FRIEND_TEST(HardwareAndroidTest, IsKernelUpdateValid);
- // Helper for IsPartitionUpdateValid.
+ // Helper for IsPartitionUpdateValid. Check an update from |old_release|
+ // to |new_release| is valid or not.
+ // - If |new_release| is invalid, return kDownloadManifestParseError
+ // - If downgrade detected, kPayloadTimestampError if |prevent_downgrade| is
+ // set to true, or kSuccess if |prevent_downgrade| is set to false
+ // - If update is valid, kSuccess.
static ErrorCode IsKernelUpdateValid(const std::string& old_release,
- const std::string& new_release);
+ const std::string& new_release,
+ bool prevent_downgrade);
DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
};
diff --git a/hardware_android_unittest.cc b/hardware_android_unittest.cc
index 9a491f3..679356c 100644
--- a/hardware_android_unittest.cc
+++ b/hardware_android_unittest.cc
@@ -14,54 +14,70 @@
// limitations under the License.
//
+#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "update_engine/common/error_code.h"
-#include "update_engine/common/test_utils.h"
#include "update_engine/hardware_android.h"
+using ::testing::NiceMock;
+using ::testing::Return;
+
namespace chromeos_update_engine {
TEST(HardwareAndroidTest, IsKernelUpdateValid) {
EXPECT_EQ(ErrorCode::kSuccess,
- HardwareAndroid::IsKernelUpdateValid("5.4.42-not-gki", ""))
+ HardwareAndroid::IsKernelUpdateValid(
+ "5.4.42-not-gki", "", true /*prevent_downgrade*/))
<< "Legacy update should be fine";
- EXPECT_EQ(ErrorCode::kSuccess,
- HardwareAndroid::IsKernelUpdateValid("5.4.42-not-gki",
- "5.4.42-android12-0"))
+ EXPECT_EQ(
+ ErrorCode::kSuccess,
+ HardwareAndroid::IsKernelUpdateValid(
+ "5.4.42-not-gki", "5.4.42-android12-0", true /*prevent_downgrade*/))
<< "Update to GKI should be fine";
- EXPECT_EQ(
- ErrorCode::kDownloadManifestParseError,
- HardwareAndroid::IsKernelUpdateValid("5.4.42-not-gki", "5.4.42-not-gki"))
+ EXPECT_EQ(ErrorCode::kDownloadManifestParseError,
+ HardwareAndroid::IsKernelUpdateValid(
+ "5.4.42-not-gki", "5.4.42-not-gki", true /*prevent_downgrade*/))
<< "Should report parse error for invalid version field";
EXPECT_EQ(ErrorCode::kSuccess,
- HardwareAndroid::IsKernelUpdateValid(
- "5.4.42-android12-0-something", "5.4.42-android12-0-something"))
+ HardwareAndroid::IsKernelUpdateValid("5.4.42-android12-0-something",
+ "5.4.42-android12-0-something",
+ true /*prevent_downgrade*/))
<< "Self update should be fine";
EXPECT_EQ(ErrorCode::kSuccess,
- HardwareAndroid::IsKernelUpdateValid(
- "5.4.42-android12-0-something", "5.4.43-android12-0-something"))
+ HardwareAndroid::IsKernelUpdateValid("5.4.42-android12-0-something",
+ "5.4.43-android12-0-something",
+ true /*prevent_downgrade*/))
<< "Sub-level update should be fine";
EXPECT_EQ(
ErrorCode::kSuccess,
HardwareAndroid::IsKernelUpdateValid("5.4.42-android12-0-something",
- "5.10.10-android12-0-something"))
+ "5.10.10-android12-0-something",
+ true /*prevent_downgrade*/))
<< "KMI version update should be fine";
EXPECT_EQ(ErrorCode::kPayloadTimestampError,
HardwareAndroid::IsKernelUpdateValid("5.4.42-android12-0-something",
- "5.4.5-android12-0-something"))
+ "5.4.5-android12-0-something",
+ true /*prevent_downgrade*/))
<< "Should detect sub-level downgrade";
EXPECT_EQ(ErrorCode::kPayloadTimestampError,
HardwareAndroid::IsKernelUpdateValid("5.4.42-android12-0-something",
- "5.1.5-android12-0-something"))
+ "5.1.5-android12-0-something",
+ true /*prevent_downgrade*/))
<< "Should detect KMI version downgrade";
+
+ EXPECT_EQ(ErrorCode::kSuccess,
+ HardwareAndroid::IsKernelUpdateValid("5.4.42-android12-0-something",
+ "5.4.5-android12-0-something",
+ false /*prevent_downgrade*/))
+ << "Should suppress sub-level downgrade";
}
} // namespace chromeos_update_engine