diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index cda009ad04f6..91206b322c98 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -121,7 +121,6 @@ import com.android.internal.annotations.Immutable; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; -import com.android.internal.util.PropImitationHooks; import com.android.internal.util.UserIcons; import dalvik.system.VMRuntime; @@ -808,10 +807,60 @@ public Boolean recompute(HasSystemFeatureQuery query) { } }; + private static final String[] pTensorCodenames = { + "felix", + "tangorpro", + "lynx", + "cheetah", + "panther", + "bluejay", + "oriole", + "raven" + }; + + private static final String[] featuresPixel = { + "com.google.android.apps.photos.PIXEL_2019_PRELOAD", + "com.google.android.apps.photos.PIXEL_2019_MIDYEAR_PRELOAD", + "com.google.android.apps.photos.PIXEL_2018_PRELOAD", + "com.google.android.apps.photos.PIXEL_2017_PRELOAD", + "com.google.android.feature.PIXEL_2021_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2020_EXPERIENCE", + "com.google.android.feature.PIXEL_2020_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2019_EXPERIENCE", + "com.google.android.feature.PIXEL_2019_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2018_EXPERIENCE", + "com.google.android.feature.PIXEL_2017_EXPERIENCE", + "com.google.android.feature.PIXEL_EXPERIENCE", + "com.google.android.feature.GOOGLE_BUILD", + "com.google.android.feature.GOOGLE_EXPERIENCE" + }; + + private static final String[] featuresTensor = { + "com.google.android.feature.PIXEL_2022_EXPERIENCE", + "com.google.android.feature.PIXEL_2022_MIDYEAR_EXPERIENCE", + "com.google.android.feature.PIXEL_2021_EXPERIENCE", + }; + + private static final String[] featuresNexus = { + "com.google.android.apps.photos.NEXUS_PRELOAD", + "com.google.android.apps.photos.nexus_preload" + }; + @Override public boolean hasSystemFeature(String name, int version) { - return PropImitationHooks.hasSystemFeature(name, - mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version))); + if (name != null && Arrays.asList(featuresTensor).contains(name) && + !Arrays.asList(pTensorCodenames).contains(SystemProperties.get("ro.product.device"))) { + return false; + } + String packageName = ActivityThread.currentPackageName(); + if (packageName != null && + packageName.equals("com.google.android.apps.photos")) { + if (Arrays.asList(featuresPixel).contains(name)) return false; + if (Arrays.asList(featuresNexus).contains(name)) return true; + } + if (Arrays.asList(featuresPixel).contains(name)) return true; + + return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version)); } /** @hide */ diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java index e17d6805700a..f9c9f0d77fe0 100644 --- a/core/java/android/app/Instrumentation.java +++ b/core/java/android/app/Instrumentation.java @@ -56,7 +56,6 @@ import android.view.WindowManagerGlobal; import com.android.internal.content.ReferrerIntent; -import com.android.internal.util.PropImitationHooks; import java.io.File; import java.lang.annotation.Retention; @@ -65,6 +64,8 @@ import java.util.List; import java.util.concurrent.TimeoutException; +import com.android.internal.util.custom.PixelPropsUtils; + /** * Base class for implementing application instrumentation code. When running * with instrumentation turned on, this class will be instantiated for you @@ -1243,7 +1244,8 @@ public Application newApplication(ClassLoader cl, String className, Context cont Application app = getFactory(context.getPackageName()) .instantiateApplication(cl, className); app.attach(context); - PropImitationHooks.setProps(context); + String packageName = context.getPackageName(); + PixelPropsUtils.setProps(packageName); return app; } @@ -1261,7 +1263,8 @@ static public Application newApplication(Class clazz, Context context) ClassNotFoundException { Application app = (Application)clazz.newInstance(); app.attach(context); - PropImitationHooks.setProps(context); + String packageName = context.getPackageName(); + PixelPropsUtils.setProps(packageName); return app; } diff --git a/core/java/com/android/internal/util/PropImitationHooks.java b/core/java/com/android/internal/util/PropImitationHooks.java deleted file mode 100644 index 552acb1aeece..000000000000 --- a/core/java/com/android/internal/util/PropImitationHooks.java +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright (C) 2022 Paranoid Android - * (C) 2023 ArrowOS - * (C) 2023 The LibreMobileOS Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.util; - -import android.app.ActivityTaskManager; -import android.app.Application; -import android.app.TaskStackListener; -import android.content.ComponentName; -import android.content.Context; -import android.content.res.Resources; -import android.os.Build; -import android.os.Binder; -import android.os.Process; -import android.text.TextUtils; -import android.util.Log; - -import com.android.internal.R; - -import java.lang.reflect.Field; -import java.util.Arrays; -import java.util.Map; -import java.util.Set; - -public class PropImitationHooks { - - private static final String TAG = "PropImitationHooks"; - private static final boolean DEBUG = false; - - private static final String[] sCertifiedProps = - Resources.getSystem().getStringArray(R.array.config_certifiedBuildProperties); - - private static final String sStockFp = - Resources.getSystem().getString(R.string.config_stockFingerprint); - - private static final String sNetflixModel = - Resources.getSystem().getString(R.string.config_netflixSpoofModel); - - private static final boolean sSpoofGapps = - Resources.getSystem().getBoolean(R.bool.config_spoofGoogleApps); - - private static final String PACKAGE_ARCORE = "com.google.ar.core"; - private static final String PACKAGE_ASI = "com.google.android.as"; - private static final String PACKAGE_FINSKY = "com.android.vending"; - private static final String PACKAGE_GMS = "com.google.android.gms"; - private static final String PACKAGE_GPHOTOS = "com.google.android.apps.photos"; - private static final String PACKAGE_NETFLIX = "com.netflix.mediaclient"; - private static final String PACKAGE_SNAPCHAT = "com.snapchat.android"; - private static final String PACKAGE_SMS_ORGANIZER = "com.microsoft.android.smsorganizer"; - private static final String PACKAGE_VELVET = "com.google.android.googlequicksearchbox"; - private static final String PACKAGE_LIVE_WALLPAPER = "com.google.pixel.livewallpaper"; - private static final String PACKAGE_WALLPAPER_EMOJI = "com.google.android.apps.emojiwallpaper"; - private static final String PACKAGE_PIXEL_LAUNCHER = "com.google.android.apps.nexuslauncher"; - - private static final String PROCESS_GMS_PERSISTENT = PACKAGE_GMS + ".persistent"; - private static final String PROCESS_GMS_UNSTABLE = PACKAGE_GMS + ".unstable"; - - private static final Map sPixel7Props = Map.of( - "BRAND", "google", - "MANUFACTURER", "Google", - "DEVICE", "cheetah", - "PRODUCT", "cheetah", - "MODEL", "Pixel 7 Pro", - "FINGERPRINT", "google/cheetah/cheetah:13/TQ3A.230805.001/10316531:user/release-keys" - ); - - private static final Map sPixelProps = Map.of( - "BRAND", "google", - "MANUFACTURER", "Google", - "DEVICE", "redfin", - "PRODUCT", "redfin", - "MODEL", "Pixel 5", - "FINGERPRINT", "google/redfin/redfin:13/TQ3A.230805.001/10316531:user/release-keys" - ); - - private static final ComponentName GMS_ADD_ACCOUNT_ACTIVITY = ComponentName.unflattenFromString( - "com.google.android.gms/.auth.uiflows.minutemaid.MinuteMaidActivity"); - - private static final Map sPixelXLProps = Map.of( - "BRAND", "google", - "MANUFACTURER", "Google", - "DEVICE", "marlin", - "PRODUCT", "marlin", - "MODEL", "Pixel XL", - "FINGERPRINT", "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys" - ); - - private static final Set sFeatureBlacklist = Set.of( - "PIXEL_2017_PRELOAD", - "PIXEL_2018_PRELOAD", - "PIXEL_2019_MIDYEAR_PRELOAD", - "PIXEL_2019_PRELOAD", - "PIXEL_2020_EXPERIENCE", - "PIXEL_2020_MIDYEAR_EXPERIENCE", - "PIXEL_2021_EXPERIENCE", - "PIXEL_2021_MIDYEAR_EXPERIENCE" - ); - - private static final Set sTensorFeatureBlacklist = Set.of( - "PIXEL_2022_EXPERIENCE", - "PIXEL_2022_MIDYEAR_EXPERIENCE", - "PIXEL_2021_EXPERIENCE", - "PIXEL_2021_MIDYEAR_EXPERIENCE" - ); - - private static volatile String sProcessName; - private static volatile boolean sIsGms, sIsFinsky, sIsPhotos, sIsPixelLauncher, sIsASI; - - public static void setProps(Context context) { - final String packageName = context.getPackageName(); - final String processName = Application.getProcessName(); - - setPropValue("TYPE", "user"); - setPropValue("TAGS", "release-keys"); - - if (TextUtils.isEmpty(packageName) || TextUtils.isEmpty(processName)) { - Log.e(TAG, "Null package or process name"); - return; - } - - sProcessName = processName; - sIsGms = packageName.equals(PACKAGE_GMS) && processName.equals(PROCESS_GMS_UNSTABLE); - sIsFinsky = packageName.equals(PACKAGE_FINSKY); - sIsPhotos = sSpoofGapps && packageName.equals(PACKAGE_GPHOTOS); - sIsPixelLauncher = sSpoofGapps && packageName.equals(PACKAGE_PIXEL_LAUNCHER); - sIsASI = sSpoofGapps && packageName.equals(PACKAGE_ASI); - - /* Set certified properties for GMSCore - * Set stock fingerprint for ARCore - * Set Pixel 5 for Snapchat, SMS Organizer, Google, ASI and GMS device configurator - * Set Pixel 7 Pro for Live wallpaper and WallpaperEmoji - * Set Pixel XL for Google Photos - * Set custom model for Netflix - */ - if (sIsGms) { - setCertifiedPropsForGms(); - } else if (!sStockFp.isEmpty() && packageName.equals(PACKAGE_ARCORE)) { - dlog("Setting stock fingerprint for: " + packageName); - setPropValue("FINGERPRINT", sStockFp); - } else if (sSpoofGapps && (packageName.equals(PACKAGE_VELVET) - || packageName.equals(PACKAGE_ASI) - || packageName.equals(PACKAGE_SNAPCHAT) - || packageName.equals(PACKAGE_SMS_ORGANIZER) - || (packageName.equals(PACKAGE_GMS) - && processName.equals(PROCESS_GMS_PERSISTENT)))) { - dlog("Spoofing Pixel 5 for: " + packageName + " process: " + processName); - sPixelProps.forEach(PropImitationHooks::setPropValue); - } else if (sSpoofGapps && (packageName.equals(PACKAGE_WALLPAPER_EMOJI) - || packageName.equals(PACKAGE_LIVE_WALLPAPER))) { - dlog("Spoofing Pixel 7 Pro for: " + packageName + " process: " + processName); - sPixel7Props.forEach(PropImitationHooks::setPropValue); - } else if (sIsPhotos) { - dlog("Spoofing Pixel XL for Google Photos"); - sPixelXLProps.forEach(PropImitationHooks::setPropValue); - } else if (!sNetflixModel.isEmpty() && packageName.equals(PACKAGE_NETFLIX)) { - dlog("Setting model to " + sNetflixModel + " for Netflix"); - setPropValue("MODEL", sNetflixModel); - } - } - - private static void setPropValue(String key, Object value) { - try { - dlog("Setting prop " + key + " to " + value.toString()); - Field field = Build.class.getDeclaredField(key); - field.setAccessible(true); - field.set(null, value); - field.setAccessible(false); - } catch (NoSuchFieldException | IllegalAccessException e) { - Log.e(TAG, "Failed to set prop " + key, e); - } - } - - private static void setCertifiedPropsForGms() { - if (sCertifiedProps.length != 4) { - Log.e(TAG, "Insufficient array size for certified props: " - + sCertifiedProps.length + ", required 4"); - return; - } - final boolean was = isGmsAddAccountActivityOnTop(); - final TaskStackListener taskStackListener = new TaskStackListener() { - @Override - public void onTaskStackChanged() { - final boolean is = isGmsAddAccountActivityOnTop(); - if (is ^ was) { - dlog("GmsAddAccountActivityOnTop is:" + is + " was:" + was + - ", killing myself!"); // process will restart automatically later - Process.killProcess(Process.myPid()); - } - } - }; - if (!was) { - dlog("Spoofing build for GMS"); - setPropValue("DEVICE", sCertifiedProps[0]); - setPropValue("PRODUCT", sCertifiedProps[1]); - setPropValue("MODEL", sCertifiedProps[2]); - setPropValue("FINGERPRINT", sCertifiedProps[3]); - } else { - dlog("Skip spoofing build for GMS, because GmsAddAccountActivityOnTop"); - } - try { - ActivityTaskManager.getService().registerTaskStackListener(taskStackListener); - } catch (Exception e) { - Log.e(TAG, "Failed to register task stack listener!", e); - } - } - - private static boolean isGmsAddAccountActivityOnTop() { - try { - final ActivityTaskManager.RootTaskInfo focusedTask = - ActivityTaskManager.getService().getFocusedRootTaskInfo(); - return focusedTask != null && focusedTask.topActivity != null - && focusedTask.topActivity.equals(GMS_ADD_ACCOUNT_ACTIVITY); - } catch (Exception e) { - Log.e(TAG, "Unable to get top activity!", e); - } - return false; - } - - public static boolean shouldBypassTaskPermission(Context context) { - // GMS doesn't have MANAGE_ACTIVITY_TASKS permission - final int callingUid = Binder.getCallingUid(); - final int gmsUid; - try { - gmsUid = context.getPackageManager().getApplicationInfo(PACKAGE_GMS, 0).uid; - dlog("shouldBypassTaskPermission: gmsUid:" + gmsUid + " callingUid:" + callingUid); - } catch (Exception e) { - Log.e(TAG, "shouldBypassTaskPermission: unable to get gms uid", e); - return false; - } - return gmsUid == callingUid; - } - - private static boolean isCallerSafetyNet() { - return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace()) - .anyMatch(elem -> elem.getClassName().contains("DroidGuard")); - } - - public static void onEngineGetCertificateChain() { - // Check stack for SafetyNet or Play Integrity - if (isCallerSafetyNet() || sIsFinsky) { - dlog("Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky); - throw new UnsupportedOperationException(); - } - } - - public static boolean hasSystemFeature(String name, boolean def) { - if (sIsPhotos && def && sFeatureBlacklist.stream().anyMatch(name::contains)) { - dlog("Blocked system feature " + name + " for Google Photos"); - return false; - } - if (sIsASI && def && sTensorFeatureBlacklist.stream().anyMatch(name::contains)) { - dlog("Blocked system feature " + name + " for ASI"); - return false; - } - if (sIsPixelLauncher && def && sTensorFeatureBlacklist.stream().anyMatch(name::contains)) { - dlog("Blocked system feature " + name + " for Pixel Launcher"); - return false; - } - return def; - } - - private static void dlog(String msg) { - if (DEBUG) Log.d(TAG, "[" + sProcessName + "] " + msg); - } -} diff --git a/core/java/com/android/internal/util/custom/PixelPropsUtils.java b/core/java/com/android/internal/util/custom/PixelPropsUtils.java new file mode 100644 index 000000000000..60e7099c94b0 --- /dev/null +++ b/core/java/com/android/internal/util/custom/PixelPropsUtils.java @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2022 The Pixel Experience Project + * 2021-2022 crDroid Android Project + * (C) 2023 ArrowOS + * (C) 2023 The LibreMobileOS Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util.custom; + +import android.app.ActivityTaskManager; +import android.app.Application; +import android.app.TaskStackListener; +import android.content.ComponentName; +import android.content.Context; +import android.os.Binder; +import android.os.Build; +import android.os.Process; +import android.os.SystemProperties; +import android.util.Log; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class PixelPropsUtils { + + private static final String TAG = PixelPropsUtils.class.getSimpleName(); + private static final String DEVICE = "org.pixelexperience.device"; + + private static final String PACKAGE_GMS = "com.google.android.gms"; + private static final ComponentName GMS_ADD_ACCOUNT_ACTIVITY = ComponentName.unflattenFromString( + "com.google.android.gms/.auth.uiflows.minutemaid.MinuteMaidActivity"); + + private static final boolean DEBUG = false; + + private static final Map propsToChangeGeneric; + private static final Map propsToChangePixel7Pro; + private static final Map propsToChangePixel5; + private static final Map propsToChangePixelXL; + private static final Map> propsToKeep; + + private static final String[] packagesToChangePixel7Pro = { + "com.google.android.apps.privacy.wildlife", + "com.google.android.apps.wallpaper.pixel", + "com.google.android.apps.wallpaper", + "com.google.android.apps.subscriptions.red", + "com.google.pixel.livewallpaper", + "com.google.android.wallpaper.effects", + "com.google.android.apps.emojiwallpaper", + }; + + private static final String[] extraPackagesToChange = { + "com.android.chrome", + "com.breel.wallpapers20", + "com.nhs.online.nhsonline", + "com.netflix.mediaclient", + "com.nothing.smartcenter" + }; + + private static final String[] packagesToKeep = { + "com.google.android.dialer", + "com.google.android.euicc", + "com.google.ar.core", + "com.google.android.youtube", + "com.google.android.apps.youtube.kids", + "com.google.android.apps.youtube.music", + "com.google.android.apps.recorder", + "com.google.android.apps.wearables.maestro.companion", + "com.google.android.apps.tachyon", + "com.google.android.apps.tycho", + "com.google.android.as", + "com.google.android.gms", + "com.google.android.apps.restore" + }; + + private static final String[] customGoogleCameraPackages = { + "com.google.android.MTCL83", + "com.google.android.UltraCVM", + "com.google.android.apps.cameralite" + }; + + // Codenames for currently supported Pixels by Google + private static final String[] pixelCodenames = { + "felix", + "tangorpro", + "lynx", + "cheetah", + "panther", + "bluejay", + "oriole", + "raven", + "barbet", + "redfin", + "bramble", + "sunfish" + }; + + private static volatile boolean sIsGms, sIsFinsky, sIsPhotos; + + static { + propsToKeep = new HashMap<>(); + propsToKeep.put("com.google.android.settings.intelligence", new ArrayList<>(Collections.singletonList("FINGERPRINT"))); + propsToChangeGeneric = new HashMap<>(); + propsToChangeGeneric.put("TYPE", "user"); + propsToChangeGeneric.put("TAGS", "release-keys"); + propsToChangePixel7Pro = new HashMap<>(); + propsToChangePixel7Pro.put("BRAND", "google"); + propsToChangePixel7Pro.put("MANUFACTURER", "Google"); + propsToChangePixel7Pro.put("DEVICE", "cheetah"); + propsToChangePixel7Pro.put("PRODUCT", "cheetah"); + propsToChangePixel7Pro.put("MODEL", "Pixel 7 Pro"); + propsToChangePixel7Pro.put("FINGERPRINT", "google/cheetah/cheetah:13/TQ3A.230805.001/10316531:user/release-keys"); + propsToChangePixel5 = new HashMap<>(); + propsToChangePixel5.put("BRAND", "google"); + propsToChangePixel5.put("MANUFACTURER", "Google"); + propsToChangePixel5.put("DEVICE", "redfin"); + propsToChangePixel5.put("PRODUCT", "redfin"); + propsToChangePixel5.put("MODEL", "Pixel 5"); + propsToChangePixel5.put("FINGERPRINT", "google/redfin/redfin:13/TQ3A.230805.001/10316531:user/release-keys"); + propsToChangePixelXL = new HashMap<>(); + propsToChangePixelXL.put("BRAND", "google"); + propsToChangePixelXL.put("MANUFACTURER", "Google"); + propsToChangePixelXL.put("DEVICE", "marlin"); + propsToChangePixelXL.put("PRODUCT", "marlin"); + propsToChangePixelXL.put("MODEL", "Pixel XL"); + propsToChangePixelXL.put("FINGERPRINT", "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys"); + } + + private static boolean isGoogleCameraPackage(String packageName) { + return packageName.startsWith("com.google.android.GoogleCamera") || + Arrays.asList(customGoogleCameraPackages).contains(packageName); + } + + public static boolean setPropsForGms(String packageName) { + if (packageName.equals("com.android.vending")) { + sIsFinsky = true; + } + if (packageName.equals(PACKAGE_GMS) + || packageName.toLowerCase().contains("androidx.test") + || packageName.equalsIgnoreCase("com.google.android.apps.restore")) { + final String processName = Application.getProcessName(); + if (processName.toLowerCase().contains("unstable") + || processName.toLowerCase().contains("pixelmigrate") + || processName.toLowerCase().contains("instrumentation")) { + sIsGms = true; + + final boolean was = isGmsAddAccountActivityOnTop(); + final TaskStackListener taskStackListener = new TaskStackListener() { + @Override + public void onTaskStackChanged() { + final boolean is = isGmsAddAccountActivityOnTop(); + if (is ^ was) { + dlog("GmsAddAccountActivityOnTop is:" + is + " was:" + was + ", killing myself!"); + // process will restart automatically later + Process.killProcess(Process.myPid()); + } + } + }; + try { + ActivityTaskManager.getService().registerTaskStackListener(taskStackListener); + } catch (Exception e) { + Log.e(TAG, "Failed to register task stack listener!", e); + } + if (was) return true; + + dlog("Spoofing build for GMS"); + // Alter build parameters to pixel 2 for avoiding hardware attestation enforcement + setBuildField("DEVICE", "walleye"); + setBuildField("FINGERPRINT", "google/walleye/walleye:8.1.0/OPM1.171019.011/4448085:user/release-keys"); + setBuildField("MODEL", "Pixel 2"); + setBuildField("PRODUCT", "walleye"); + setVersionField("DEVICE_INITIAL_SDK_INT", Build.VERSION_CODES.O); + return true; + } + } + return false; + } + + public static void setProps(String packageName) { + propsToChangeGeneric.forEach((k, v) -> setPropValue(k, v)); + if (packageName == null || packageName.isEmpty()) { + return; + } + if (setPropsForGms(packageName)){ + return; + } + if (Arrays.asList(packagesToKeep).contains(packageName)) { + return; + } + if (isGoogleCameraPackage(packageName)) { + return; + } + + Map propsToChange = new HashMap<>(); + + if (packageName.startsWith("com.google.") + || packageName.startsWith("com.samsung.") + || Arrays.asList(extraPackagesToChange).contains(packageName)) { + + boolean isPixelDevice = Arrays.asList(pixelCodenames).contains(SystemProperties.get(DEVICE)); + + if (packageName.equals("com.google.android.apps.photos")) { + propsToChange.putAll(propsToChangePixelXL); + } else if (isPixelDevice) { + return; + } else { + if (Arrays.asList(packagesToChangePixel7Pro).contains(packageName)) { + propsToChange.putAll(propsToChangePixel7Pro); + } else { + propsToChange.putAll(propsToChangePixel5); + } + } + + if (DEBUG) Log.d(TAG, "Defining props for: " + packageName); + for (Map.Entry prop : propsToChange.entrySet()) { + String key = prop.getKey(); + Object value = prop.getValue(); + if (propsToKeep.containsKey(packageName) && propsToKeep.get(packageName).contains(key)) { + if (DEBUG) Log.d(TAG, "Not defining " + key + " prop for: " + packageName); + continue; + } + if (DEBUG) Log.d(TAG, "Defining " + key + " prop for: " + packageName); + setPropValue(key, value); + } + // Set proper indexing fingerprint + if (packageName.equals("com.google.android.settings.intelligence")) { + setPropValue("FINGERPRINT", Build.VERSION.INCREMENTAL); + } + } + } + + private static void setPropValue(String key, Object value) { + try { + if (DEBUG) Log.d(TAG, "Defining prop " + key + " to " + value.toString()); + Field field = Build.class.getDeclaredField(key); + field.setAccessible(true); + field.set(null, value); + field.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException e) { + Log.e(TAG, "Failed to set prop " + key, e); + } + } + + private static void setBuildField(String key, String value) { + try { + // Unlock + Field field = Build.class.getDeclaredField(key); + field.setAccessible(true); + + // Edit + field.set(null, value); + + // Lock + field.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException e) { + Log.e(TAG, "Failed to spoof Build." + key, e); + } + } + + private static void setVersionField(String key, Object value) { + try { + // Unlock + if (DEBUG) Log.d(TAG, "Defining version field " + key + " to " + value.toString()); + Field field = Build.VERSION.class.getDeclaredField(key); + field.setAccessible(true); + + // Edit + field.set(null, value); + + // Lock + field.setAccessible(false); + } catch (NoSuchFieldException | IllegalAccessException e) { + Log.e(TAG, "Failed to set version field " + key, e); + } + } + + private static boolean isGmsAddAccountActivityOnTop() { + try { + final ActivityTaskManager.RootTaskInfo focusedTask = + ActivityTaskManager.getService().getFocusedRootTaskInfo(); + return focusedTask != null && focusedTask.topActivity != null + && focusedTask.topActivity.equals(GMS_ADD_ACCOUNT_ACTIVITY); + } catch (Exception e) { + Log.e(TAG, "Unable to get top activity!", e); + } + return false; + } + + public static boolean shouldBypassTaskPermission(Context context) { + // GMS doesn't have MANAGE_ACTIVITY_TASKS permission + final int callingUid = Binder.getCallingUid(); + final int gmsUid; + try { + gmsUid = context.getPackageManager().getApplicationInfo(PACKAGE_GMS, 0).uid; + dlog("shouldBypassTaskPermission: gmsUid:" + gmsUid + " callingUid:" + callingUid); + } catch (Exception e) { + Log.e(TAG, "shouldBypassTaskPermission: unable to get gms uid", e); + return false; + } + return gmsUid == callingUid; + } + + private static boolean isCallerSafetyNet() { + return sIsGms && Arrays.stream(Thread.currentThread().getStackTrace()) + .anyMatch(elem -> elem.getClassName().contains("DroidGuard")); + } + + public static void onEngineGetCertificateChain() { + // Check stack for SafetyNet or Play Integrity + if (isCallerSafetyNet() || sIsFinsky) { + Log.i(TAG, "Blocked key attestation sIsGms=" + sIsGms + " sIsFinsky=" + sIsFinsky); + throw new UnsupportedOperationException(); + } + } + + public static void dlog(String msg) { + if (DEBUG) Log.d(TAG, msg); + } + +} diff --git a/core/res/res/values/custom_config.xml b/core/res/res/values/custom_config.xml index 1c4af2965ae1..2359fe0f2ae2 100644 --- a/core/res/res/values/custom_config.xml +++ b/core/res/res/values/custom_config.xml @@ -48,26 +48,6 @@ - - - - - - - - - - - - - false - diff --git a/core/res/res/values/custom_symbols.xml b/core/res/res/values/custom_symbols.xml index cf31417f3dfb..4e1b361efe50 100644 --- a/core/res/res/values/custom_symbols.xml +++ b/core/res/res/values/custom_symbols.xml @@ -34,12 +34,6 @@ - - - - - - diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java index ac1508298b6b..88717cfff0e9 100644 --- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java @@ -42,7 +42,6 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.util.PropImitationHooks; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -78,6 +77,8 @@ import javax.crypto.SecretKey; +import com.android.internal.util.custom.PixelPropsUtils; + /** * A java.security.KeyStore interface for the Android KeyStore. An instance of * it can be created via the {@link java.security.KeyStore#getInstance(String) @@ -165,7 +166,7 @@ private KeyEntryResponse getKeyMetadata(String alias) { @Override public Certificate[] engineGetCertificateChain(String alias) { - PropImitationHooks.onEngineGetCertificateChain(); + PixelPropsUtils.onEngineGetCertificateChain(); KeyEntryResponse response = getKeyMetadata(alias); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 5ae337f8320c..8a556514a5c9 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -270,8 +270,8 @@ import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.usage.AppStandbyInternal; -import com.android.internal.util.PropImitationHooks; import com.android.internal.util.custom.cutout.CutoutFullscreenController; +import com.android.internal.util.custom.PixelPropsUtils; import java.io.BufferedReader; import java.io.File; @@ -1972,7 +1972,7 @@ public void setFrontActivityScreenCompatMode(int mode) { @Override public RootTaskInfo getFocusedRootTaskInfo() throws RemoteException { - if (!PropImitationHooks.shouldBypassTaskPermission(mContext)) { + if (!PixelPropsUtils.shouldBypassTaskPermission(mContext)) { enforceTaskPermission("getFocusedRootTaskInfo()"); } final long ident = Binder.clearCallingIdentity(); @@ -3004,7 +3004,7 @@ public void moveRootTaskToDisplay(int taskId, int displayId) { /** Sets the task stack listener that gets callbacks when a task stack changes. */ @Override public void registerTaskStackListener(ITaskStackListener listener) { - if (!PropImitationHooks.shouldBypassTaskPermission(mContext)) { + if (!PixelPropsUtils.shouldBypassTaskPermission(mContext)) { enforceTaskPermission("registerTaskStackListener()"); } mTaskChangeNotificationController.registerTaskStackListener(listener);