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

Commit ba266c7b authored by Matt Pape's avatar Matt Pape Committed by Android (Google) Code Review
Browse files

Merge "Add a new config table to the settings provider for remotely configured...

Merge "Add a new config table to the settings provider for remotely configured parameters. This includes the minimum number of changes necessary to make the table work, but no API surface yet."
parents 1abd4fea 1b31a331
Loading
Loading
Loading
Loading
+117 −0
Original line number Diff line number Diff line
@@ -1613,6 +1613,11 @@ public final class Settings {
     */
    public static final String CALL_METHOD_GET_GLOBAL = "GET_global";
    /**
     * @hide - Private call() method on SettingsProvider to read from 'config' table.
     */
    public static final String CALL_METHOD_GET_CONFIG = "GET_config";
    /**
     * @hide - Specifies that the caller of the fast-path call()-based flow tracks
     * the settings generation in order to cache values locally. If this key is
@@ -1672,9 +1677,15 @@ public final class Settings {
    /** @hide - Private call() method to write to 'global' table */
    public static final String CALL_METHOD_PUT_GLOBAL= "PUT_global";
    /** @hide - Private call() method to write to 'configuration' table */
    public static final String CALL_METHOD_PUT_CONFIG = "PUT_config";
    /** @hide - Private call() method to reset to defaults the 'global' table */
    public static final String CALL_METHOD_RESET_GLOBAL = "RESET_global";
    /** @hide - Private call() method to reset to defaults the 'configuration' table */
    public static final String CALL_METHOD_RESET_CONFIG = "RESET_config";
    /** @hide - Private call() method to reset to defaults the 'secure' table */
    public static final String CALL_METHOD_RESET_SECURE = "RESET_secure";
@@ -13438,6 +13449,112 @@ public final class Settings {
    }
    /**
     * Configuration system settings, containing settings which are applied identically for all
     * defined users. Only Android can read these and only a specific configuration service can
     * write these.
     *
     * @hide
     */
    public static final class Config extends NameValueTable {
        /**
         * The content:// style URL for the config table.
         *
         * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a
         *     System API.
         */
        private static final Uri CONTENT_URI =
                Uri.parse("content://" + AUTHORITY + "/config");
        private static final ContentProviderHolder sProviderHolder =
                new ContentProviderHolder(CONTENT_URI);
        // Populated lazily, guarded by class object:
        private static final NameValueCache sNameValueCache = new NameValueCache(
                CONTENT_URI,
                CALL_METHOD_GET_CONFIG,
                CALL_METHOD_PUT_CONFIG,
                sProviderHolder);
        /**
         * Look up a name in the database.
         * @param resolver to access the database with
         * @param name to look up in the table
         * @return the corresponding value, or null if not present
         *
         * @hide
         */
        // TODO(b/117663715): require a new read permission
        static String getString(ContentResolver resolver, String name) {
            return sNameValueCache.getStringForUser(resolver, name, resolver.getUserId());
        }
        /**
         * Store a name/value pair into the database.
         * <p>
         * The method takes an optional tag to associate with the setting which can be used to clear
         * only settings made by your package and associated with this tag by passing the tag to
         * {@link #resetToDefaults(ContentResolver, String)}. The value of this setting can be
         * overridden by future calls to this or other put methods, and the tag provided in those
         * calls, which may be null, will override the tag provided in this call. Any call to a put
         * method which does not accept a tag will effectively set the tag to null.
         * </p><p>
         * Also the method takes an argument whether to make the value the default for this setting.
         * If the system already specified a default value, then the one passed in here will
         * <strong>not</strong> be set as the default.
         * </p>
         *
         * @param resolver to access the database with.
         * @param name to store.
         * @param value to associate with the name.
         * @param tag to associated with the setting.
         * @param makeDefault whether to make the value the default one.
         * @return true if the value was set, false on database errors.
         *
         * @see #resetToDefaults(ContentResolver, String)
         *
         * @hide
         */
        // TODO(b/117663715): require a new write permission restricted to a single source
        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
        static boolean putString(@NonNull ContentResolver resolver,
                @NonNull String name, @Nullable String value, @Nullable String tag,
                boolean makeDefault) {
            return sNameValueCache.putStringForUser(resolver, name, value, tag, makeDefault,
                    resolver.getUserId());
        }
        /**
         * Reset the settings to their defaults. This would reset <strong>only</strong> settings set
         * by the caller's package. Passing in the optional tag will reset only settings changed by
         * your package and associated with this tag.
         *
         * @param resolver Handle to the content resolver.
         * @param tag Optional tag which should be associated with the settings to reset.
         *
         * @see #putString(ContentResolver, String, String, String, boolean)
         *
         * @hide
         */
        // TODO(b/117663715): require a new write permission restricted to a single source
        @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
        static void resetToDefaults(@NonNull ContentResolver resolver,
                @Nullable String tag) {
            try {
                Bundle arg = new Bundle();
                arg.putInt(CALL_METHOD_USER_KEY, resolver.getUserId());
                if (tag != null) {
                    arg.putString(CALL_METHOD_TAG_KEY, tag);
                }
                arg.putInt(CALL_METHOD_RESET_MODE_KEY, RESET_MODE_PACKAGE_DEFAULTS);
                IContentProvider cp = sProviderHolder.getProvider(resolver);
                cp.call(resolver.getPackageName(), CALL_METHOD_RESET_CONFIG, null, arg);
            } catch (RemoteException e) {
                Log.w(TAG, "Can't reset to defaults for " + CONTENT_URI, e);
            }
        }
    }
    /**
     * User-defined bookmarks and shortcuts.  The target of each bookmark is an
     * Intent URL, allowing it to be either a web page or a particular
+7 −0
Original line number Diff line number Diff line
@@ -35,6 +35,13 @@ class SettingsProtoDumpUtil {

    static void dumpProtoLocked(SettingsProvider.SettingsRegistry settingsRegistry,
            ProtoOutputStream proto) {
        // Config settings
        SettingsState configSettings = settingsRegistry.getSettingsLocked(
                SettingsProvider.SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
        if (configSettings != null) {
            // TODO(b/113100523): dump configuration settings after they are added
        }

        // Global settings
        SettingsState globalSettings = settingsRegistry.getSettingsLocked(
                SettingsProvider.SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
+122 −2
Original line number Diff line number Diff line
@@ -180,6 +180,7 @@ public class SettingsProvider extends ContentProvider {
    public static final int SETTINGS_TYPE_SYSTEM = SettingsState.SETTINGS_TYPE_SYSTEM;
    public static final int SETTINGS_TYPE_SECURE = SettingsState.SETTINGS_TYPE_SECURE;
    public static final int SETTINGS_TYPE_SSAID = SettingsState.SETTINGS_TYPE_SSAID;
    public static final int SETTINGS_TYPE_CONFIG = SettingsState.SETTINGS_TYPE_CONFIG;

    private static final Bundle NULL_SETTING_BUNDLE = Bundle.forPair(
            Settings.NameValueTable.VALUE, null);
@@ -189,6 +190,13 @@ public class SettingsProvider extends ContentProvider {
    private static final Set<String> OVERLAY_ALLOWED_SYSTEM_INSTANT_APP_SETTINGS = new ArraySet<>();
    private static final Set<String> OVERLAY_ALLOWED_SECURE_INSTANT_APP_SETTINGS = new ArraySet<>();

    /**
     * TODO(b/113100523): Move this to DeviceConfig.java when it is added, and expose it as a System
     *     API.
     */
    private static final Uri CONFIG_CONTENT_URI =
            Uri.parse("content://" + Settings.AUTHORITY + "/config");

    static {
        for (String name : Resources.getSystem().getStringArray(
                com.android.internal.R.array.config_allowedGlobalInstantAppSettings)) {
@@ -380,6 +388,11 @@ public class SettingsProvider extends ContentProvider {
    public Bundle call(String method, String name, Bundle args) {
        final int requestingUserId = getRequestingUserId(args);
        switch (method) {
            case Settings.CALL_METHOD_GET_CONFIG: {
                Setting setting = getConfigSetting(name);
                return packageValueForCallResult(setting, isTrackingGeneration(args));
            }

            case Settings.CALL_METHOD_GET_GLOBAL: {
                Setting setting = getGlobalSetting(name);
                return packageValueForCallResult(setting, isTrackingGeneration(args));
@@ -396,6 +409,14 @@ public class SettingsProvider extends ContentProvider {
                return packageValueForCallResult(setting, isTrackingGeneration(args));
            }

            case Settings.CALL_METHOD_PUT_CONFIG: {
                String value = getSettingValue(args);
                String tag = getSettingTag(args);
                final boolean makeDefault = getSettingMakeDefault(args);
                insertConfigSetting(name, value, tag, makeDefault, requestingUserId, false);
                break;
            }

            case Settings.CALL_METHOD_PUT_GLOBAL: {
                String value = getSettingValue(args);
                String tag = getSettingTag(args);
@@ -418,6 +439,13 @@ public class SettingsProvider extends ContentProvider {
                break;
            }

            case Settings.CALL_METHOD_RESET_CONFIG: {
                final int mode = getResetModeEnforcingPermission(args);
                String tag = getSettingTag(args);
                resetConfigSetting(requestingUserId, mode, tag);
                break;
            }

            case Settings.CALL_METHOD_RESET_GLOBAL: {
                final int mode = getResetModeEnforcingPermission(args);
                String tag = getSettingTag(args);
@@ -725,6 +753,15 @@ public class SettingsProvider extends ContentProvider {
    @GuardedBy("mLock")
    private void dumpForUserLocked(int userId, PrintWriter pw) {
        if (userId == UserHandle.USER_SYSTEM) {
            pw.println("CONFIG SETTINGS (user " + userId + ")");
            SettingsState configSettings = mSettingsRegistry.getSettingsLocked(
                    SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
            if (configSettings != null) {
                dumpSettingsLocked(configSettings, pw);
                pw.println();
                configSettings.dumpHistoricalOperations(pw);
            }

            pw.println("GLOBAL SETTINGS (user " + userId + ")");
            SettingsState globalSettings = mSettingsRegistry.getSettingsLocked(
                    SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
@@ -939,6 +976,69 @@ public class SettingsProvider extends ContentProvider {
        });
    }

    private Setting getConfigSetting(String name) {
        if (DEBUG) {
            Slog.v(LOG_TAG, "getConfigSetting(" + name + ")");
        }

        // TODO(b/117663715): Ensure the caller can access the setting.
        // enforceSettingReadable(name, SETTINGS_TYPE_CONFIG, UserHandle.getCallingUserId());

        // Get the value.
        synchronized (mLock) {
            return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_CONFIG,
                    UserHandle.USER_SYSTEM, name);
        }
    }

    private boolean insertConfigSetting(String name, String value, String tag,
            boolean makeDefault, int requestingUserId, boolean forceNotify) {
        if (DEBUG) {
            Slog.v(LOG_TAG, "insertConfigSetting(" + name + ", " + value  + ", "
                    + ", " + tag + ", " + makeDefault + ", " + requestingUserId
                    + ", " + forceNotify + ")");
        }
        return mutateConfigSetting(name, value, tag, makeDefault, requestingUserId,
                MUTATION_OPERATION_INSERT, forceNotify, 0);
    }

    private void resetConfigSetting(int requestingUserId, int mode, String tag) {
        if (DEBUG) {
            Slog.v(LOG_TAG, "resetConfigSetting(" + requestingUserId + ", "
                    + mode + ", " + tag + ")");
        }
        mutateConfigSetting(null, null, tag, false, requestingUserId,
                MUTATION_OPERATION_RESET, false, mode);
    }

    private boolean mutateConfigSetting(String name, String value, String tag,
            boolean makeDefault, int requestingUserId, int operation, boolean forceNotify,
            int mode) {
        // TODO(b/117663715): check the new permission when it's added.
        // enforceWritePermission(Manifest.permission.WRITE_SECURE_SETTINGS);

        // Resolve the userId on whose behalf the call is made.
        final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(requestingUserId);

        // Perform the mutation.
        synchronized (mLock) {
            switch (operation) {
                case MUTATION_OPERATION_INSERT: {
                    return mSettingsRegistry.insertSettingLocked(SETTINGS_TYPE_CONFIG,
                            UserHandle.USER_SYSTEM, name, value, tag, makeDefault,
                            getCallingPackage(), forceNotify, null);
                }

                case MUTATION_OPERATION_RESET: {
                    mSettingsRegistry.resetSettingsLocked(SETTINGS_TYPE_CONFIG,
                            UserHandle.USER_SYSTEM, getCallingPackage(), mode, tag);
                } return true;
            }
        }

        return false;
    }

    private Cursor getAllGlobalSettings(String[] projection) {
        if (DEBUG) {
            Slog.v(LOG_TAG, "getAllGlobalSettings()");
@@ -2132,6 +2232,7 @@ public class SettingsProvider extends ContentProvider {
        private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
        private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
        private static final String SETTINGS_FILE_SSAID = "settings_ssaid.xml";
        private static final String SETTINGS_FILE_CONFIG = "settings_config.xml";

        private static final String SSAID_USER_KEY = "userkey";

@@ -2303,6 +2404,13 @@ public class SettingsProvider extends ContentProvider {
            // Migrate the setting for this user if needed.
            migrateLegacySettingsForUserIfNeededLocked(userId);

            // Ensure config settings loaded if owner.
            if (userId == UserHandle.USER_SYSTEM) {
                final int configKey
                        = makeKey(SETTINGS_TYPE_CONFIG, UserHandle.USER_SYSTEM);
                ensureSettingsStateLocked(configKey);
            }

            // Ensure global settings loaded if owner.
            if (userId == UserHandle.USER_SYSTEM) {
                final int globalKey = makeKey(SETTINGS_TYPE_GLOBAL, UserHandle.USER_SYSTEM);
@@ -2853,6 +2961,10 @@ public class SettingsProvider extends ContentProvider {
            }
        }

        private boolean isConfigSettingsKey(int key) {
            return getTypeFromKey(key) == SETTINGS_TYPE_CONFIG;
        }

        private boolean isGlobalSettingsKey(int key) {
            return getTypeFromKey(key) == SETTINGS_TYPE_GLOBAL;
        }
@@ -2870,7 +2982,11 @@ public class SettingsProvider extends ContentProvider {
        }

        private File getSettingsFile(int key) {
            if (isGlobalSettingsKey(key)) {
            if (isConfigSettingsKey(key)) {
                final int userId = getUserIdFromKey(key);
                return new File(Environment.getUserSystemDirectory(userId),
                        SETTINGS_FILE_CONFIG);
            } else if (isGlobalSettingsKey(key)) {
                final int userId = getUserIdFromKey(key);
                return new File(Environment.getUserSystemDirectory(userId),
                        SETTINGS_FILE_GLOBAL);
@@ -2892,7 +3008,10 @@ public class SettingsProvider extends ContentProvider {
        }

        private Uri getNotificationUriFor(int key, String name) {
            if (isGlobalSettingsKey(key)) {
            if (isConfigSettingsKey(key)) {
                return (name != null) ? Uri.withAppendedPath(CONFIG_CONTENT_URI, name)
                        : CONFIG_CONTENT_URI;
            } else if (isGlobalSettingsKey(key)) {
                return (name != null) ? Uri.withAppendedPath(Settings.Global.CONTENT_URI, name)
                        : Settings.Global.CONTENT_URI;
            } else if (isSecureSettingsKey(key)) {
@@ -2908,6 +3027,7 @@ public class SettingsProvider extends ContentProvider {

        private int getMaxBytesPerPackageForType(int type) {
            switch (type) {
                case SETTINGS_TYPE_CONFIG:
                case SETTINGS_TYPE_GLOBAL:
                case SETTINGS_TYPE_SECURE:
                case SETTINGS_TYPE_SSAID: {
+4 −2
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.os.SystemClock;
import android.os.UserHandle;
import android.provider.Settings;
import android.provider.Settings.Global;
import android.providers.settings.GlobalSettingsProto;
import android.providers.settings.SettingsOperationProto;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -67,7 +66,6 @@ import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * This class contains the state for one type of settings. It is responsible
@@ -205,6 +203,7 @@ final class SettingsState {
    public static final int SETTINGS_TYPE_SYSTEM = 1;
    public static final int SETTINGS_TYPE_SECURE = 2;
    public static final int SETTINGS_TYPE_SSAID = 3;
    public static final int SETTINGS_TYPE_CONFIG = 4;

    public static final int SETTINGS_TYPE_MASK = 0xF0000000;
    public static final int SETTINGS_TYPE_SHIFT = 28;
@@ -223,6 +222,9 @@ final class SettingsState {

    public static String settingTypeToString(int type) {
        switch (type) {
            case SETTINGS_TYPE_CONFIG: {
                return "SETTINGS_CONFIG";
            }
            case SETTINGS_TYPE_GLOBAL: {
                return "SETTINGS_GLOBAL";
            }