diff options
-rw-r--r-- | core/java/android/os/Build.java | 41 | ||||
-rw-r--r-- | core/java/com/android/internal/os/RuntimeInit.java | 2 |
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 */ |