Support appending vbmeta digest to id/fingerprint

Background in http://go/compatible-build-fingerprint. To uniquely
identify the mixed build, we plan to append the unique vbmeta digest
to ro.build.id.

If BOARD_USE_VBMETA_DIGTEST_IN_FINGERPRINT is true, the build system
will not set ro.build.id. Instead, init will set it at runtime, by
appending the digest to the legacy build id.

Bug: 186786987
Test: build and boot a device with new build id
Change-Id: Idea57df599bfd6eede760671e2555541f7dc3f21
diff --git a/init/property_service.cpp b/init/property_service.cpp
index fe3490d..6511bce 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -94,6 +94,12 @@
 
 namespace android {
 namespace init {
+constexpr auto FINGERPRINT_PROP = "ro.build.fingerprint";
+constexpr auto LEGACY_FINGERPRINT_PROP = "ro.build.legacy.fingerprint";
+constexpr auto ID_PROP = "ro.build.id";
+constexpr auto LEGACY_ID_PROP = "ro.build.legacy.id";
+constexpr auto VBMETA_DIGEST_PROP = "ro.boot.vbmeta.digest";
+constexpr auto DIGEST_SIZE_USED = 8;
 
 static bool persistent_properties_loaded = false;
 
@@ -857,15 +863,33 @@
     }
 }
 
-// If the ro.build.fingerprint property has not been set, derive it from constituent pieces
-static void property_derive_build_fingerprint() {
-    std::string build_fingerprint = GetProperty("ro.build.fingerprint", "");
-    if (!build_fingerprint.empty()) {
+static void property_initialize_build_id() {
+    std::string build_id = GetProperty(ID_PROP, "");
+    if (!build_id.empty()) {
         return;
     }
 
+    std::string legacy_build_id = GetProperty(LEGACY_ID_PROP, "");
+    std::string vbmeta_digest = GetProperty(VBMETA_DIGEST_PROP, "");
+    if (vbmeta_digest.size() < DIGEST_SIZE_USED) {
+        LOG(ERROR) << "vbmeta digest size too small " << vbmeta_digest;
+        // Still try to set the id field in the unexpected case.
+        build_id = legacy_build_id;
+    } else {
+        // Derive the ro.build.id by appending the vbmeta digest to the base value.
+        build_id = legacy_build_id + "." + vbmeta_digest.substr(0, DIGEST_SIZE_USED);
+    }
+
+    std::string error;
+    auto res = PropertySet(ID_PROP, build_id, &error);
+    if (res != PROP_SUCCESS) {
+        LOG(ERROR) << "Failed to set " << ID_PROP << " to " << build_id;
+    }
+}
+
+static std::string ConstructBuildFingerprint(bool legacy) {
     const std::string UNKNOWN = "unknown";
-    build_fingerprint = GetProperty("ro.product.brand", UNKNOWN);
+    std::string build_fingerprint = GetProperty("ro.product.brand", UNKNOWN);
     build_fingerprint += '/';
     build_fingerprint += GetProperty("ro.product.name", UNKNOWN);
     build_fingerprint += '/';
@@ -873,7 +897,10 @@
     build_fingerprint += ':';
     build_fingerprint += GetProperty("ro.build.version.release_or_codename", UNKNOWN);
     build_fingerprint += '/';
-    build_fingerprint += GetProperty("ro.build.id", UNKNOWN);
+
+    std::string build_id =
+            legacy ? GetProperty(LEGACY_ID_PROP, UNKNOWN) : GetProperty(ID_PROP, UNKNOWN);
+    build_fingerprint += build_id;
     build_fingerprint += '/';
     build_fingerprint += GetProperty("ro.build.version.incremental", UNKNOWN);
     build_fingerprint += ':';
@@ -881,13 +908,49 @@
     build_fingerprint += '/';
     build_fingerprint += GetProperty("ro.build.tags", UNKNOWN);
 
-    LOG(INFO) << "Setting property 'ro.build.fingerprint' to '" << build_fingerprint << "'";
+    return build_fingerprint;
+}
+
+// Derive the legacy build fingerprint if we overwrite the build id at runtime.
+static void property_derive_legacy_build_fingerprint() {
+    std::string legacy_build_fingerprint = GetProperty(LEGACY_FINGERPRINT_PROP, "");
+    if (!legacy_build_fingerprint.empty()) {
+        return;
+    }
+
+    // The device doesn't have a legacy build id, skipping the legacy fingerprint.
+    std::string legacy_build_id = GetProperty(LEGACY_ID_PROP, "");
+    if (legacy_build_id.empty()) {
+        return;
+    }
+
+    legacy_build_fingerprint = ConstructBuildFingerprint(true /* legacy fingerprint */);
+    LOG(INFO) << "Setting property '" << LEGACY_FINGERPRINT_PROP << "' to '"
+              << legacy_build_fingerprint << "'";
 
     std::string error;
-    uint32_t res = PropertySet("ro.build.fingerprint", build_fingerprint, &error);
+    uint32_t res = PropertySet(LEGACY_FINGERPRINT_PROP, legacy_build_fingerprint, &error);
     if (res != PROP_SUCCESS) {
-        LOG(ERROR) << "Error setting property 'ro.build.fingerprint': err=" << res << " (" << error
-                   << ")";
+        LOG(ERROR) << "Error setting property '" << LEGACY_FINGERPRINT_PROP << "': err=" << res
+                   << " (" << error << ")";
+    }
+}
+
+// If the ro.build.fingerprint property has not been set, derive it from constituent pieces
+static void property_derive_build_fingerprint() {
+    std::string build_fingerprint = GetProperty("ro.build.fingerprint", "");
+    if (!build_fingerprint.empty()) {
+        return;
+    }
+
+    build_fingerprint = ConstructBuildFingerprint(false /* legacy fingerprint */);
+    LOG(INFO) << "Setting property '" << FINGERPRINT_PROP << "' to '" << build_fingerprint << "'";
+
+    std::string error;
+    uint32_t res = PropertySet(FINGERPRINT_PROP, build_fingerprint, &error);
+    if (res != PROP_SUCCESS) {
+        LOG(ERROR) << "Error setting property '" << FINGERPRINT_PROP << "': err=" << res << " ("
+                   << error << ")";
     }
 }
 
@@ -1035,7 +1098,9 @@
     }
 
     property_initialize_ro_product_props();
+    property_initialize_build_id();
     property_derive_build_fingerprint();
+    property_derive_legacy_build_fingerprint();
     property_initialize_ro_cpu_abilist();
 
     update_sys_usb_config();