Compare commits

..

No commits in common. "82edcb62604de052997cf05df2f5b98f9ea4f5af" and "83c865fd13799fddb832704d57761dc624726fc8" have entirely different histories.

8 changed files with 0 additions and 803 deletions

View file

@ -834,104 +834,8 @@ public class ApplicationPackageManager extends PackageManager {
}
};
private static final String[] pTensorCodenames = {
"comet",
"komodo",
"caiman",
"tokay",
"akita",
"husky",
"shiba",
"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[] featuresPixelOthers = {
"com.google.android.feature.ASI",
"com.google.android.feature.ANDROID_ONE_EXPERIENCE",
"com.google.android.feature.GOOGLE_FI_BUNDLED",
"com.google.android.feature.LILY_EXPERIENCE",
"com.google.android.feature.TURBO_PRELOAD",
"com.google.android.feature.WELLBEING",
"com.google.lens.feature.IMAGE_INTEGRATION",
"com.google.lens.feature.CAMERA_INTEGRATION",
"com.google.photos.trust_debug_certs",
"com.google.android.feature.AER_OPTIMIZED",
"com.google.android.feature.NEXT_GENERATION_ASSISTANT",
"android.software.game_service",
"com.google.android.feature.EXCHANGE_6_2",
"com.google.android.apps.dialer.call_recording_audio",
"com.google.android.apps.dialer.SUPPORTED"
};
private static final String[] featuresTensor = {
"com.google.android.feature.PIXEL_2025_EXPERIENCE",
"com.google.android.feature.PIXEL_2025_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2024_EXPERIENCE",
"com.google.android.feature.PIXEL_2024_MIDYEAR_EXPERIENCE",
"com.google.android.feature.PIXEL_2023_EXPERIENCE",
"com.google.android.feature.PIXEL_2023_MIDYEAR_EXPERIENCE",
"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",
"com.google.android.feature.PIXEL_EXPERIENCE",
"com.google.android.feature.GOOGLE_BUILD",
"com.google.android.feature.GOOGLE_EXPERIENCE"
};
@Override
public boolean hasSystemFeature(String name, int version) {
String packageName = ActivityThread.currentPackageName();
if (packageName != null
&& (packageName.equals("com.google.android.googlequicksearchbox")
|| packageName.equals("com.google.android.apps.nexuslauncher"))) {
if (Arrays.asList(featuresPixel).contains(name)) return true;
if (Arrays.asList(featuresPixelOthers).contains(name)) return true;
if (Arrays.asList(featuresTensor).contains(name)) return true;
if (Arrays.asList(featuresNexus).contains(name)) return true;
}
if (packageName != null
&& packageName.equals("com.google.android.apps.photos")
&& SystemProperties.getBoolean("persist.sys.pixelprops.gphotos", true)) {
if (Arrays.asList(featuresPixel).contains(name)) return false;
if (Arrays.asList(featuresPixelOthers).contains(name)) return true;
if (Arrays.asList(featuresTensor).contains(name)) return false;
if (Arrays.asList(featuresNexus).contains(name)) return true;
}
if (name != null && Arrays.asList(featuresTensor).contains(name)
&& !Arrays.asList(pTensorCodenames).contains(SystemProperties.get("ro.product.device"))) {
return false;
}
if (Arrays.asList(featuresPixel).contains(name)) return true;
if (Arrays.asList(featuresPixelOthers).contains(name)) return true;
return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version));
}

View file

@ -75,8 +75,6 @@ import java.util.Objects;
import java.util.StringJoiner;
import java.util.concurrent.TimeoutException;
import com.android.internal.util.crdroid.PixelPropsUtils;
/**
* Base class for implementing application instrumentation code. When running
* with instrumentation turned on, this class will be instantiated for you
@ -1358,7 +1356,6 @@ public class Instrumentation {
Application app = getFactory(context.getPackageName())
.instantiateApplication(cl, className);
app.attach(context);
PixelPropsUtils.setProps(context);
return app;
}
@ -1376,7 +1373,6 @@ public class Instrumentation {
ClassNotFoundException {
Application app = (Application)clazz.newInstance();
app.attach(context);
PixelPropsUtils.setProps(context);
return app;
}

View file

@ -1,470 +0,0 @@
/*
* Copyright (C) 2020 The Pixel Experience Project
* 2021-2025 crDroid Android Project
*
* 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.crdroid;
import android.app.Application;
import android.content.Context;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Environment;
import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Log;
import com.android.internal.R;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* @hide
*/
public final class PixelPropsUtils {
private static final String TAG = PixelPropsUtils.class.getSimpleName();
private static final String DEVICE = "ro.product.device";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private static final String DATA_FILE = "gms_certified_props.json";
private static final String SPOOF_PIXEL_PI = "persist.sys.pixelprops.pi";
private static final String SPOOF_PIXEL_GAMES = "persist.sys.pixelprops.games";
private static final String SPOOF_PIXEL_GPHOTOS = "persist.sys.pixelprops.gphotos";
private static final String SPOOF_PIXEL_NETFLIX = "persist.sys.pixelprops.netflix";
private static final Map<String, Object> propsToChangeGeneric;
private static final Map<String, Object> propsToChangePixel9ProXL;
private static final Map<String, Object> propsToChangePixelTablet;
private static final Map<String, Object> propsToChangePixelXL;
private static final Map<String, Object> propsToChangeROG6;
private static final Map<String, Object> propsToChangeLenovoY700;
private static final Map<String, Object> propsToChangeOP8P;
private static final Map<String, Object> propsToChangeOP9P;
private static final Map<String, Object> propsToChangeMI11TP;
private static final Map<String, Object> propsToChangeMI13P;
private static final Map<String, Object> propsToChangeF5;
private static final Map<String, Object> propsToChangeBS4;
private static final Map<String, Object> propsToChangeS24U;
// Packages to Spoof as the most recent Pixel device
private static final String[] packagesToChangeRecentPixel = {
"com.android.vending",
"com.google.android.aicore",
"com.google.android.apps.aiwallpapers",
"com.google.android.apps.bard",
"com.google.android.apps.customization.pixel",
"com.google.android.apps.emojiwallpaper",
"com.google.android.apps.nexuslauncher",
"com.google.android.apps.photos",
"com.google.android.apps.pixel.agent",
"com.google.android.apps.pixel.creativeassistant",
"com.google.android.apps.pixel.support",
"com.google.android.apps.privacy.wildlife",
"com.google.android.apps.wallpaper",
"com.google.android.apps.wallpaper.pixel",
"com.google.android.apps.weather",
"com.google.android.gms",
"com.google.android.googlequicksearchbox",
"com.google.android.settings.intelligence",
"com.google.android.wallpaper.effects",
"com.google.pixel.livewallpaper",
"com.netflix.mediaclient",
"com.nhs.online.nhsonline"
};
// Packages to Spoof as ROG Phone 6
private static final String[] packagesToChangeROG6 = {
"com.ea.gp.fifamobile",
"com.gameloft.android.ANMP.GloftA9HM",
"com.madfingergames.legends",
"com.pearlabyss.blackdesertm",
"com.pearlabyss.blackdesertm.gl"
};
// Packages to Spoof as Lenovo Y700
private static final String[] packagesToChangeLenovoY700 = {
"com.activision.callofduty.shooter",
"com.garena.game.codm",
"com.tencent.tmgp.kr.codm",
"com.vng.codmvn"
};
// Packages to Spoof as OnePlus 8 Pro
private static final String[] packagesToChangeOP8P = {
"com.netease.lztgglobal",
"com.riotgames.league.wildrift",
"com.riotgames.league.wildrifttw",
"com.riotgames.league.wildriftvn",
"com.riotgames.league.teamfighttactics",
"com.riotgames.league.teamfighttacticstw",
"com.riotgames.league.teamfighttacticsvn"
};
// Packages to Spoof as OnePlus 9 Pro
private static final String[] packagesToChangeOP9P = {
"com.epicgames.fortnite",
"com.epicgames.portal",
"com.tencent.lolm"
};
// Packages to Spoof as Mi 11T Pro
private static final String[] packagesToChangeMI11TP = {
"com.ea.gp.apexlegendsmobilefps",
"com.levelinfinite.hotta.gp",
"com.supercell.clashofclans",
"com.vng.mlbbvn"
};
// Packages to Spoof as Xiaomi 13 Pro
private static final String[] packagesToChangeMI13P = {
"com.levelinfinite.sgameGlobal",
"com.tencent.tmgp.sgame"
};
// Packages to Spoof as POCO F5
private static final String[] packagesToChangeF5 = {
"com.dts.freefiremax",
"com.dts.freefireth",
"com.mobile.legends"
};
// Packages to Spoof as Black Shark 4
private static final String[] packagesToChangeBS4 = {
"com.proximabeta.mf.uamo"
};
// Packages to Spoof as Samsung S24 Ultra
private static final String[] packagesToChangeS24U = {
"com.pubg.imobile",
"com.pubg.krmobile",
"com.rekoo.pubgm",
"com.tencent.ig",
"com.tencent.tmgp.pubgmhd",
"com.vng.pubgmobile"
};
private static volatile boolean sIsFinsky = false;
private static volatile List<String> sCertifiedProps = new ArrayList<>();
static {
propsToChangeGeneric = new HashMap<>();
propsToChangeGeneric.put("TYPE", "user");
propsToChangeGeneric.put("TAGS", "release-keys");
propsToChangePixel9ProXL = new HashMap<>();
propsToChangePixel9ProXL.put("BRAND", "google");
propsToChangePixel9ProXL.put("MANUFACTURER", "Google");
propsToChangePixel9ProXL.put("DEVICE", "komodo");
propsToChangePixel9ProXL.put("PRODUCT", "komodo");
propsToChangePixel9ProXL.put("HARDWARE", "komodo");
propsToChangePixel9ProXL.put("MODEL", "Pixel 9 Pro XL");
propsToChangePixel9ProXL.put("ID", "BP1A.250405.007");
propsToChangePixel9ProXL.put("FINGERPRINT", "google/komodo/komodo:15/BP1A.250405.007/13240079:user/release-keys");
propsToChangePixelTablet = new HashMap<>();
propsToChangePixelTablet.put("BRAND", "google");
propsToChangePixelTablet.put("MANUFACTURER", "Google");
propsToChangePixelTablet.put("DEVICE", "tangorpro");
propsToChangePixelTablet.put("PRODUCT", "tangorpro");
propsToChangePixelTablet.put("HARDWARE", "tangorpro");
propsToChangePixelTablet.put("MODEL", "Pixel Tablet");
propsToChangePixelTablet.put("ID", "BP1A.250405.007");
propsToChangePixelTablet.put("FINGERPRINT", "google/tangorpro/tangorpro:15/BP1A.250405.007/13240079:user/release-keys");
propsToChangePixelXL = new HashMap<>();
propsToChangePixelXL.put("BRAND", "google");
propsToChangePixelXL.put("MANUFACTURER", "Google");
propsToChangePixelXL.put("DEVICE", "marlin");
propsToChangePixelXL.put("PRODUCT", "marlin");
propsToChangePixelXL.put("HARDWARE", "marlin");
propsToChangePixelXL.put("MODEL", "Pixel XL");
propsToChangePixelXL.put("ID", "QP1A.191005.007.A3");
propsToChangePixelXL.put("FINGERPRINT", "google/marlin/marlin:10/QP1A.191005.007.A3/5972272:user/release-keys");
propsToChangeROG6 = new HashMap<>();
propsToChangeROG6.put("BRAND", "asus");
propsToChangeROG6.put("MANUFACTURER", "asus");
propsToChangeROG6.put("DEVICE", "AI2201");
propsToChangeROG6.put("MODEL", "ASUS_AI2201");
propsToChangeLenovoY700 = new HashMap<>();
propsToChangeLenovoY700.put("MODEL", "Lenovo TB-9707F");
propsToChangeLenovoY700.put("MANUFACTURER", "lenovo");
propsToChangeOP8P = new HashMap<>();
propsToChangeOP8P.put("MODEL", "IN2020");
propsToChangeOP8P.put("MANUFACTURER", "OnePlus");
propsToChangeOP9P = new HashMap<>();
propsToChangeOP9P.put("MODEL", "LE2123");
propsToChangeOP9P.put("MANUFACTURER", "OnePlus");
propsToChangeMI11TP = new HashMap<>();
propsToChangeMI11TP.put("MODEL", "2107113SI");
propsToChangeMI11TP.put("MANUFACTURER", "Xiaomi");
propsToChangeMI13P = new HashMap<>();
propsToChangeMI13P.put("BRAND", "Xiaomi");
propsToChangeMI13P.put("MANUFACTURER", "Xiaomi");
propsToChangeMI13P.put("MODEL", "2210132C");
propsToChangeF5 = new HashMap<>();
propsToChangeF5.put("MODEL", "23049PCD8G");
propsToChangeF5.put("MANUFACTURER", "Xiaomi");
propsToChangeBS4 = new HashMap<>();
propsToChangeBS4.put("MODEL", "2SM-X706B");
propsToChangeBS4.put("MANUFACTURER", "blackshark");
propsToChangeS24U = new HashMap<>();
propsToChangeS24U.put("BRAND", "SAMSUNG");
propsToChangeS24U.put("DEVICE", "S24 ULTRA");
propsToChangeS24U.put("MANUFACTURER", "SM-S928B");
propsToChangeS24U.put("MODEL", "SM-S928B");
}
public static void setProps(Context context) {
final String packageName = context.getPackageName();
if (packageName == null || packageName.isEmpty()) {
return;
}
propsToChangeGeneric.forEach((k, v) -> setPropValue(k, v));
if (Arrays.asList(packagesToChangeRecentPixel).contains(packageName)) {
Map<String, Object> propsToChange = new HashMap<>();
if (packageName.equals("com.google.android.apps.photos")) {
if (SystemProperties.getBoolean(SPOOF_PIXEL_GPHOTOS, true)) {
propsToChange.putAll(propsToChangePixelXL);
}
} else if (packageName.equals("com.netflix.mediaclient") &&
!SystemProperties.getBoolean(SPOOF_PIXEL_NETFLIX, false)) {
if (DEBUG) Log.d(TAG, "Netflix spoofing disabled by system prop");
return;
} else if (packageName.equals("com.android.vending")) {
sIsFinsky = true;
return;
} else if (packageName.equals("com.google.android.gms")) {
final String processName = Application.getProcessName().toLowerCase();
if (processName.contains("unstable")) {
spoofBuildGms(context);
return;
}
return;
} else if (packageName.equals("com.google.android.settings.intelligence")) {
setPropValue("FINGERPRINT", Build.VERSION.INCREMENTAL);
return;
} else {
if (isDeviceTablet(context.getApplicationContext())) {
propsToChange.putAll(propsToChangePixelTablet);
} else {
propsToChange.putAll(propsToChangePixel9ProXL);
}
}
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChange.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
if (DEBUG) Log.d(TAG, "Defining " + key + " prop for: " + packageName);
setPropValue(key, value);
}
} else {
if (!SystemProperties.getBoolean(SPOOF_PIXEL_GAMES, false))
return;
if (Arrays.asList(packagesToChangeROG6).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeROG6.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeLenovoY700).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeLenovoY700.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeOP8P).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeOP8P.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeOP9P).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeOP9P.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeMI11TP).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeMI11TP.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeMI13P).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeMI13P.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeF5).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeF5.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeBS4).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeBS4.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
} else if (Arrays.asList(packagesToChangeS24U).contains(packageName)) {
if (DEBUG) Log.d(TAG, "Defining props for: " + packageName);
for (Map.Entry<String, Object> prop : propsToChangeS24U.entrySet()) {
String key = prop.getKey();
Object value = prop.getValue();
setPropValue(key, value);
}
}
}
}
private static boolean isDeviceTablet(Context context) {
if (context == null) {
return false;
}
Configuration config = context.getResources().getConfiguration();
boolean isTablet = (config.smallestScreenWidthDp >= 600);
return isTablet;
}
private static void setPropValue(String key, Object value) {
setPropValue(key, value.toString());
}
private static void setPropValue(String key, String value) {
try {
if (DEBUG) Log.d(TAG, "Defining prop " + key + " to " + value);
Class<?> clazz = Build.class;
if (key.startsWith("VERSION.")) {
clazz = Build.VERSION.class;
key = key.substring(8);
}
Field field = clazz.getDeclaredField(key);
field.setAccessible(true);
// Determine the field type and parse the value accordingly.
if (field.getType().equals(Integer.TYPE)) {
field.set(null, Integer.parseInt(value));
} else if (field.getType().equals(Long.TYPE)) {
field.set(null, Long.parseLong(value));
} else {
field.set(null, value);
}
field.setAccessible(false);
} catch (Exception e) {
Log.e(TAG, "Failed to set prop " + key, e);
}
}
private static void spoofBuildGms(Context context) {
if (!SystemProperties.getBoolean(SPOOF_PIXEL_PI, true))
return;
File dataFile = new File(Environment.getDataSystemDirectory(), DATA_FILE);
String savedProps = readFromFile(dataFile);
if (TextUtils.isEmpty(savedProps)) {
Log.d(TAG, "Parsing props locally - data file unavailable");
sCertifiedProps = Arrays.asList(context.getResources().getStringArray(R.array.config_certifiedBuildProperties));
} else {
Log.d(TAG, "Parsing props fetched by attestation service");
try {
JSONObject parsedProps = new JSONObject(savedProps);
Iterator<String> keys = parsedProps.keys();
while (keys.hasNext()) {
String key = keys.next();
String value = parsedProps.getString(key);
sCertifiedProps.add(key + ":" + value);
}
} catch (JSONException e) {
Log.e(TAG, "Error parsing JSON data", e);
Log.d(TAG, "Parsing props locally as fallback");
sCertifiedProps = Arrays.asList(context.getResources().getStringArray(R.array.config_certifiedBuildProperties));
}
}
// Alter build parameters to avoid hardware attestation enforcement
for (String entry : sCertifiedProps) {
// Each entry must be of the format FIELD:value
final String[] fieldAndProp = entry.split(":", 2);
if (fieldAndProp.length != 2) {
Log.e(TAG, "Invalid entry in certified props: " + entry);
continue;
}
setPropValue(fieldAndProp[0], fieldAndProp[1]);
}
}
private static String readFromFile(File file) {
StringBuilder content = new StringBuilder();
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (IOException e) {
Log.e(TAG, "Error reading from file", e);
}
}
return content.toString();
}
private static boolean isCallerSafetyNet() {
return Arrays.stream(Thread.currentThread().getStackTrace())
.anyMatch(elem -> elem.getClassName().toLowerCase()
.contains("droidguard"));
}
public static void onEngineGetCertificateChain() {
if (!SystemProperties.getBoolean(SPOOF_PIXEL_PI, true))
return;
// Check stack for SafetyNet or Play Integrity
if (isCallerSafetyNet() || sIsFinsky) {
Log.i(TAG, "Blocked key attestation");
throw new UnsupportedOperationException();
}
}
}

View file

@ -1,21 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-FileCopyrightText: 2016-2025 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<resources>
<!-- Build properties from a GMS certified device against current platform SPL level -->
<string-array name="config_certifiedBuildProperties" translatable="false">
<!--
Each entry must be of the format
FIELD:value
with the field belonging to android.os.Build or android.os.Build.VERSION class.
Example:
<item>BRAND:foo</item>
<item>DEVICE:bar</item>
<item>FINGERPRINT:foo/bar/bar:1.0/lorem/ipsum:dolor/sit-amet</item>
<item>VERSION.RELEASE:1.0</item>
-->
</string-array>
</resources>

View file

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
SPDX-FileCopyrightText: 2016-2025 crDroid Android Project
SPDX-License-Identifier: Apache-2.0
-->
<resources>
<!-- Build properties from a GMS certified device against current platform SPL level -->
<java-symbol type="array" name="config_certifiedBuildProperties" />
</resources>

View file

@ -90,8 +90,6 @@ import java.util.NoSuchElementException;
import javax.crypto.SecretKey;
import com.android.internal.util.crdroid.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)
@ -180,8 +178,6 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
@Override
public Certificate[] engineGetCertificateChain(String alias) {
PixelPropsUtils.onEngineGetCertificateChain();
KeyEntryResponse response = getKeyMetadata(alias);
if (response == null || response.metadata.certificate == null) {

View file

@ -1,192 +0,0 @@
/*
* Copyright (C) 2024 The LeafOS Project
* Copyright (C) 2024 crDroid Android Project
*
* SPDX-License-Identifier: Apache-2.0
*
*/
package com.android.server.crdroid;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.os.Environment;
import android.os.SystemProperties;
import android.util.Log;
import com.android.server.SystemService;
import com.android.internal.util.crdroid.Utils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public final class AttestationService extends SystemService {
private static final String TAG = AttestationService.class.getSimpleName();
private static final String API = "https://raw.githubusercontent.com/crdroidandroid/android_vendor_certification/refs/heads/15.0/gms_certified_props.json";
private static final String SPOOF_PIXEL_PI = "persist.sys.pixelprops.pi";
private static final String DATA_FILE = "gms_certified_props.json";
private static final long INITIAL_DELAY = 0; // Start immediately on boot
private static final long INTERVAL = 8; // Interval in hours
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
private final File mDataFile;
private final ScheduledExecutorService mScheduler;
private final ConnectivityManager mConnectivityManager;
private final FetchGmsCertifiedProps mFetchRunnable;
private boolean mPendingUpdate;
public AttestationService(Context context) {
super(context);
mContext = context;
mDataFile = new File(Environment.getDataSystemDirectory(), DATA_FILE);
mFetchRunnable = new FetchGmsCertifiedProps();
mScheduler = Executors.newSingleThreadScheduledExecutor();
mConnectivityManager =
(ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
registerNetworkCallback();
}
@Override
public void onStart() {}
@Override
public void onBootPhase(int phase) {
if (Utils.isPackageInstalled(mContext, "com.google.android.gms")
&& phase == PHASE_BOOT_COMPLETED) {
Log.i(TAG, "Scheduling the service");
mScheduler.scheduleAtFixedRate(
mFetchRunnable, INITIAL_DELAY, INTERVAL, TimeUnit.HOURS);
}
}
private String readFromFile(File file) {
StringBuilder content = new StringBuilder();
if (file.exists()) {
try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
String line;
while ((line = reader.readLine()) != null) {
content.append(line);
}
} catch (IOException e) {
Log.e(TAG, "Error reading from file", e);
}
}
return content.toString();
}
private void writeToFile(File file, String data) {
try (FileWriter writer = new FileWriter(file)) {
writer.write(data);
// Set -rw-r--r-- (644) permission to make it readable by others.
file.setReadable(true, false);
} catch (IOException e) {
Log.e(TAG, "Error writing to file", e);
}
}
private String fetchProps() {
try {
URL url = new URI(API).toURL();
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
urlConnection.setConnectTimeout(10000);
urlConnection.setReadTimeout(10000);
try (BufferedReader reader =
new BufferedReader(new InputStreamReader(urlConnection.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
return response.toString();
}
} finally {
urlConnection.disconnect();
}
} catch (Exception e) {
Log.e(TAG, "Error making an API request", e);
return null;
}
}
private void dlog(String message) {
if (DEBUG) Log.d(TAG, message);
}
private boolean isInternetConnected() {
Network network = mConnectivityManager.getActiveNetwork();
if (network != null) {
NetworkCapabilities capabilities = mConnectivityManager.getNetworkCapabilities(network);
return capabilities != null && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
return false;
}
private void registerNetworkCallback() {
mConnectivityManager.registerDefaultNetworkCallback(new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(Network network) {
Log.i(TAG, "Internet is available, resuming update");
if (mPendingUpdate) {
mScheduler.schedule(mFetchRunnable, 0, TimeUnit.SECONDS);
}
}
});
}
private class FetchGmsCertifiedProps implements Runnable {
@Override
public void run() {
if (!SystemProperties.getBoolean(SPOOF_PIXEL_PI, true)) {
mPendingUpdate = false;
return;
}
try {
dlog("FetchGmsCertifiedProps started");
if (!isInternetConnected()) {
Log.e(TAG, "Internet is unavailable, deferring update");
mPendingUpdate = true;
return;
}
mPendingUpdate = false;
String savedProps = readFromFile(mDataFile);
String props = fetchProps();
if (props != null && !savedProps.equals(props)) {
dlog("Found new props");
writeToFile(mDataFile, props);
dlog("FetchGmsCertifiedProps completed");
} else {
dlog("No change in props");
}
} catch (Exception e) {
Log.e(TAG, "Error in FetchGmsCertifiedProps", e);
}
}
}
}

View file

@ -163,7 +163,6 @@ import com.android.server.contextualsearch.ContextualSearchManagerService;
import com.android.server.coverage.CoverageService;
import com.android.server.cpu.CpuMonitorService;
import com.android.server.crashrecovery.CrashRecoveryAdaptor;
import com.android.server.crdroid.AttestationService;
import com.android.server.credentials.CredentialManagerService;
import com.android.server.criticalevents.CriticalEventLog;
import com.android.server.devicepolicy.DevicePolicyManagerService;
@ -2758,11 +2757,6 @@ public final class SystemServer implements Dumpable {
mSystemServiceManager.startService(BackgroundInstallControlService.class);
t.traceEnd();
}
// AttestationService
t.traceBegin("AttestationService");
mSystemServiceManager.startService(AttestationService.class);
t.traceEnd();
}
t.traceBegin("StartMediaProjectionManager");