Merge "Add recovery support of dynamic fingerprints" am: dca4844328 am: e7034ce855 am: fd481f6f62 am: 1772365161 am: f1c0efc3cc am: cac5ff1f8c

Original change: https://android-review.googlesource.com/c/platform/bootable/recovery/+/1351602

Change-Id: I1abfbb008a49196cb116b581db2b7ac7242a6d1f
diff --git a/install/install.cpp b/install/install.cpp
index d404997..1c711f6 100644
--- a/install/install.cpp
+++ b/install/install.cpp
@@ -67,8 +67,11 @@
 // Default allocation of progress bar segments to operations
 static constexpr int VERIFICATION_PROGRESS_TIME = 60;
 static constexpr float VERIFICATION_PROGRESS_FRACTION = 0.25;
-
+// The charater used to separate dynamic fingerprints. e.x. sargo|aosp-sargo
+static const char* FINGERPRING_SEPARATOR = "|";
 static std::condition_variable finish_log_temperature;
+static bool isInStringList(const std::string& target_token, const std::string& str_list,
+                           const std::string& deliminator);
 
 bool ReadMetadataFromPackage(ZipArchiveHandle zip, std::map<std::string, std::string>* metadata) {
   CHECK(metadata != nullptr);
@@ -151,7 +154,8 @@
 
   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) {
+  if (!pkg_pre_build_fingerprint.empty() &&
+      !isInStringList(device_fingerprint, pkg_pre_build_fingerprint, FINGERPRING_SEPARATOR)) {
     LOG(ERROR) << "Package is for source build " << pkg_pre_build_fingerprint << " but expected "
                << device_fingerprint;
     return false;
@@ -199,7 +203,8 @@
 
   auto device = android::base::GetProperty("ro.product.device", "");
   auto pkg_device = get_value(metadata, "pre-device");
-  if (pkg_device != device || pkg_device.empty()) {
+  // device name can be a | separated list, so need to check
+  if (pkg_device.empty() || !isInStringList(device, pkg_device, FINGERPRING_SEPARATOR)) {
     LOG(ERROR) << "Package is for product " << pkg_device << " but expected " << device;
     return false;
   }
@@ -699,3 +704,18 @@
   }
   return true;
 }
+
+// Check if `target_token` is in string `str_list`, where `str_list` is expected to be a
+// list delimited by `deliminator`
+// E.X. isInStringList("a", "a|b|c|d", "|") => true
+// E.X. isInStringList("abc", "abc", "|") => true
+static bool isInStringList(const std::string& target_token, const std::string& str_list,
+                           const std::string& deliminator) {
+  if (target_token.length() > str_list.length()) {
+    return false;
+  } else if (target_token.length() == str_list.length() || deliminator.length() == 0) {
+    return target_token == str_list;
+  }
+  auto&& list = android::base::Split(str_list, deliminator);
+  return std::find(list.begin(), list.end(), target_token) != list.end();
+}
diff --git a/tests/unit/install_test.cpp b/tests/unit/install_test.cpp
index ee75349..90c4b14 100644
--- a/tests/unit/install_test.cpp
+++ b/tests/unit/install_test.cpp
@@ -466,6 +466,34 @@
   TestCheckPackageMetadata(metadata, OtaType::AB, false);
 }
 
+TEST(InstallTest, CheckPackageMetadata_dynamic_fingerprint) {
+  std::string device = android::base::GetProperty("ro.product.device", "");
+  ASSERT_FALSE(device.empty());
+
+  std::string finger_print = android::base::GetProperty("ro.build.fingerprint", "");
+  ASSERT_FALSE(finger_print.empty());
+
+  std::string metadata = android::base::Join(
+      std::vector<std::string>{
+          "ota-type=AB",
+          "pre-device=please|work|" + device + "|please|work",
+          "pre-build=" + finger_print = "pass|this|test",
+          "post-timestamp=" + std::to_string(std::numeric_limits<int64_t>::max()),
+      },
+      "\n");
+  TestCheckPackageMetadata(metadata, OtaType::AB, true);
+
+  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");
+  TestCheckPackageMetadata(metadata, OtaType::AB, false);
+}
+
 TEST(InstallTest, CheckPackageMetadata_ab_post_timestamp) {
   std::string device = android::base::GetProperty("ro.product.device", "");
   ASSERT_NE("", device);