Refactor the code to check the metadata

The two functions check_wipe_package() and check_newer_ab_build() were
using the same flow; and checked the same device properties against the
metadata file in the package. These properties include: ota_type,
pre-device, and serial number.

Therefore, we can consolidate the checks to a single function; and
continue to check the fingerprint and timestamp only for AB updates.

This change also addresses the need to accept multiple serial number in
the wipe package.

Bug: 118401208
Test: unit tests pass
Change-Id: Ia6bc48fb6effcae059a2ff2cf71764b4136b4c00
diff --git a/install.cpp b/install.cpp
index 42d2641..e1e8ee8 100644
--- a/install.cpp
+++ b/install.cpp
@@ -32,9 +32,7 @@
 #include <condition_variable>
 #include <functional>
 #include <limits>
-#include <map>
 #include <mutex>
-#include <string>
 #include <thread>
 #include <vector>
 
@@ -47,7 +45,6 @@
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
 #include <vintf/VintfObjectRecovery.h>
-#include <ziparchive/zip_archive.h>
 
 #include "common.h"
 #include "otautil/error_code.h"
@@ -67,18 +64,7 @@
 
 static std::condition_variable finish_log_temperature;
 
-// This function parses and returns the build.version.incremental
-static std::string parse_build_number(const std::string& str) {
-    size_t pos = str.find('=');
-    if (pos != std::string::npos) {
-        return android::base::Trim(str.substr(pos+1));
-    }
-
-    LOG(ERROR) << "Failed to parse build number in " << str;
-    return "";
-}
-
-bool read_metadata_from_package(ZipArchiveHandle zip, std::string* metadata) {
+bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::string>* metadata) {
   CHECK(metadata != nullptr);
 
   static constexpr const char* METADATA_PATH = "META-INF/com/android/metadata";
@@ -90,101 +76,79 @@
   }
 
   uint32_t length = entry.uncompressed_length;
-  metadata->resize(length, '\0');
-  int32_t err = ExtractToMemory(zip, &entry, reinterpret_cast<uint8_t*>(&(*metadata)[0]), length);
+  std::string metadata_string(length, '\0');
+  int32_t err =
+      ExtractToMemory(zip, &entry, reinterpret_cast<uint8_t*>(&metadata_string[0]), length);
   if (err != 0) {
     LOG(ERROR) << "Failed to extract " << METADATA_PATH << ": " << ErrorCodeString(err);
     return false;
   }
+
+  for (const std::string& line : android::base::Split(metadata_string, "\n")) {
+    size_t eq = line.find('=');
+    if (eq != std::string::npos) {
+      metadata->emplace(android::base::Trim(line.substr(0, eq)),
+                        android::base::Trim(line.substr(eq + 1)));
+    }
+  }
+
   return true;
 }
 
-// Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
-static void read_source_target_build(ZipArchiveHandle zip, std::vector<std::string>* log_buffer) {
-  std::string metadata;
-  if (!read_metadata_from_package(zip, &metadata)) {
-    return;
-  }
-  // Examples of the pre-build and post-build strings in metadata:
-  //   pre-build-incremental=2943039
-  //   post-build-incremental=2951741
-  std::vector<std::string> lines = android::base::Split(metadata, "\n");
-  for (const std::string& line : lines) {
-    std::string str = android::base::Trim(line);
-    if (android::base::StartsWith(str, "pre-build-incremental")) {
-      std::string source_build = parse_build_number(str);
-      if (!source_build.empty()) {
-        log_buffer->push_back("source_build: " + source_build);
-      }
-    } else if (android::base::StartsWith(str, "post-build-incremental")) {
-      std::string target_build = parse_build_number(str);
-      if (!target_build.empty()) {
-        log_buffer->push_back("target_build: " + target_build);
-      }
-    }
+// Gets the value for the given key in |metadata|. Returns an emtpy string if the key isn't
+// present.
+static std::string get_value(const std::map<std::string, std::string>& metadata,
+                             const std::string& key) {
+  const auto& it = metadata.find(key);
+  return (it == metadata.end()) ? "" : it->second;
+}
+
+static std::string OtaTypeToString(OtaType type) {
+  switch (type) {
+    case OtaType::AB:
+      return "AB";
+    case OtaType::BLOCK:
+      return "BLOCK";
+    case OtaType::BRICK:
+      return "BRICK";
   }
 }
 
-// Parses the metadata of the OTA package in |zip| and checks whether we are allowed to accept this
-// A/B package. Downgrading is not allowed unless explicitly enabled in the package and only for
+// Read the build.version.incremental of src/tgt from the metadata and log it to last_install.
+static void ReadSourceTargetBuild(const std::map<std::string, std::string>& metadata,
+                                  std::vector<std::string>* log_buffer) {
+  // Examples of the pre-build and post-build strings in metadata:
+  //   pre-build-incremental=2943039
+  //   post-build-incremental=2951741
+  auto source_build = get_value(metadata, "pre-build-incremental");
+  if (!source_build.empty()) {
+    log_buffer->push_back("source_build: " + source_build);
+  }
+
+  auto target_build = get_value(metadata, "post-build-incremental");
+  if (!target_build.empty()) {
+    log_buffer->push_back("target_build: " + target_build);
+  }
+}
+
+// Checks the build version, fingerprint and timestamp in the metadata of the A/B package.
+// Downgrading is not allowed unless explicitly enabled in the package and only for
 // incremental packages.
-static int check_newer_ab_build(ZipArchiveHandle zip) {
-  std::string metadata_str;
-  if (!read_metadata_from_package(zip, &metadata_str)) {
-    return INSTALL_CORRUPT;
-  }
-  std::map<std::string, std::string> metadata;
-  for (const std::string& line : android::base::Split(metadata_str, "\n")) {
-    size_t eq = line.find('=');
-    if (eq != std::string::npos) {
-      metadata[line.substr(0, eq)] = line.substr(eq + 1);
-    }
-  }
-
-  std::string value = android::base::GetProperty("ro.product.device", "");
-  const std::string& pkg_device = metadata["pre-device"];
-  if (pkg_device != value || pkg_device.empty()) {
-    LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << value;
-    return INSTALL_ERROR;
-  }
-
-  // We allow the package to not have any serialno; and we also allow it to carry multiple serial
-  // numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the
-  // verification if the device's serialno doesn't match any of these carried numbers.
-  value = android::base::GetProperty("ro.serialno", "");
-  const std::string& pkg_serial_no = metadata["serialno"];
-  if (!pkg_serial_no.empty()) {
-    bool match = false;
-    for (const std::string& number : android::base::Split(pkg_serial_no, "|")) {
-      if (value == android::base::Trim(number)) {
-        match = true;
-        break;
-      }
-    }
-    if (!match) {
-      LOG(ERROR) << "Package is for serial " << pkg_serial_no;
-      return INSTALL_ERROR;
-    }
-  }
-
-  if (metadata["ota-type"] != "AB") {
-    LOG(ERROR) << "Package is not A/B";
-    return INSTALL_ERROR;
-  }
-
+static int CheckAbSpecificMetadata(const std::map<std::string, std::string>& metadata) {
   // Incremental updates should match the current build.
-  value = android::base::GetProperty("ro.build.version.incremental", "");
-  const std::string& pkg_pre_build = metadata["pre-build-incremental"];
-  if (!pkg_pre_build.empty() && pkg_pre_build != value) {
-    LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected " << value;
+  auto device_pre_build = android::base::GetProperty("ro.build.version.incremental", "");
+  auto pkg_pre_build = get_value(metadata, "pre-build-incremental");
+  if (!pkg_pre_build.empty() && pkg_pre_build != device_pre_build) {
+    LOG(ERROR) << "Package is for source build " << pkg_pre_build << " but expected "
+               << device_pre_build;
     return INSTALL_ERROR;
   }
 
-  value = android::base::GetProperty("ro.build.fingerprint", "");
-  const std::string& pkg_pre_build_fingerprint = metadata["pre-build"];
-  if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != value) {
+  auto device_fingerprint = android::base::GetProperty("ro.build.fingerprint", "");
+  auto pkg_pre_build_fingerprint = get_value(metadata, "pre-build");
+  if (!pkg_pre_build_fingerprint.empty() && pkg_pre_build_fingerprint != device_fingerprint) {
     LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint << " but expected "
-               << value;
+               << device_fingerprint;
     return INSTALL_ERROR;
   }
 
@@ -194,10 +158,11 @@
   int64_t pkg_post_timestamp = 0;
   // We allow to full update to the same version we are running, in case there
   // is a problem with the current copy of that version.
-  if (metadata["post-timestamp"].empty() ||
-      !android::base::ParseInt(metadata["post-timestamp"].c_str(), &pkg_post_timestamp) ||
+  auto pkg_post_timestamp_string = get_value(metadata, "post-timestamp");
+  if (pkg_post_timestamp_string.empty() ||
+      !android::base::ParseInt(pkg_post_timestamp_string, &pkg_post_timestamp) ||
       pkg_post_timestamp < build_timestamp) {
-    if (metadata["ota-downgrade"] != "yes") {
+    if (get_value(metadata, "ota-downgrade") != "yes") {
       LOG(ERROR) << "Update package is older than the current build, expected a build "
                     "newer than timestamp "
                  << build_timestamp << " but package has timestamp " << pkg_post_timestamp
@@ -213,13 +178,55 @@
   return 0;
 }
 
+int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type) {
+  auto package_ota_type = get_value(metadata, "ota-type");
+  auto expected_ota_type = OtaTypeToString(ota_type);
+  if (ota_type != OtaType::AB && ota_type != OtaType::BRICK) {
+    LOG(INFO) << "Skip package metadata check for ota type " << expected_ota_type;
+    return 0;
+  }
+
+  if (package_ota_type != expected_ota_type) {
+    LOG(ERROR) << "Unexpected ota package type, expects " << expected_ota_type << ", actual "
+               << package_ota_type;
+    return INSTALL_ERROR;
+  }
+
+  auto device = android::base::GetProperty("ro.product.device", "");
+  auto pkg_device = get_value(metadata, "pre-device");
+  if (pkg_device != device || pkg_device.empty()) {
+    LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << device;
+    return INSTALL_ERROR;
+  }
+
+  // We allow the package to not have any serialno; and we also allow it to carry multiple serial
+  // numbers split by "|"; e.g. serialno=serialno1|serialno2|serialno3 ... We will fail the
+  // verification if the device's serialno doesn't match any of these carried numbers.
+  auto pkg_serial_no = get_value(metadata, "serialno");
+  if (!pkg_serial_no.empty()) {
+    auto device_serial_no = android::base::GetProperty("ro.serialno", "");
+    bool serial_number_match = false;
+    for (const auto& number : android::base::Split(pkg_serial_no, "|")) {
+      if (device_serial_no == android::base::Trim(number)) {
+        serial_number_match = true;
+      }
+    }
+    if (!serial_number_match) {
+      LOG(ERROR) << "Package is for serial " << pkg_serial_no;
+      return INSTALL_ERROR;
+    }
+  }
+
+  if (ota_type == OtaType::AB) {
+    return CheckAbSpecificMetadata(metadata);
+  }
+
+  return 0;
+}
+
 int SetUpAbUpdateCommands(const std::string& package, ZipArchiveHandle zip, int status_fd,
                           std::vector<std::string>* cmd) {
   CHECK(cmd != nullptr);
-  int ret = check_newer_ab_build(zip);
-  if (ret != 0) {
-    return ret;
-  }
 
   // For A/B updates we extract the payload properties to a buffer and obtain the RAW payload offset
   // in the zip file.
@@ -311,20 +318,33 @@
 static int try_update_binary(const std::string& package, ZipArchiveHandle zip, bool* wipe_cache,
                              std::vector<std::string>* log_buffer, int retry_count,
                              int* max_temperature) {
-  read_source_target_build(zip, log_buffer);
+  std::map<std::string, std::string> metadata;
+  if (!ReadMetadataFromPackage(zip, &metadata)) {
+    LOG(ERROR) << "Failed to parse metadata in the zip file";
+    return INSTALL_CORRUPT;
+  }
+
+  bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
+  // Verifies against the metadata in the package first.
+  if (int check_status = is_ab ? CheckPackageMetadata(metadata, OtaType::AB) : 0;
+      check_status != 0) {
+    log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
+    return check_status;
+  }
+
+  ReadSourceTargetBuild(metadata, log_buffer);
 
   int pipefd[2];
   pipe(pipefd);
-
-  bool is_ab = android::base::GetBoolProperty("ro.build.ab_update", false);
   std::vector<std::string> args;
-  int ret = is_ab ? SetUpAbUpdateCommands(package, zip, pipefd[1], &args)
-                  : SetUpNonAbUpdateCommands(package, zip, retry_count, pipefd[1], &args);
-  if (ret) {
+  if (int update_status =
+          is_ab ? SetUpAbUpdateCommands(package, zip, pipefd[1], &args)
+                : SetUpNonAbUpdateCommands(package, zip, retry_count, pipefd[1], &args);
+      update_status != 0) {
     close(pipefd[0]);
     close(pipefd[1]);
     log_buffer->push_back(android::base::StringPrintf("error: %d", kUpdateBinaryCommandFailure));
-    return ret;
+    return update_status;
   }
 
   // When executing the update binary contained in the package, the
diff --git a/install.h b/install.h
index 1d3d0cd..c6db1d1 100644
--- a/install.h
+++ b/install.h
@@ -19,6 +19,7 @@
 
 #include <stddef.h>
 
+#include <map>
 #include <string>
 
 #include <ziparchive/zip_archive.h>
@@ -33,6 +34,12 @@
   INSTALL_KEY_INTERRUPTED
 };
 
+enum class OtaType {
+  AB,
+  BLOCK,
+  BRICK,
+};
+
 // Installs the given update package. If INSTALL_SUCCESS is returned and *wipe_cache is true on
 // exit, caller should wipe the cache partition.
 int install_package(const std::string& package, bool* wipe_cache, bool needs_mount,
@@ -42,12 +49,17 @@
 // otherwise return false.
 bool verify_package(const unsigned char* package_data, size_t package_size);
 
-// Read meta data file of the package, write its content in the string pointed by meta_data.
-// Return true if succeed, otherwise return false.
-bool read_metadata_from_package(ZipArchiveHandle zip, std::string* metadata);
+// Reads meta data file of the package; parses each line in the format "key=value"; and writes the
+// result to |metadata|. Return true if succeed, otherwise return false.
+bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::string>* metadata);
 
 // Verifies the compatibility info in a Treble-compatible package. Returns true directly if the
 // entry doesn't exist.
 bool verify_package_compatibility(ZipArchiveHandle package_zip);
 
+// Checks if the the metadata in the OTA package has expected values. Returns 0 on success.
+// Mandatory checks: ota-type, pre-device and serial number(if presents)
+// AB OTA specific checks: pre-build version, fingerprint, timestamp.
+int CheckPackageMetadata(const std::map<std::string, std::string>& metadata, OtaType ota_type);
+
 #endif  // RECOVERY_INSTALL_H_
diff --git a/recovery.cpp b/recovery.cpp
index d7bc6fd..e17526a 100644
--- a/recovery.cpp
+++ b/recovery.cpp
@@ -520,34 +520,17 @@
         LOG(ERROR) << "Can't open wipe package : " << ErrorCodeString(err);
         return false;
     }
-    std::string metadata;
-    if (!read_metadata_from_package(zip, &metadata)) {
-        CloseArchive(zip);
-        return false;
+
+    std::map<std::string, std::string> metadata;
+    if (!ReadMetadataFromPackage(zip, &metadata)) {
+      LOG(ERROR) << "Failed to parse metadata in the zip file";
+      return false;
     }
+
+    int result = CheckPackageMetadata(metadata, OtaType::BRICK);
     CloseArchive(zip);
 
-    // Check metadata
-    std::vector<std::string> lines = android::base::Split(metadata, "\n");
-    bool ota_type_matched = false;
-    bool device_type_matched = false;
-    bool has_serial_number = false;
-    bool serial_number_matched = false;
-    for (const auto& line : lines) {
-        if (line == "ota-type=BRICK") {
-            ota_type_matched = true;
-        } else if (android::base::StartsWith(line, "pre-device=")) {
-            std::string device_type = line.substr(strlen("pre-device="));
-            std::string real_device_type = android::base::GetProperty("ro.build.product", "");
-            device_type_matched = (device_type == real_device_type);
-        } else if (android::base::StartsWith(line, "serialno=")) {
-            std::string serial_no = line.substr(strlen("serialno="));
-            std::string real_serial_no = android::base::GetProperty("ro.serialno", "");
-            has_serial_number = true;
-            serial_number_matched = (serial_no == real_serial_no);
-        }
-    }
-    return ota_type_matched && device_type_matched && (!has_serial_number || serial_number_matched);
+    return result == 0;
 }
 
 // Wipes the current A/B device, with a secure wipe of all the partitions in RECOVERY_WIPE.
diff --git a/tests/component/install_test.cpp b/tests/component/install_test.cpp
index 6583c96..5c6d584 100644
--- a/tests/component/install_test.cpp
+++ b/tests/component/install_test.cpp
@@ -20,6 +20,7 @@
 #include <unistd.h>
 
 #include <algorithm>
+#include <random>
 #include <string>
 #include <vector>
 
@@ -74,15 +75,15 @@
 
 TEST(InstallTest, read_metadata_from_package_smoke) {
   TemporaryFile temp_file;
-  const std::string content("abcdefg");
+  const std::string content("abc=defg");
   BuildZipArchive({ { "META-INF/com/android/metadata", content } }, temp_file.release(),
                   kCompressStored);
 
   ZipArchiveHandle zip;
   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
-  std::string metadata;
-  ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
-  ASSERT_EQ(content, metadata);
+  std::map<std::string, std::string> metadata;
+  ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
+  ASSERT_EQ("defg", metadata["abc"]);
   CloseArchive(zip);
 
   TemporaryFile temp_file2;
@@ -91,8 +92,8 @@
 
   ASSERT_EQ(0, OpenArchive(temp_file2.path, &zip));
   metadata.clear();
-  ASSERT_TRUE(read_metadata_from_package(zip, &metadata));
-  ASSERT_EQ(content, metadata);
+  ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
+  ASSERT_EQ("defg", metadata["abc"]);
   CloseArchive(zip);
 }
 
@@ -102,8 +103,8 @@
 
   ZipArchiveHandle zip;
   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
-  std::string metadata;
-  ASSERT_FALSE(read_metadata_from_package(zip, &metadata));
+  std::map<std::string, std::string> metadata;
+  ASSERT_FALSE(ReadMetadataFromPackage(zip, &metadata));
   CloseArchive(zip);
 }
 
@@ -235,11 +236,11 @@
   if (!serialno.empty()) {
     meta.push_back("serialno=" + serialno);
   }
-  std::string metadata = android::base::Join(meta, "\n");
+  std::string metadata_string = android::base::Join(meta, "\n");
 
   BuildZipArchive({ { "payload.bin", "" },
                     { "payload_properties.txt", properties },
-                    { "META-INF/com/android/metadata", metadata } },
+                    { "META-INF/com/android/metadata", metadata_string } },
                   temp_file.release(), kCompressStored);
 
   ZipArchiveHandle zip;
@@ -247,10 +248,15 @@
   ZipString payload_name("payload.bin");
   ZipEntry payload_entry;
   ASSERT_EQ(0, FindEntry(zip, payload_name, &payload_entry));
-  int status_fd = 10;
-  std::string package = "/path/to/update.zip";
-  std::vector<std::string> cmd;
+
+  std::map<std::string, std::string> metadata;
+  ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
   if (success) {
+    ASSERT_EQ(0, CheckPackageMetadata(metadata, OtaType::AB));
+
+    int status_fd = 10;
+    std::string package = "/path/to/update.zip";
+    std::vector<std::string> cmd;
     ASSERT_EQ(0, SetUpAbUpdateCommands(package, zip, status_fd, &cmd));
     ASSERT_EQ(5U, cmd.size());
     ASSERT_EQ("/system/bin/update_engine_sideload", cmd[0]);
@@ -259,7 +265,7 @@
     ASSERT_EQ("--headers=" + properties, cmd[3]);
     ASSERT_EQ("--status_fd=" + std::to_string(status_fd), cmd[4]);
   } else {
-    ASSERT_EQ(INSTALL_ERROR, SetUpAbUpdateCommands(package, zip, status_fd, &cmd));
+    ASSERT_EQ(INSTALL_ERROR, CheckPackageMetadata(metadata, OtaType::AB));
   }
   CloseArchive(zip);
 }
@@ -282,8 +288,12 @@
       },
       "\n");
 
-  BuildZipArchive({ { "payload.bin", "" }, { "META-INF/com/android/metadata", metadata } },
-                  temp_file.release(), kCompressStored);
+  BuildZipArchive(
+      {
+          { "payload.bin", "" },
+          { "META-INF/com/android/metadata", metadata },
+      },
+      temp_file.release(), kCompressStored);
 
   ZipArchiveHandle zip;
   ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
@@ -322,3 +332,241 @@
   // String with the matching serialno should pass the verification.
   VerifyAbUpdateCommands(long_serialno);
 }
+
+static void test_check_package_metadata(const std::string& metadata_string, OtaType ota_type,
+                                        int exptected_result) {
+  TemporaryFile temp_file;
+  BuildZipArchive(
+      {
+          { "META-INF/com/android/metadata", metadata_string },
+      },
+      temp_file.release(), kCompressStored);
+
+  ZipArchiveHandle zip;
+  ASSERT_EQ(0, OpenArchive(temp_file.path, &zip));
+
+  std::map<std::string, std::string> metadata;
+  ASSERT_TRUE(ReadMetadataFromPackage(zip, &metadata));
+  ASSERT_EQ(exptected_result, CheckPackageMetadata(metadata, ota_type));
+  CloseArchive(zip);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ota_type) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_NE("", device);
+
+  // ota-type must be present
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "pre-device=" + device,
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+  // Checks if ota-type matches
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, 0);
+
+  test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_device_type) {
+  // device type can not be empty
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+
+  // device type mismatches
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+          "pre-device=dummy_device_type",
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_serial_number_smoke) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_NE("", device);
+
+  // Serial number doesn't need to exist
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+          "pre-device=" + device,
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, 0);
+
+  // Serial number mismatches
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+          "pre-device=" + device,
+          "serialno=dummy_serial",
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+
+  std::string serialno = android::base::GetProperty("ro.serialno", "");
+  ASSERT_NE("", serialno);
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+          "pre-device=" + device,
+          "serialno=" + serialno,
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, 0);
+}
+
+TEST(InstallTest, CheckPackageMetadata_multiple_serial_number) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_NE("", device);
+
+  std::string serialno = android::base::GetProperty("ro.serialno", "");
+  ASSERT_NE("", serialno);
+
+  std::vector<std::string> serial_numbers;
+  // Creates a dummy serial number string.
+  for (size_t c = 'a'; c <= 'z'; c++) {
+    serial_numbers.emplace_back(c, serialno.size());
+  }
+
+  // No matched serialno found.
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+          "pre-device=" + device,
+          "serialno=" + android::base::Join(serial_numbers, '|'),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, INSTALL_ERROR);
+
+  serial_numbers.emplace_back(serialno);
+  std::shuffle(serial_numbers.begin(), serial_numbers.end(), std::default_random_engine());
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=BRICK",
+          "pre-device=" + device,
+          "serialno=" + android::base::Join(serial_numbers, '|'),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::BRICK, 0);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ab_build_version) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_NE("", device);
+
+  std::string build_version = android::base::GetProperty("ro.build.version.incremental", "");
+  ASSERT_NE("", build_version);
+
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "pre-build-incremental=" + build_version,
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, 0);
+
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "pre-build-incremental=dummy_build",
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ab_fingerprint) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_NE("", device);
+
+  std::string finger_print = android::base::GetProperty("ro.build.fingerprint", "");
+  ASSERT_NE("", finger_print);
+
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "pre-build=" + finger_print,
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, 0);
+
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "pre-build=dummy_build_fingerprint",
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+}
+
+TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_NE("", device);
+
+  // post timestamp is required for upgrade.
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+  // post timestamp should be larger than the timestamp on device.
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "post-timestamp=0",
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+  // fingerprint is required for downgrade
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "post-timestamp=0",
+          "ota-downgrade=yes",
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, INSTALL_ERROR);
+
+  std::string finger_print = android::base::GetProperty("ro.build.fingerprint", "");
+  ASSERT_NE("", finger_print);
+
+  metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=" + device,
+          "post-timestamp=0",
+          "pre-build=" + finger_print,
+          "ota-downgrade=yes",
+      },
+      "\n");
+  test_check_package_metadata(metadata, OtaType::AB, 0);
+}