diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/Build.java b/play-services-base-core/src/main/java/org/microg/gms/common/Build.java deleted file mode 100644 index c297c295..00000000 --- a/play-services-base-core/src/main/java/org/microg/gms/common/Build.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2013-2017 microG Project Team - * - * 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 org.microg.gms.common; - -import android.annotation.TargetApi; - -import java.util.Locale; -import java.util.Random; - -// TODO: Make flexible -public class Build { - public String board = android.os.Build.BOARD; - public String bootloader = android.os.Build.BOOTLOADER; - public String brand = android.os.Build.BRAND; - public String cpu_abi = android.os.Build.CPU_ABI; - public String cpu_abi2 = android.os.Build.CPU_ABI2; - @TargetApi(21) - public String[] supported_abis = android.os.Build.VERSION.SDK_INT >= 21 ? android.os.Build.SUPPORTED_ABIS : new String[0]; - public String device = android.os.Build.DEVICE; - public String display = android.os.Build.DISPLAY; - public String fingerprint = android.os.Build.FINGERPRINT; - public String hardware = android.os.Build.HARDWARE; - public String host = android.os.Build.HOST; - public String id = android.os.Build.ID; - public String manufacturer = android.os.Build.MANUFACTURER; - public String model = android.os.Build.MODEL; - public String product = android.os.Build.PRODUCT; - public String radio = android.os.Build.RADIO; - public String serial = generateSerialNumber(); // TODO: static - public String tags = android.os.Build.TAGS; - public long time = android.os.Build.TIME; - public String type = android.os.Build.TYPE; - public String user = android.os.Build.USER; - public String version_codename = android.os.Build.VERSION.CODENAME; - public String version_incremental = android.os.Build.VERSION.INCREMENTAL; - public String version_release = android.os.Build.VERSION.RELEASE; - public String version_sdk = android.os.Build.VERSION.SDK; - public int version_sdk_int = android.os.Build.VERSION.SDK_INT; - - private String generateSerialNumber() { - String serial = "008741"; - Random rand = new Random(); - for (int i = 0; i < 10; i++) - serial += Integer.toString(rand.nextInt(16), 16); - serial = serial.toUpperCase(Locale.US); - return serial; - } -} diff --git a/play-services-base-core/src/main/java/org/microg/gms/common/Utils.java b/play-services-base-core/src/main/java/org/microg/gms/common/Utils.java index c965a444..5e5dfd7a 100644 --- a/play-services-base-core/src/main/java/org/microg/gms/common/Utils.java +++ b/play-services-base-core/src/main/java/org/microg/gms/common/Utils.java @@ -33,10 +33,6 @@ public class Utils { return Locale.getDefault(); // TODO } - public static Build getBuild(Context context) { - return new Build(); - } - public static DeviceIdentifier getDeviceIdentifier(Context context) { return new DeviceIdentifier(); } diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt new file mode 100644 index 00000000..c3cb8853 --- /dev/null +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/Build.kt @@ -0,0 +1,94 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.profile + +import android.annotation.TargetApi +import android.content.Context +import android.os.Build +import kotlin.random.Random + +object Build { + @JvmField + var BOARD: String? = null + + @JvmField + var BOOTLOADER: String? = null + + @JvmField + var BRAND: String? = null + + @JvmField + var CPU_ABI: String? = null + + @JvmField + var CPU_ABI2: String? = null + + @JvmField + @TargetApi(21) + var SUPPORTED_ABIS: Array = emptyArray() + + @JvmField + var DEVICE: String? = null + + @JvmField + var DISPLAY: String? = null + + @JvmField + var FINGERPRINT: String? = null + + @JvmField + var HARDWARE: String? = null + + @JvmField + var HOST: String? = null + + @JvmField + var ID: String? = null + + @JvmField + var MANUFACTURER: String? = null + + @JvmField + var MODEL: String? = null + + @JvmField + var PRODUCT: String? = null + + @JvmField + var RADIO: String? = null + + @JvmField + var SERIAL: String? = null + + @JvmField + var TAGS: String? = null + + @JvmField + var TIME: Long = 0L + + @JvmField + var TYPE: String? = null + + @JvmField + var USER: String? = null + + object VERSION { + @JvmField + var CODENAME: String? = null + + @JvmField + var INCREMENTAL: String? = null + + @JvmField + var RELEASE: String? = null + + @JvmField + var SDK: String? = null + + @JvmField + var SDK_INT: Int = 0 + } +} diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt new file mode 100644 index 00000000..493f8bd0 --- /dev/null +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/profile/ProfileManager.kt @@ -0,0 +1,231 @@ +/* + * SPDX-FileCopyrightText: 2021, microG Project Team + * SPDX-License-Identifier: Apache-2.0 + */ + +package org.microg.gms.profile + +import android.annotation.SuppressLint +import android.content.ContentValues +import android.content.Context +import android.util.Log +import org.microg.gms.settings.SettingsContract +import org.microg.gms.settings.SettingsContract.Profile +import org.xmlpull.v1.XmlPullParser +import kotlin.random.Random + +object ProfileManager { + private const val TAG = "ProfileManager" + const val PROFILE_REAL = "real" + const val PROFILE_AUTO = "auto" + const val PROFILE_NATIVE = "native" + + private var initialized = false + + private fun getProfileFromSettings(context: Context) = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.PROFILE)) { it.getString(0) } + private fun getAutoProfile(context: Context): String { + val profile = "${android.os.Build.DEVICE}_${android.os.Build.VERSION.SDK_INT}" + if (hasProfile(context, profile)) return profile + return PROFILE_NATIVE + } + + private fun getProfileResId(context: Context, profile: String) = context.resources.getIdentifier("${context.packageName}:xml/profile_$profile", null, null) + private fun hasProfile(context: Context, profile: String): Boolean = getProfileResId(context, profile) != 0 + private fun getProfileData(context: Context, profile: String, realData: Map): Map? { + try { + if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) return null + val profileResId = getProfileResId(context, profile) + if (profileResId == 0) return null + val resultData = mutableMapOf() + resultData.putAll(realData) + context.resources.getXml(profileResId).use { + var next = it.next() + while (next != XmlPullParser.END_DOCUMENT) { + when (next) { + XmlPullParser.START_TAG -> when (it.name) { + "data" -> { + val key = it.getAttributeValue(null, "key") + val value = it.getAttributeValue(null, "value") + resultData[key] = value + Log.d(TAG, "Overwrite from profile: $key = $value") + } + } + } + next = it.next() + } + } + for (entry in resultData) { + Log.d(TAG, "") + } + return resultData + } catch (e: Exception) { + Log.w(TAG, e) + return null + } + } + + private fun getActiveProfile(context: Context) = getProfileFromSettings(context).let { if (it != PROFILE_AUTO) it else getAutoProfile(context) } + private fun getSerialFromSettings(context: Context): String? = SettingsContract.getSettings(context, Profile.getContentUri(context), arrayOf(Profile.SERIAL)) { it.getString(0) } + private fun saveSerial(context: Context, serial: String) = SettingsContract.setSettings(context, Profile.getContentUri(context)) { put(Profile.SERIAL, serial) } + + private fun randomSerial(template: String, prefixLength: Int = (template.length / 2).coerceAtMost(6)): String { + val serial = StringBuilder() + template.forEachIndexed { index, c -> + serial.append(when { + index < prefixLength -> c + c.isDigit() -> '0' + Random.nextInt(10) + c.isLowerCase() && c <= 'f' -> 'a' + Random.nextInt(6) + c.isLowerCase() -> 'a' + Random.nextInt(26) + c.isUpperCase() && c <= 'F' -> 'A' + Random.nextInt(6) + c.isUpperCase() -> 'A' + Random.nextInt(26) + else -> c + }) + } + return serial.toString() + } + + @SuppressLint("MissingPermission") + private fun getProfileSerialTemplate(context: Context, profile: String): String { + // Native + if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) { + return kotlin.runCatching { + if (android.os.Build.VERSION.SDK_INT >= 26) { + android.os.Build.getSerial() + } else { + null + } + }.getOrNull()?.takeIf { it != android.os.Build.UNKNOWN } ?: android.os.Build.SERIAL + } + + // From profile + try { + val profileResId = getProfileResId(context, profile) + if (profileResId != 0) { + context.resources.getXml(profileResId).use { + var next = it.next() + while (next != XmlPullParser.END_DOCUMENT) { + when (next) { + XmlPullParser.START_TAG -> when (it.name) { + "serial" -> return it.getAttributeValue(null, "template") + } + } + next = it.next() + } + } + } + } catch (e: Exception) { + Log.w(TAG, e) + } + + // Fallback + return "008741A0B2C4D6E8" + } + + @SuppressLint("MissingPermission") + private fun getEffectiveProfileSerial(context: Context, profile: String): String { + getSerialFromSettings(context)?.let { return it } + val serialTemplate = getProfileSerialTemplate(context, profile) + val serial = when { + profile == PROFILE_REAL && serialTemplate != android.os.Build.UNKNOWN -> serialTemplate + else -> randomSerial(serialTemplate) + } + saveSerial(context, serial) + return serial + } + + private fun getRealData(): Map = mutableMapOf( + "Build.BOARD" to android.os.Build.BOARD, + "Build.BOOTLOADER" to android.os.Build.BOOTLOADER, + "Build.BRAND" to android.os.Build.BRAND, + "Build.CPU_ABI" to android.os.Build.CPU_ABI, + "Build.CPU_ABI2" to android.os.Build.CPU_ABI2, + "Build.DEVICE" to android.os.Build.DEVICE, + "Build.DISPLAY" to android.os.Build.DISPLAY, + "Build.FINGERPRINT" to android.os.Build.FINGERPRINT, + "Build.HARDWARE" to android.os.Build.HARDWARE, + "Build.HOST" to android.os.Build.HOST, + "Build.ID" to android.os.Build.ID, + "Build.MANUFACTURER" to android.os.Build.MANUFACTURER, + "Build.MODEL" to android.os.Build.MODEL, + "Build.PRODUCT" to android.os.Build.PRODUCT, + "Build.RADIO" to android.os.Build.RADIO, + "Build.SERIAL" to android.os.Build.SERIAL, + "Build.TAGS" to android.os.Build.TAGS, + "Build.TIME" to android.os.Build.TIME.toString(), + "Build.TYPE" to android.os.Build.TYPE, + "Build.USER" to android.os.Build.USER, + "Build.VERSION.CODENAME" to android.os.Build.VERSION.CODENAME, + "Build.VERSION.INCREMENTAL" to android.os.Build.VERSION.INCREMENTAL, + "Build.VERSION.RELEASE" to android.os.Build.VERSION.RELEASE, + "Build.VERSION.SDK" to android.os.Build.VERSION.SDK, + "Build.VERSION.SDK_INT" to android.os.Build.VERSION.SDK_INT.toString() + ).apply { + if (android.os.Build.VERSION.SDK_INT > 21) { + put("Build.SUPPORTED_ABIS", android.os.Build.SUPPORTED_ABIS.joinToString(",")) + } + } + + private fun applyProfileData(profileData: Map) { + fun applyStringField(key: String, valueSetter: (String) -> Unit) = profileData[key]?.let { valueSetter(it) } + fun applyIntField(key: String, valueSetter: (Int) -> Unit) = profileData[key]?.toIntOrNull()?.let { valueSetter(it) } + fun applyLongField(key: String, valueSetter: (Long) -> Unit) = profileData[key]?.toLongOrNull()?.let { valueSetter(it) } + + applyStringField("Build.BOARD") { Build.BOARD = it } + applyStringField("Build.BOOTLOADER") { Build.BOOTLOADER = it } + applyStringField("Build.BRAND") { Build.BRAND = it } + applyStringField("Build.CPU_ABI") { Build.CPU_ABI = it } + applyStringField("Build.CPU_ABI2") { Build.CPU_ABI2 = it } + applyStringField("Build.DEVICE") { Build.DEVICE = it } + applyStringField("Build.DISPLAY") { Build.DISPLAY = it } + applyStringField("Build.FINGERPRINT") { Build.FINGERPRINT = it } + applyStringField("Build.HARDWARE") { Build.HARDWARE = it } + applyStringField("Build.HOST") { Build.HOST = it } + applyStringField("Build.ID") { Build.ID = it } + applyStringField("Build.MANUFACTURER") { Build.MANUFACTURER = it } + applyStringField("Build.MODEL") { Build.MODEL = it } + applyStringField("Build.PRODUCT") { Build.PRODUCT = it } + applyStringField("Build.RADIO") { Build.RADIO = it } + applyStringField("Build.SERIAL") { Build.SERIAL = it } + applyStringField("Build.TAGS") { Build.TAGS = it } + applyLongField("Build.TIME") { Build.TIME = it } + applyStringField("Build.TYPE") { Build.TYPE = it } + applyStringField("Build.USER") { Build.USER = it } + applyStringField("Build.VERSION.CODENAME") { Build.VERSION.CODENAME = it } + applyStringField("Build.VERSION.INCREMENTAL") { Build.VERSION.INCREMENTAL = it } + applyStringField("Build.VERSION.RELEASE") { Build.VERSION.RELEASE = it } + applyStringField("Build.VERSION.SDK") { Build.VERSION.SDK = it } + applyIntField("Build.VERSION.SDK_INT") { Build.VERSION.SDK_INT = it } + if (android.os.Build.VERSION.SDK_INT > 21) { + Build.SUPPORTED_ABIS = profileData["Build.SUPPORTED_ABIS"]?.split(",")?.toTypedArray() ?: emptyArray() + } + } + + private fun applyProfile(context: Context, profile: String) { + val profileData = getProfileData(context, profile, getRealData()) ?: getRealData() + applyProfileData(profileData) + Build.SERIAL = getEffectiveProfileSerial(context, profile) + Log.d(TAG, "Using Serial ${Build.SERIAL}") + } + + fun setProfile(context: Context, profile: String?) { + SettingsContract.setSettings(context, Profile.getContentUri(context)) { + put(Profile.PROFILE, profile) + put(Profile.SERIAL, null as String?) + } + applyProfile(context, profile ?: PROFILE_AUTO) + } + + @JvmStatic + fun ensureInitialized(context: Context) { + if (initialized) return + try { + val profile = getActiveProfile(context) + applyProfile(context, profile) + initialized = true + } catch (e: Exception) { + Log.w(TAG, e) + } + } + + +} diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt index 7132c7cf..42b8b7cb 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsContract.kt @@ -131,6 +131,20 @@ object SettingsContract { ) } + object Profile { + private const val id = "profile" + fun getContentUri(context: Context) = Uri.withAppendedPath(getAuthorityUri(context), id) + fun getContentType(context: Context) = "vnd.android.cursor.item/vnd.${getAuthority(context)}.$id" + + const val PROFILE = "device_profile" + const val SERIAL = "device_profile_serial" + + val PROJECTION = arrayOf( + PROFILE, + SERIAL + ) + } + private fun withoutCallingIdentity(f: () -> T): T { val identity = Binder.clearCallingIdentity() try { diff --git a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt index 3d1f712f..c4adcc96 100644 --- a/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt +++ b/play-services-base-core/src/main/kotlin/org/microg/gms/settings/SettingsProvider.kt @@ -20,6 +20,7 @@ import org.microg.gms.settings.SettingsContract.CheckIn import org.microg.gms.settings.SettingsContract.DroidGuard import org.microg.gms.settings.SettingsContract.Exposure import org.microg.gms.settings.SettingsContract.Gcm +import org.microg.gms.settings.SettingsContract.Profile import org.microg.gms.settings.SettingsContract.SafetyNet import org.microg.gms.settings.SettingsContract.getAuthority import java.io.File @@ -65,6 +66,7 @@ class SettingsProvider : ContentProvider() { Exposure.getContentUri(context!!) -> queryExposure(projection ?: Exposure.PROJECTION) SafetyNet.getContentUri(context!!) -> querySafetyNet(projection ?: SafetyNet.PROJECTION) DroidGuard.getContentUri(context!!) -> queryDroidGuard(projection ?: DroidGuard.PROJECTION) + Profile.getContentUri(context!!) -> queryProfile(projection ?: Profile.PROJECTION) else -> null } @@ -83,6 +85,7 @@ class SettingsProvider : ContentProvider() { Exposure.getContentUri(context!!) -> updateExposure(values) SafetyNet.getContentUri(context!!) -> updateSafetyNet(values) DroidGuard.getContentUri(context!!) -> updateDroidGuard(values) + Profile.getContentUri(context!!) -> updateProfile(values) else -> return 0 } return 1 @@ -264,6 +267,27 @@ class SettingsProvider : ContentProvider() { editor.apply() } + private fun queryProfile(p: Array): Cursor = MatrixCursor(p).addRow(p) { key -> + when (key) { + Profile.PROFILE -> getSettingsString(key, "auto") + Profile.SERIAL -> getSettingsString(key) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + + private fun updateProfile(values: ContentValues) { + if (values.size() == 0) return + val editor = preferences.edit() + values.valueSet().forEach { (key, value) -> + when (key) { + Profile.PROFILE -> editor.putString(key, value as String?) + Profile.SERIAL -> editor.putString(key, value as String?) + else -> throw IllegalArgumentException("Unknown key: $key") + } + } + editor.apply() + } + private fun MatrixCursor.addRow( p: Array, valueGetter: (String) -> Any? diff --git a/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java b/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java index b65648cb..d0bb1144 100644 --- a/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java +++ b/play-services-core/src/main/java/org/microg/gms/auth/AuthRequest.java @@ -19,10 +19,11 @@ package org.microg.gms.auth; import android.content.Context; import org.microg.gms.checkin.LastCheckinInfo; -import org.microg.gms.common.Build; +import org.microg.gms.profile.Build; import org.microg.gms.common.Constants; import org.microg.gms.common.HttpFormClient; import org.microg.gms.common.Utils; +import org.microg.gms.profile.ProfileManager; import java.io.IOException; import java.util.Locale; @@ -91,10 +92,11 @@ public class AuthRequest extends HttpFormClient.Request { userAgent = String.format(USER_AGENT, deviceName, buildVersion); } - public AuthRequest build(Build build) { - sdkVersion = build.version_sdk_int; - deviceName = build.device; - buildVersion = build.id; + public AuthRequest build(Context context) { + ProfileManager.ensureInitialized(context); + sdkVersion = Build.VERSION.SDK_INT; + deviceName = Build.DEVICE; + buildVersion = Build.ID; return this; } @@ -111,7 +113,7 @@ public class AuthRequest extends HttpFormClient.Request { } public AuthRequest fromContext(Context context) { - build(Utils.getBuild(context)); + build(context); locale(Utils.getLocale(context)); androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId()); return this; diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java index 9186d1a3..87c566c0 100644 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinClient.java @@ -16,13 +16,15 @@ package org.microg.gms.checkin; +import android.content.Context; import android.util.Log; -import org.microg.gms.common.Build; import org.microg.gms.common.DeviceConfiguration; import org.microg.gms.common.DeviceIdentifier; import org.microg.gms.common.PhoneInfo; import org.microg.gms.common.Utils; +import org.microg.gms.profile.Build; +import org.microg.gms.profile.ProfileManager; import java.io.IOException; import java.io.InputStream; @@ -76,29 +78,30 @@ public class CheckinClient { return response; } - public static CheckinRequest makeRequest(Build build, DeviceConfiguration deviceConfiguration, + public static CheckinRequest makeRequest(Context context, DeviceConfiguration deviceConfiguration, DeviceIdentifier deviceIdent, PhoneInfo phoneInfo, LastCheckinInfo checkinInfo, Locale locale, List accounts) { + ProfileManager.ensureInitialized(context); CheckinRequest.Builder builder = new CheckinRequest.Builder() .accountCookie(new ArrayList<>()) .androidId(checkinInfo.getAndroidId()) .checkin(new CheckinRequest.Checkin.Builder() .build(new CheckinRequest.Checkin.Build.Builder() - .bootloader(build.bootloader) - .brand(build.brand) + .bootloader(Build.BOOTLOADER) + .brand(Build.BRAND) .clientId("android-google") - .device(build.device) - .fingerprint(build.fingerprint) - .hardware(build.hardware) - .manufacturer(build.manufacturer) - .model(build.model) + .device(Build.DEVICE) + .fingerprint(Build.FINGERPRINT) + .hardware(Build.HARDWARE) + .manufacturer(Build.MANUFACTURER) + .model(Build.MODEL) .otaInstalled(false) // TODO? //.packageVersionCode(Constants.MAX_REFERENCE_VERSION) - .product(build.product) - .radio(build.radio) - .sdkVersion(build.version_sdk_int) - .time(build.time / 1000) + .product(Build.PRODUCT) + .radio(Build.RADIO) + .sdkVersion(Build.VERSION.SDK_INT) + .time(Build.TIME / 1000) .build()) .cellOperator(phoneInfo.cellOperator) .event(Collections.singletonList(new CheckinRequest.Checkin.Event.Builder() @@ -137,7 +140,7 @@ public class CheckinClient { .loggingId(new Random().nextLong()) // TODO: static .meid(deviceIdent.meid) .otaCert(Collections.singletonList("71Q6Rn2DDZl1zPDVaaeEHItd")) - .serial(build.serial) + .serial(Build.SERIAL) .timeZone(TimeZone.getDefault().getID()) .userName((String) TODO) .userSerialNumber((Integer) TODO) diff --git a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java index 95b81984..d6cfdabb 100644 --- a/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java +++ b/play-services-core/src/main/java/org/microg/gms/checkin/CheckinManager.java @@ -56,7 +56,7 @@ public class CheckinManager { accounts.add(new CheckinClient.Account(account.name, token)); } } - CheckinRequest request = CheckinClient.makeRequest(Utils.getBuild(context), + CheckinRequest request = CheckinClient.makeRequest(context, new DeviceConfiguration(context), Utils.getDeviceIdentifier(context), Utils.getPhoneInfo(context), info, Utils.getLocale(context), accounts); return handleResponse(context, CheckinClient.request(request)); diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java index 16220724..e17b86fd 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/PushRegisterManager.java @@ -41,7 +41,7 @@ public class PushRegisterManager { RegisterResponse response = new RegisterResponse(); try { response = new RegisterRequest() - .build(Utils.getBuild(context)) + .build(context) .sender(sender) .info(info) .checkin(LastCheckinInfo.read(context)) diff --git a/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java b/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java index 43f04028..bcc2f736 100644 --- a/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java +++ b/play-services-core/src/main/java/org/microg/gms/gcm/RegisterRequest.java @@ -16,12 +16,14 @@ package org.microg.gms.gcm; +import android.content.Context; import android.os.Bundle; import android.text.TextUtils; import org.microg.gms.checkin.LastCheckinInfo; -import org.microg.gms.common.Build; import org.microg.gms.common.HttpFormClient; +import org.microg.gms.profile.Build; +import org.microg.gms.profile.ProfileManager; import java.io.IOException; import java.util.LinkedHashMap; @@ -103,9 +105,10 @@ public class RegisterRequest extends HttpFormClient.Request { return this; } - public RegisterRequest build(Build build) { - deviceName = build.device; - buildVersion = build.id; + public RegisterRequest build(Context context) { + ProfileManager.ensureInitialized(context); + deviceName = Build.DEVICE; + buildVersion = Build.ID; return this; } diff --git a/play-services-core/src/main/java/org/microg/gms/safetynet/Attestation.java b/play-services-core/src/main/java/org/microg/gms/safetynet/Attestation.java index 805814ba..d5eba6d9 100644 --- a/play-services-core/src/main/java/org/microg/gms/safetynet/Attestation.java +++ b/play-services-core/src/main/java/org/microg/gms/safetynet/Attestation.java @@ -13,10 +13,11 @@ import android.content.pm.Signature; import android.util.Base64; import android.util.Log; -import org.microg.gms.common.Build; import org.microg.gms.common.Constants; import org.microg.gms.common.PackageUtils; import org.microg.gms.common.Utils; +import org.microg.gms.profile.Build; +import org.microg.gms.profile.ProfileManager; import org.microg.gms.snet.AttestRequest; import org.microg.gms.snet.AttestResponse; import org.microg.gms.snet.FileState; @@ -154,6 +155,7 @@ public class Attestation { } private AttestResponse attest(AttestRequest request, String apiKey) throws IOException { + ProfileManager.ensureInitialized(context); String requestUrl = SafetyNetPrefs.get(context).getServiceUrl() + "?alt=PROTO&key=" + apiKey; HttpURLConnection connection = (HttpURLConnection) new URL(requestUrl).openConnection(); connection.setRequestMethod("POST"); @@ -163,8 +165,7 @@ public class Attestation { connection.setRequestProperty("Accept-Encoding", "gzip"); connection.setRequestProperty("X-Android-Package", packageName); connection.setRequestProperty("X-Android-Cert", PackageUtils.firstSignatureDigest(context, packageName)); - Build build = Utils.getBuild(context); - connection.setRequestProperty("User-Agent", "SafetyNet/" + Constants.GMS_VERSION_CODE + " (" + build.device + " " + build.id + "); gzip"); + connection.setRequestProperty("User-Agent", "SafetyNet/" + Constants.GMS_VERSION_CODE + " (" + Build.DEVICE + " " + Build.ID + "); gzip"); OutputStream os = connection.getOutputStream(); os.write(request.encode()); diff --git a/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java b/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java index 6a84253c..5cdb087a 100644 --- a/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java +++ b/play-services-core/src/main/java/org/microg/gms/wearable/MessageHandler.java @@ -24,7 +24,7 @@ import com.google.android.gms.wearable.ConnectionConfiguration; import com.google.android.gms.wearable.internal.MessageEventParcelable; import org.microg.gms.checkin.LastCheckinInfo; -import org.microg.gms.common.Build; +import org.microg.gms.profile.Build; import org.microg.wearable.ServerMessageListener; import org.microg.wearable.proto.AckAsset; import org.microg.wearable.proto.Connect; @@ -48,7 +48,7 @@ public class MessageHandler extends ServerMessageListener { private String peerNodeId; public MessageHandler(WearableImpl wearable, ConnectionConfiguration config) { - this(wearable, config, new Build().model, config.nodeId, LastCheckinInfo.read(wearable.getContext()).getAndroidId()); + this(wearable, config, Build.MODEL, config.nodeId, LastCheckinInfo.read(wearable.getContext()).getAndroidId()); } private MessageHandler(WearableImpl wearable, ConnectionConfiguration config, String name, String networkId, long androidId) { diff --git a/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt b/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt index f1ba3435..864c9e83 100644 --- a/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt +++ b/play-services-core/src/main/kotlin/org/microg/gms/gcm/PushRegisterService.kt @@ -148,7 +148,7 @@ class PushRegisterService : LifecycleService() { Log.d(TAG, "register[req]: " + intent.toString() + " extras=" + intent!!.extras) val bundle = completeRegisterRequest(this, database, RegisterRequest() - .build(Utils.getBuild(this)) + .build(this) .sender(intent.getStringExtra(EXTRA_SENDER)) .checkin(LastCheckinInfo.read(this)) .app(packageName) @@ -164,7 +164,7 @@ class PushRegisterService : LifecycleService() { val packageName = intent.appPackageName ?: throw RuntimeException("No package provided") Log.d(TAG, "unregister[req]: " + intent.toString() + " extras=" + intent.extras) val bundle = completeRegisterRequest(this, database, RegisterRequest() - .build(Utils.getBuild(this)) + .build(this) .sender(intent.getStringExtra(EXTRA_SENDER)) .checkin(LastCheckinInfo.read(this)) .app(packageName) @@ -314,7 +314,7 @@ internal class PushRegisterHandler(private val context: Context, private val dat if (!delete) ensureAppRegistrationAllowed(context, database, packageName) val bundle = completeRegisterRequest(context, database, RegisterRequest() - .build(Utils.getBuild(context)) + .build(context) .sender(sender) .checkin(LastCheckinInfo.read(context)) .app(packageName) diff --git a/play-services-core/src/main/res/xml/profile_bullhead_27.xml b/play-services-core/src/main/res/xml/profile_bullhead_27.xml new file mode 100644 index 00000000..66d1a94e --- /dev/null +++ b/play-services-core/src/main/res/xml/profile_bullhead_27.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/play-services-droidguard-core/src/main/java/com/google/android/gms/framework/tracing/wrapper/TracingIntentService.java b/play-services-droidguard-core/src/main/java/com/google/android/gms/framework/tracing/wrapper/TracingIntentService.java index 7d10c103..0db16eb6 100644 --- a/play-services-droidguard-core/src/main/java/com/google/android/gms/framework/tracing/wrapper/TracingIntentService.java +++ b/play-services-droidguard-core/src/main/java/com/google/android/gms/framework/tracing/wrapper/TracingIntentService.java @@ -40,7 +40,7 @@ public abstract class TracingIntentService extends IntentService { public PackageInfo getPackageInfo(@NonNull String packageName, int flags) { PackageInfo packageInfo = super.getPackageInfo(packageName, flags); if ("com.google.android.gms".equals(packageName)) { - VersionUtil versionUtil = new VersionUtil(TracingIntentService.this, new org.microg.gms.common.Build()); + VersionUtil versionUtil = new VersionUtil(TracingIntentService.this); packageInfo.versionCode = versionUtil.getVersionCode(); packageInfo.versionName = versionUtil.getVersionString(); packageInfo.sharedUserId = "com.google.uid.shared"; diff --git a/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/HandleProxyFactory.kt b/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/HandleProxyFactory.kt index a8fe931b..0b4aff1f 100644 --- a/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/HandleProxyFactory.kt +++ b/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/HandleProxyFactory.kt @@ -14,8 +14,9 @@ import com.google.android.gms.droidguard.internal.DroidGuardResultsRequest import dalvik.system.DexClassLoader import okio.ByteString.Companion.decodeHex import okio.ByteString.Companion.of -import org.microg.gms.common.Build import org.microg.gms.droidguard.core.BuildConfig +import org.microg.gms.profile.Build +import org.microg.gms.profile.ProfileManager import java.io.File import java.io.IOException import java.security.MessageDigest @@ -25,10 +26,9 @@ import com.android.volley.Request as VolleyRequest import com.android.volley.Response as VolleyResponse class HandleProxyFactory(private val context: Context) { - private val build: Build = Build() private val classMap = hashMapOf>() private val dgDb: DgDatabaseHelper = DgDatabaseHelper(context) - private val version = VersionUtil(context, build) + private val version = VersionUtil(context) private val queue = Volley.newRequestQueue(context) fun createHandle(packageName: String, flow: String?, callback: GuardCallback, request: DroidGuardResultsRequest?): HandleProxy { @@ -55,40 +55,42 @@ class HandleProxyFactory(private val context: Context) { } private fun readFromDatabase(flow: String?): Triple? { - val id = "$flow/${version.versionString}/${build.fingerprint}" + ProfileManager.ensureInitialized(context) + val id = "$flow/${version.versionString}/${Build.FINGERPRINT}" return dgDb.get(id) } fun createRequest(flow: String?, packageName: String, pingData: PingData? = null, extra: ByteArray? = null): Request { + ProfileManager.ensureInitialized(context) return Request( usage = Usage(flow, packageName), info = listOf( - KeyValuePair("BOARD", build.board), - KeyValuePair("BOOTLOADER", build.bootloader), - KeyValuePair("BRAND", build.brand), - KeyValuePair("CPU_ABI", build.cpu_abi), - KeyValuePair("CPU_ABI2", build.cpu_abi2), - KeyValuePair("SUPPORTED_ABIS", build.supported_abis.joinToString(",")), - KeyValuePair("DEVICE", build.device), - KeyValuePair("DISPLAY", build.display), - KeyValuePair("FINGERPRINT", build.fingerprint), - KeyValuePair("HARDWARE", build.hardware), - KeyValuePair("HOST", build.host), - KeyValuePair("ID", build.id), - KeyValuePair("MANUFACTURER", build.manufacturer), - KeyValuePair("MODEL", build.model), - KeyValuePair("PRODUCT", build.product), - KeyValuePair("RADIO", build.radio), - KeyValuePair("SERIAL", build.serial), - KeyValuePair("TAGS", build.tags), - KeyValuePair("TIME", build.time.toString()), - KeyValuePair("TYPE", build.type), - KeyValuePair("USER", build.user), - KeyValuePair("VERSION.CODENAME", build.version_codename), - KeyValuePair("VERSION.INCREMENTAL", build.version_incremental), - KeyValuePair("VERSION.RELEASE", build.version_release), - KeyValuePair("VERSION.SDK", build.version_sdk), - KeyValuePair("VERSION.SDK_INT", build.version_sdk_int.toString()), + KeyValuePair("BOARD", Build.BOARD), + KeyValuePair("BOOTLOADER", Build.BOOTLOADER), + KeyValuePair("BRAND", Build.BRAND), + KeyValuePair("CPU_ABI", Build.CPU_ABI), + KeyValuePair("CPU_ABI2", Build.CPU_ABI2), + KeyValuePair("SUPPORTED_ABIS", Build.SUPPORTED_ABIS.joinToString(",")), + KeyValuePair("DEVICE", Build.DEVICE), + KeyValuePair("DISPLAY", Build.DISPLAY), + KeyValuePair("FINGERPRINT", Build.FINGERPRINT), + KeyValuePair("HARDWARE", Build.HARDWARE), + KeyValuePair("HOST", Build.HOST), + KeyValuePair("ID", Build.ID), + KeyValuePair("MANUFACTURER", Build.MANUFACTURER), + KeyValuePair("MODEL", Build.MODEL), + KeyValuePair("PRODUCT", Build.PRODUCT), + KeyValuePair("RADIO", Build.RADIO), + KeyValuePair("SERIAL", Build.SERIAL), + KeyValuePair("TAGS", Build.TAGS), + KeyValuePair("TIME", Build.TIME.toString()), + KeyValuePair("TYPE", Build.TYPE), + KeyValuePair("USER", Build.USER), + KeyValuePair("VERSION.CODENAME", Build.VERSION.CODENAME), + KeyValuePair("VERSION.INCREMENTAL", Build.VERSION.INCREMENTAL), + KeyValuePair("VERSION.RELEASE", Build.VERSION.RELEASE), + KeyValuePair("VERSION.SDK", Build.VERSION.SDK), + KeyValuePair("VERSION.SDK_INT", Build.VERSION.SDK_INT.toString()), ), versionName = version.versionString, versionCode = BuildConfig.VERSION_CODE, @@ -107,6 +109,7 @@ class HandleProxyFactory(private val context: Context) { } fun fetchFromServer(flow: String?, request: Request): Triple { + ProfileManager.ensureInitialized(context) val future = RequestFuture.newFuture() queue.add(object : VolleyRequest(Method.POST, SERVER_URL, future) { override fun parseNetworkResponse(response: NetworkResponse): VolleyResponse { @@ -146,11 +149,13 @@ class HandleProxyFactory(private val context: Context) { throw IllegalStateException() } } - val id = "$flow/${version.versionString}/${build.fingerprint}" + val id = "$flow/${version.versionString}/${Build.FINGERPRINT}" val expiry = (response.expiryTimeSecs ?: 0).toLong() - val byteCode = response.byteCode!!.toByteArray() - val extra = response.extra!!.toByteArray() - dgDb.put(id, expiry, vmKey, byteCode, extra) + val byteCode = response.byteCode?.toByteArray() ?: ByteArray(0) + val extra = response.extra?.toByteArray() ?: ByteArray(0) + if (response.save != false) { + dgDb.put(id, expiry, vmKey, byteCode, extra) + } return Triple(vmKey, byteCode, extra) } diff --git a/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/VersionUtil.kt b/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/VersionUtil.kt index c9a4b35f..ce128f4d 100644 --- a/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/VersionUtil.kt +++ b/play-services-droidguard-core/src/main/kotlin/org/microg/gms/droidguard/VersionUtil.kt @@ -6,14 +6,16 @@ package org.microg.gms.droidguard import android.content.Context -import org.microg.gms.common.Build import org.microg.gms.droidguard.core.BuildConfig +import org.microg.gms.profile.Build +import org.microg.gms.profile.ProfileManager -class VersionUtil(private val context: Context, private val build: Build = Build()) { +class VersionUtil(private val context: Context) { val buildType: String get() { + ProfileManager.ensureInitialized(context) // Note: Android TV and Watch use different version codes - val versionCode = when (build.version_sdk_int) { + val versionCode = when (Build.VERSION.SDK_INT) { 31 -> "19" 30 -> "15" 29 -> "12" @@ -22,14 +24,14 @@ class VersionUtil(private val context: Context, private val build: Build = Build 21, 22 -> "02" else -> "00" } - val architectureCode = when (build.cpu_abi) { + val architectureCode = when (Build.CPU_ABI) { "x86_64" -> "08" "x86" -> "07" "arm64-v8a" -> "04" "arm", "armeabi", "armeabi-v7a" -> "03" else -> "00" } - val dpiCode = when (context.resources.displayMetrics.densityDpi) { + val dpiCode = when (context.resources.displayMetrics.densityDpi) { // TODO: Also something to get from profile 160 -> "02" 240 -> "04" 320 -> "06"