Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit aa3a2d65 authored by Torsten Grote's avatar Torsten Grote Committed by Marvin W.
Browse files

Refactor settings access to use a SettingsProvider

to enable safe usage of settings no matter which process is getting/setting them.
Previously, different processes were accessing settings in an unsafe way and the warn methods were throwing Runtime exceptions which went largely unnoticed, but happened, especially on a fresh start of the OS.

Change-Id: Ie4134e7be2a7ca4a373790f45fbcbd09bf02ad86
parent fbcb6066
Loading
Loading
Loading
Loading
+120 −0
Original line number Diff line number Diff line
package org.microg.gms.settings

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.net.Uri

object SettingsContract {
    const val AUTHORITY = "org.microg.gms.settings"
    val AUTHORITY_URI: Uri = Uri.parse("content://$AUTHORITY")

    object CheckIn {
        private const val id = "check-in"
        val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
        const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"

        const val ENABLED = "checkin_enable_service"
        const val ANDROID_ID = "androidId"
        const val DIGEST = "digest"
        const val LAST_CHECK_IN = "lastCheckin"
        const val SECURITY_TOKEN = "securityToken"
        const val VERSION_INFO = "versionInfo"
        const val DEVICE_DATA_VERSION_INFO = "deviceDataVersionInfo"

        val PROJECTION = arrayOf(
            ENABLED,
            ANDROID_ID,
            DIGEST,
            LAST_CHECK_IN,
            SECURITY_TOKEN,
            VERSION_INFO,
            DEVICE_DATA_VERSION_INFO,
        )
        const val PREFERENCES_NAME = "checkin"
        const val INITIAL_DIGEST = "1-929a0dca0eee55513280171a8585da7dcd3700f8"
    }

    object Gcm {
        private const val id = "gcm"
        val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
        const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"

        const val FULL_LOG = "gcm_full_log"
        const val LAST_PERSISTENT_ID = "gcm_last_persistent_id"
        const val CONFIRM_NEW_APPS = "gcm_confirm_new_apps"
        const val ENABLE_GCM = "gcm_enable_mcs_service"

        const val NETWORK_MOBILE = "gcm_network_mobile"
        const val NETWORK_WIFI = "gcm_network_wifi"
        const val NETWORK_ROAMING = "gcm_network_roaming"
        const val NETWORK_OTHER = "gcm_network_other"

        const val LEARNT_MOBILE = "gcm_learnt_mobile"
        const val LEARNT_WIFI = "gcm_learnt_wifi"
        const val LEARNT_OTHER = "gcm_learnt_other"

        val PROJECTION = arrayOf(
            FULL_LOG,
            LAST_PERSISTENT_ID,
            CONFIRM_NEW_APPS,
            ENABLE_GCM,
            NETWORK_MOBILE,
            NETWORK_WIFI,
            NETWORK_ROAMING,
            NETWORK_OTHER,
            LEARNT_MOBILE,
            LEARNT_WIFI,
            LEARNT_OTHER,
        )
    }

    object Auth {
        private const val id = "auth"
        val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
        const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"

        const val TRUST_GOOGLE = "auth_manager_trust_google"
        const val VISIBLE = "auth_manager_visible"

        val PROJECTION = arrayOf(
            TRUST_GOOGLE,
            VISIBLE,
        )
    }

    object Exposure {
        private const val id = "exposureNotification"
        val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
        const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"

        const val SCANNER_ENABLED = "exposure_scanner_enabled"
        const val LAST_CLEANUP = "exposure_last_cleanup"

        val PROJECTION = arrayOf(
            SCANNER_ENABLED,
            LAST_CLEANUP,
        )
    }

    object SafetyNet {
        private const val id = "safety-net"
        val CONTENT_URI: Uri = Uri.withAppendedPath(AUTHORITY_URI, id)
        const val CONTENT_TYPE = "vnd.android.cursor.item/vnd.$AUTHORITY.$id"
    }

    fun <T> getSettings(context: Context, uri: Uri, projection: Array<out String>?, f: (Cursor) -> T): T {
        context.contentResolver.query(uri, projection, null, null, null).use { c ->
            require(c != null) { "Cursor for query $uri ${projection?.toList()} was null" }
            if (!c.moveToFirst()) error("Cursor for query $uri ${projection?.toList()} was empty")
            return f.invoke(c)
        }
    }

    fun setSettings(context: Context, uri: Uri, v: ContentValues.() -> Unit) {
        val values = ContentValues().apply { v.invoke(this) }
        val affected = context.contentResolver.update(uri, values, null, null)
        require(affected == 1) { "Update for $uri with $values affected 0 rows"}
    }

}
+7 −2
Original line number Diff line number Diff line
@@ -129,6 +129,13 @@
            android:exported="true"
            android:permission="org.microg.gms.PROVISION" />

        <!-- Internal Settings -->

        <provider
            android:name="org.microg.gms.settings.SettingsProvider"
            android:authorities="org.microg.gms.settings"
            android:exported="false" />

        <!-- Location -->

        <activity
@@ -198,8 +205,6 @@
            </intent-filter>
        </service>

        <receiver android:name="org.microg.gms.checkin.ServiceInfoReceiver" />

        <receiver android:name="org.microg.gms.checkin.TriggerReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
+3 −11
Original line number Diff line number Diff line
@@ -21,22 +21,22 @@ import android.accounts.AccountManager;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.preference.PreferenceManager;
import android.util.Log;

import org.microg.gms.common.PackageUtils;
import org.microg.gms.settings.SettingsContract;

import java.io.IOException;

import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
import static org.microg.gms.auth.AuthPrefs.isTrustGooglePermitted;

public class AuthManager {

    private static final String TAG = "GmsAuthManager";
    public static final String PERMISSION_TREE_BASE = "com.google.android.googleapps.permission.GOOGLE_AUTH.";
    private static final String PREF_AUTH_TRUST_GOOGLE = "auth_manager_trust_google";
    public static final String PREF_AUTH_VISIBLE = "auth_manager_visible";
    public static final String PREF_AUTH_VISIBLE = SettingsContract.Auth.VISIBLE;
    public static final int ONE_HOUR_IN_SECONDS = 60 * 60;

    private final Context context;
@@ -185,14 +185,6 @@ public class AuthManager {
        }
    }

    public static boolean isTrustGooglePermitted(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_TRUST_GOOGLE, true);
    }

    public static boolean isAuthVisible(Context context) {
        return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(PREF_AUTH_VISIBLE, false);
    }

    private boolean isSystemApp() {
        try {
            int flags = context.getPackageManager().getApplicationInfo(packageName, 0).flags;
+1 −1
Original line number Diff line number Diff line
@@ -113,7 +113,7 @@ public class AuthRequest extends HttpFormClient.Request {
    public AuthRequest fromContext(Context context) {
        build(Utils.getBuild(context));
        locale(Utils.getLocale(context));
        androidIdHex = Long.toHexString(LastCheckinInfo.read(context).androidId);
        androidIdHex = Long.toHexString(LastCheckinInfo.read(context).getAndroidId());
        return this;
    }

+4 −5
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import android.accounts.AccountManager;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
@@ -36,7 +35,6 @@ import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.webkit.CookieManager;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@@ -72,6 +70,7 @@ import static android.view.KeyEvent.KEYCODE_BACK;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
import static org.microg.gms.auth.AuthPrefs.isAuthVisible;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
import static org.microg.gms.common.Constants.GMS_VERSION_CODE;

@@ -136,7 +135,7 @@ public class LoginActivity extends AssistantActivity {
                AccountManager accountManager = AccountManager.get(this);
                Account account = new Account(getIntent().getStringExtra(EXTRA_EMAIL), accountType);
                accountManager.addAccountExplicitly(account, getIntent().getStringExtra(EXTRA_TOKEN), null);
                if (AuthManager.isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) {
                if (isAuthVisible(this) && SDK_INT >= Build.VERSION_CODES.O) {
                    accountManager.setAccountVisibility(account, PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE, VISIBILITY_USER_MANAGED_VISIBLE);
                }
                retrieveGmsToken(account);
@@ -223,7 +222,7 @@ public class LoginActivity extends AssistantActivity {
        ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = cm.getActiveNetworkInfo();
        if (networkInfo != null && networkInfo.isConnected()) {
            if (LastCheckinInfo.read(this).androidId == 0) {
            if (LastCheckinInfo.read(this).getAndroidId() == 0) {
                new Thread(() -> {
                    Runnable next;
                    next = checkin(false) ? this::loadLoginPage : () -> showError(R.string.auth_general_error_desc);
@@ -425,7 +424,7 @@ public class LoginActivity extends AssistantActivity {

        @JavascriptInterface
        public final String getAndroidId() {
            long androidId = LastCheckinInfo.read(LoginActivity.this).androidId;
            long androidId = LastCheckinInfo.read(LoginActivity.this).getAndroidId();
            Log.d(TAG, "JSBridge: getAndroidId " + androidId);
            if (androidId == 0 || androidId == -1) return null;
            return Long.toHexString(androidId);
Loading