Derive fingerprint at runtime when undefined.

Some devices leave "ro.build.fingerprint" undefined at build time,
since they need to build it from the components at runtime.

Bug: 13340779
Change-Id: I4d74398817af22079a11c196dc6742b85d2bfb61
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 11e3795..5846bb5 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -16,6 +16,8 @@
 
 package android.os;
 
+import android.text.TextUtils;
+
 import com.android.internal.telephony.TelephonyProperties;
 
 /**
@@ -509,7 +511,39 @@
     public static final String TAGS = getString("ro.build.tags");
 
     /** A string that uniquely identifies this build.  Do not attempt to parse this value. */
-    public static final String FINGERPRINT = getString("ro.build.fingerprint");
+    public static final String FINGERPRINT = deriveFingerprint();
+
+    /**
+     * Some devices split the fingerprint components between multiple
+     * partitions, so we might derive the fingerprint at runtime.
+     */
+    private static String deriveFingerprint() {
+        String finger = SystemProperties.get("ro.build.fingerprint");
+        if (TextUtils.isEmpty(finger)) {
+            finger = getString("ro.product.brand") + '/' +
+                    getString("ro.product.name") + '/' +
+                    getString("ro.product.device") + ':' +
+                    getString("ro.build.version.release") + '/' +
+                    getString("ro.build.id") + '/' +
+                    getString("ro.build.version.incremental") + ':' +
+                    getString("ro.build.type") + '/' +
+                    getString("ro.build.tags");
+        }
+        return finger;
+    }
+
+    /**
+     * Ensure that raw fingerprint system property is defined. If it was derived
+     * dynamically by {@link #deriveFingerprint()} this is where we push the
+     * derived value into the property service.
+     *
+     * @hide
+     */
+    public static void ensureFingerprintProperty() {
+        if (TextUtils.isEmpty(SystemProperties.get("ro.build.fingerprint"))) {
+            SystemProperties.set("ro.build.fingerprint", FINGERPRINT);
+        }
+    }
 
     // The following properties only make sense for internal engineering builds.
     public static final long TIME = getLong("ro.build.date.utc") * 1000;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 00d5468..08b1eba 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -29,6 +29,7 @@
 import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.media.AudioService;
+import android.os.Build;
 import android.os.Environment;
 import android.os.FactoryTest;
 import android.os.Handler;
@@ -201,6 +202,10 @@
         // as efficient as possible with its memory usage.
         VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
 
+        // Some devices rely on runtime fingerprint generation, so make sure
+        // we've defined it before booting further.
+        Build.ensureFingerprintProperty();
+
         // Within the system server, it is an error to access Environment paths without
         // explicitly specifying a user.
         Environment.setUserRequired(true);