summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/os/Build.java41
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java2
2 files changed, 43 insertions, 0 deletions
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 862f4c4..883977f 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -23,7 +23,11 @@ import com.android.internal.telephony.TelephonyProperties;
import dalvik.system.VMRuntime;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Information about the current build, extracted from system properties.
@@ -664,6 +668,7 @@ public class Build {
/** The type of build, like "user" or "eng". */
public static final String TYPE = getString("ro.build.type");
+ private static String TYPE_FOR_APPS = parseBuildTypeFromFingerprint();
/** Comma-separated tags describing the build, like "unsigned,debug". */
public static final String TAGS = getString("ro.build.tags");
@@ -690,6 +695,42 @@ public class Build {
return finger;
}
+ // Some apps like to compare the build type embedded in fingerprint
+ // to the actual build type. As the fingerprint in our case is almost
+ // always hardcoded to the stock ROM fingerprint, provide that instead
+ // of the actual one if possible.
+ private static String parseBuildTypeFromFingerprint() {
+ final String fingerprint = SystemProperties.get("ro.build.fingerprint");
+ if (TextUtils.isEmpty(fingerprint)) {
+ return null;
+ }
+ Pattern fingerprintPattern =
+ Pattern.compile("(.*)\\/(.*)\\/(.*):(.*)\\/(.*)\\/(.*):(.*)\\/(.*)");
+ Matcher matcher = fingerprintPattern.matcher(fingerprint);
+ return matcher.matches() ? matcher.group(7) : null;
+ }
+
+ /** @hide */
+ public static void adjustBuildTypeIfNeeded() {
+ if (Process.isApplicationUid(Process.myUid()) && !TextUtils.isEmpty(TYPE_FOR_APPS)) {
+ try {
+ // This is sick. TYPE is final (which can't be changed because it's an API
+ // guarantee), but we have to reassign it. Resort to reflection to unset the
+ // final modifier, change the value and restore the final modifier afterwards.
+ Field typeField = Build.class.getField("TYPE");
+ Field accessFlagsField = Field.class.getDeclaredField("accessFlags");
+ accessFlagsField.setAccessible(true);
+ int currentFlags = accessFlagsField.getInt(typeField);
+ accessFlagsField.setInt(typeField, currentFlags & ~Modifier.FINAL);
+ typeField.set(null, TYPE_FOR_APPS);
+ accessFlagsField.setInt(typeField, currentFlags);
+ accessFlagsField.setAccessible(false);
+ } catch (Exception e) {
+ // shouldn't happen, but we don't want to crash the app even if it does happen
+ }
+ }
+ }
+
/**
* Ensure that raw fingerprint system property is defined. If it was derived
* dynamically by {@link #deriveFingerprint()} this is where we push the
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 3377189..45dac2f 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -114,6 +114,8 @@ public class RuntimeInit {
/* set default handler; this applies to all threads in the VM */
Thread.setDefaultUncaughtExceptionHandler(new UncaughtHandler());
+ Build.adjustBuildTypeIfNeeded();
+
/*
* Install a TimezoneGetter subclass for ZoneInfo.db
*/