Add profile manager

This commit is contained in:
Marvin W 2021-11-24 23:39:33 -06:00
parent 6d45bfb7ed
commit a7b2b7e3f8
No known key found for this signature in database
GPG Key ID: 072E9235DB996F2A
18 changed files with 488 additions and 140 deletions

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -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<String> = 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
}
}

View File

@ -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<String, String>): Map<String, String>? {
try {
if (profile in listOf(PROFILE_REAL, PROFILE_NATIVE)) return null
val profileResId = getProfileResId(context, profile)
if (profileResId == 0) return null
val resultData = mutableMapOf<String, String>()
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, "<data key=\"${entry.key}\" value=\"${entry.value}\" />")
}
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<String, String> = 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<String, String>) {
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)
}
}
}

View File

@ -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 <T> withoutCallingIdentity(f: () -> T): T {
val identity = Binder.clearCallingIdentity()
try {

View File

@ -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<out String>): 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<out String>,
valueGetter: (String) -> Any?

View File

@ -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;

View File

@ -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<Account> 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)

View File

@ -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));

View File

@ -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))

View File

@ -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;
}

View File

@ -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());

View File

@ -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) {

View File

@ -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)

View File

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ SPDX-FileCopyrightText: 2021, microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<profile name="Google Nexus 5X (Android 8.1.0)" device="bullhead" sdk="27" id="bullhead_27">
<!-- Data from OPM3.171019.016, Mar 2018 -->
<data key="Build.BOARD" value="bullhead" />
<data key="Build.BOOTLOADER" value="BHZ31b" />
<data key="Build.BRAND" value="google" />
<data key="Build.CPU_ABI" value="arm64-v8a" />
<data key="Build.CPU_ABI2" value="" />
<data key="Build.DEVICE" value="bullhead" />
<data key="Build.DISPLAY" value="bullhead-user 8.1.0 OPM3.171019.016 4565142 release-keys" />
<data key="Build.FINGERPRINT" value="google/bullhead/bullhead:8.1.0/OPM3.171019.016/4565142:user/release-keys" />
<data key="Build.HARDWARE" value="bullhead" />
<data key="Build.HOST" value="wpdt4.hot.corp.google.com" />
<data key="Build.ID" value="OPM3.171019.016" />
<data key="Build.MANUFACTURER" value="LGE" />
<data key="Build.MODEL" value="Nexus 5X" />
<data key="Build.PRODUCT" value="bullhead" />
<data key="Build.RADIO" value="unknown" />
<data key="Build.TAGS" value="release-keys" />
<data key="Build.TIME" value="1516849845000" />
<data key="Build.TYPE" value="user" />
<data key="Build.USER" value="android-build" />
<data key="Build.VERSION.CODENAME" value="REL" />
<data key="Build.VERSION.INCREMENTAL" value="6d95f5a143" />
<data key="Build.VERSION.RELEASE" value="8.1.0" />
<data key="Build.VERSION.SDK" value="27" />
<data key="Build.VERSION.SDK_INT" value="27" />
<data key="Build.SUPPORTED_ABIS" value="arm64-v8a,armeabi-v7a,armeabi" />
<serial template="005b56ffff999999" />
</profile>

View File

@ -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";

View File

@ -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<String, Class<*>>()
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<String, ByteArray, ByteArray>? {
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<String, ByteArray, ByteArray> {
ProfileManager.ensureInitialized(context)
val future = RequestFuture.newFuture<SignedResponse>()
queue.add(object : VolleyRequest<SignedResponse>(Method.POST, SERVER_URL, future) {
override fun parseNetworkResponse(response: NetworkResponse): VolleyResponse<SignedResponse> {
@ -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)
}

View File

@ -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"