Read boot image version from ro.bootimage.build.date.utc

This change re-defines boot image downgrade check logic. The
sysprop ro.bootimage.build.date.utc is checked instead. If the
sysprop ro.build.ab_update.gki.prevent_downgrade_version is not set,
any detected downgrades are suppressed.

Bug: 162554855
Bug: 162623577
Bug: 169169031
Test: pass

Change-Id: Ib86cb40576a852e0654a4c22d81c876d0315d0d2
diff --git a/Android.bp b/Android.bp
index 193928b..28e1bab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -261,7 +261,6 @@
 
     static_libs: [
         "gkiprops",
-        "libkver",
         "libpayload_consumer",
         "libupdate_engine_boot_control",
     ],
@@ -392,7 +391,6 @@
         "libbrillo-stream",
         "libbrillo",
         "libchrome",
-        "libkver",
     ],
     target: {
         recovery: {
@@ -686,7 +684,6 @@
         "common/utils_unittest.cc",
         "dynamic_partition_control_android_unittest.cc",
         "libcurl_http_fetcher_unittest.cc",
-        "hardware_android_unittest.cc",
         "payload_consumer/bzip_extent_writer_unittest.cc",
         "payload_consumer/cached_file_descriptor_unittest.cc",
         "payload_consumer/certificate_parser_android_unittest.cc",
diff --git a/hardware_android.cc b/hardware_android.cc
index fc6e1dc..a659bf6 100644
--- a/hardware_android.cc
+++ b/hardware_android.cc
@@ -17,7 +17,6 @@
 #include "update_engine/hardware_android.h"
 
 #include <sys/types.h>
-#include <sys/utsname.h>
 
 #include <memory>
 #include <string>
@@ -28,8 +27,6 @@
 #include <android-base/properties.h>
 #include <base/files/file_util.h>
 #include <bootloader_message/bootloader_message.h>
-#include <kver/kernel_release.h>
-#include <kver/utils.h>
 
 #include "update_engine/common/error_code_utils.h"
 #include "update_engine/common/hardware.h"
@@ -39,8 +36,6 @@
 using android::base::GetBoolProperty;
 using android::base::GetIntProperty;
 using android::base::GetProperty;
-using android::kver::IsKernelUpdateValid;
-using android::kver::KernelRelease;
 using std::string;
 
 namespace chromeos_update_engine {
@@ -62,6 +57,19 @@
                                     "");
 }
 
+ErrorCode IsTimestampNewerLogged(const std::string& partition_name,
+                                 const std::string& old_version,
+                                 const std::string& new_version) {
+  auto error_code = utils::IsTimestampNewer(old_version, new_version);
+  if (error_code != ErrorCode::kSuccess) {
+    LOG(WARNING) << "Timestamp check failed with "
+                 << utils::ErrorCodeToString(error_code) << ": "
+                 << partition_name << " Partition timestamp: " << old_version
+                 << " Update timestamp: " << new_version;
+  }
+  return error_code;
+}
+
 }  // namespace
 
 namespace hardware {
@@ -242,14 +250,8 @@
 string HardwareAndroid::GetVersionForLogging(
     const string& partition_name) const {
   if (partition_name == "boot") {
-    struct utsname buf;
-    if (uname(&buf) != 0) {
-      PLOG(ERROR) << "Unable to call uname()";
-      return "";
-    }
-    auto kernel_release =
-        KernelRelease::Parse(buf.release, true /* allow_suffix */);
-    return kernel_release.has_value() ? kernel_release->string() : "";
+    // ro.bootimage.build.date.utc
+    return GetPartitionBuildDate("bootimage");
   }
   return GetPartitionBuildDate(partition_name);
 }
@@ -257,61 +259,33 @@
 ErrorCode HardwareAndroid::IsPartitionUpdateValid(
     const string& partition_name, const string& new_version) const {
   if (partition_name == "boot") {
-    struct utsname buf;
-    if (uname(&buf) != 0) {
-      PLOG(ERROR) << "Unable to call uname()";
-      return ErrorCode::kError;
+    const auto old_version = GetPartitionBuildDate("bootimage");
+    auto error_code =
+        IsTimestampNewerLogged(partition_name, old_version, new_version);
+    if (error_code == ErrorCode::kPayloadTimestampError) {
+      bool prevent_downgrade =
+          android::sysprop::GkiProperties::prevent_downgrade_version().value_or(
+              false);
+      if (!prevent_downgrade) {
+        LOG(WARNING) << "Downgrade of boot image is detected, but permitting "
+                        "update because device does not prevent boot image "
+                        "downgrade";
+        // If prevent_downgrade_version sysprop is not explicitly set, permit
+        // downgrade in boot image version.
+        // Even though error_code is overridden here, always call
+        // IsTimestampNewerLogged to produce log messages.
+        error_code = ErrorCode::kSuccess;
+      }
     }
-    bool prevent_downgrade =
-        android::sysprop::GkiProperties::prevent_downgrade_version().value_or(
-            false);
-    return IsKernelUpdateValid(buf.release, new_version, prevent_downgrade);
+    return error_code;
   }
 
   const auto old_version = GetPartitionBuildDate(partition_name);
   // TODO(zhangkelvin)  for some partitions, missing a current timestamp should
   // be an error, e.g. system, vendor, product etc.
-  auto error_code = utils::IsTimestampNewer(old_version, new_version);
-  if (error_code != ErrorCode::kSuccess) {
-    LOG(ERROR) << "Timestamp check failed with "
-               << utils::ErrorCodeToString(error_code)
-               << " Partition timestamp: " << old_version
-               << " Update timestamp: " << new_version;
-  }
+  auto error_code =
+      IsTimestampNewerLogged(partition_name, old_version, new_version);
   return error_code;
 }
 
-ErrorCode HardwareAndroid::IsKernelUpdateValid(const string& old_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;
-  if (new_release.empty()) {
-    LOG(INFO) << "New build does not contain GKI.";
-  } else {
-    new_kernel_release =
-        KernelRelease::Parse(new_release, true /* allow_suffix */);
-    if (!new_kernel_release.has_value()) {
-      LOG(ERROR) << "New kernel release is not valid GKI kernel release: "
-                 << new_release;
-      return ErrorCode::kDownloadManifestParseError;
-    }
-  }
-
-  auto old_kernel_release =
-      KernelRelease::Parse(old_release, true /* allow_suffix */);
-  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 552cb53..d8fbbbe 100644
--- a/hardware_android.h
+++ b/hardware_android.h
@@ -22,7 +22,6 @@
 
 #include <base/macros.h>
 #include <base/time/time.h>
-#include <gtest/gtest_prod.h>
 
 #include "update_engine/common/error_code.h"
 #include "update_engine/common/hardware.h"
@@ -68,18 +67,6 @@
       const std::string& new_version) const override;
 
  private:
-  FRIEND_TEST(HardwareAndroidTest, IsKernelUpdateValid);
-
-  // 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,
-                                       bool prevent_downgrade);
-
   DISALLOW_COPY_AND_ASSIGN(HardwareAndroid);
 };
 
diff --git a/hardware_android_unittest.cc b/hardware_android_unittest.cc
deleted file mode 100644
index 679356c..0000000
--- a/hardware_android_unittest.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-//
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-//
-
-#include <gmock/gmock.h>
-#include <gtest/gtest.h>
-
-#include "update_engine/common/error_code.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", "", true /*prevent_downgrade*/))
-      << "Legacy update should be fine";
-
-  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", 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",
-                                                 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",
-                                                 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",
-                                           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",
-                                                 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",
-                                                 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