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

Commit 018f5534 authored by Ruslan Tkhakokhov's avatar Ruslan Tkhakokhov
Browse files

Add Settings.(System/Secure).putStringOverrideableByRestore

Bug: 144838882
Test: 1) SettingsStateTest
      2) Manually change settings on the device; verify isModified flag
         is set; reboot; make sure changes are persisted.

In ag/10056253 logic was introduced to make sure settings modifications
are not overridden by restore. However, some callers still need to use
the old behavior. Modification made through
Settings.System.putStringOverrideableByRestore will be overridden by
restore.

Change-Id: I91084ef61711a77ff17b2a5ee1996fa15cb17e73
parent 484000fb
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -126,6 +126,7 @@ package android {
    field @Deprecated public static final String MODIFY_NETWORK_ACCOUNTING = "android.permission.MODIFY_NETWORK_ACCOUNTING";
    field public static final String MODIFY_PARENTAL_CONTROLS = "android.permission.MODIFY_PARENTAL_CONTROLS";
    field public static final String MODIFY_QUIET_MODE = "android.permission.MODIFY_QUIET_MODE";
    field public static final String MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE = "android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE";
    field public static final String MOVE_PACKAGE = "android.permission.MOVE_PACKAGE";
    field public static final String NETWORK_AIRPLANE_MODE = "android.permission.NETWORK_AIRPLANE_MODE";
    field public static final String NETWORK_CARRIER_PROVISIONING = "android.permission.NETWORK_CARRIER_PROVISIONING";
@@ -7935,6 +7936,10 @@ package android.provider {
    field public static final int VOLUME_HUSH_VIBRATE = 1; // 0x1
  }
  public static final class Settings.System extends android.provider.Settings.NameValueTable {
    method @RequiresPermission(android.Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE) public static boolean putString(@NonNull android.content.ContentResolver, @NonNull String, @Nullable String, boolean);
  }
  public static interface Telephony.CarrierColumns extends android.provider.BaseColumns {
    field @NonNull public static final android.net.Uri CONTENT_URI;
    field public static final String EXPIRATION_TIME = "expiration_time";
+97 −16
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ import java.util.Set;
 * The Settings provider contains global system-level device preferences.
 */
public final class Settings {
    private static final boolean DEFAULT_OVERRIDEABLE_BY_RESTORE = false;
    // Intent actions for Settings
@@ -2108,6 +2109,11 @@ public final class Settings {
     */
    public static final String CALL_METHOD_FLAGS_KEY = "_flags";
    /**
     * @hide - String argument extra to the fast-path call()-based requests
     */
    public static final String CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY = "_overrideable_by_restore";
    /** @hide - Private call() method to write to 'system' table */
    public static final String CALL_METHOD_PUT_SYSTEM = "PUT_system";
@@ -2476,7 +2482,8 @@ public final class Settings {
        }
        public boolean putStringForUser(ContentResolver cr, String name, String value,
                String tag, boolean makeDefault, final int userHandle) {
                String tag, boolean makeDefault, final int userHandle,
                boolean overrideableByRestore) {
            try {
                Bundle arg = new Bundle();
                arg.putString(Settings.NameValueTable.VALUE, value);
@@ -2487,6 +2494,9 @@ public final class Settings {
                if (makeDefault) {
                    arg.putBoolean(CALL_METHOD_MAKE_DEFAULT_KEY, true);
                }
                if (overrideableByRestore) {
                    arg.putBoolean(CALL_METHOD_OVERRIDEABLE_BY_RESTORE_KEY, true);
                }
                IContentProvider cp = mProviderHolder.getProvider(cr);
                cp.call(cr.getPackageName(), cr.getFeatureId(),
                        mProviderHolder.mUri.getAuthority(), mCallSetCommand, name, arg);
@@ -3037,10 +3047,36 @@ public final class Settings {
            return putStringForUser(resolver, name, value, resolver.getUserId());
        }
        /**
         * Store a name/value pair into the database. Values written by this method will be
         * overridden if a restore happens in the future.
         *
         * @param resolver to access the database with
         * @param name to store
         * @param value to associate with the name
         *
         * @return true if the value was set, false on database errors
         *
         * @hide
         */
        @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
        @SystemApi
        public static boolean putString(@NonNull ContentResolver resolver,
                @NonNull String name, @Nullable String value, boolean overrideableByRestore) {
            return putStringForUser(resolver, name, value, resolver.getUserId(),
                   overrideableByRestore);
        }
        /** @hide */
        @UnsupportedAppUsage
        public static boolean putStringForUser(ContentResolver resolver, String name, String value,
                int userHandle) {
            return putStringForUser(resolver, name, value, userHandle,
                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        private static boolean putStringForUser(ContentResolver resolver, String name, String value,
                int userHandle, boolean overrideableByRestore) {
            if (MOVED_TO_SECURE.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.System"
                        + " to android.provider.Settings.Secure, value is unchanged.");
@@ -3051,7 +3087,8 @@ public final class Settings {
                        + " to android.provider.Settings.Global, value is unchanged.");
                return false;
            }
            return sNameValueCache.putStringForUser(resolver, name, value, null, false, userHandle);
            return sNameValueCache.putStringForUser(resolver, name, value, null, false, userHandle,
                    overrideableByRestore);
        }
        /**
@@ -3375,7 +3412,7 @@ public final class Settings {
                    // need to store the adjusted configuration as the initial settings.
                    Settings.System.putStringForUser(
                            cr, SYSTEM_LOCALES, outConfig.getLocales().toLanguageTags(),
                            userHandle);
                            userHandle, DEFAULT_OVERRIDEABLE_BY_RESTORE);
                }
            }
        }
@@ -3408,7 +3445,8 @@ public final class Settings {
                int userHandle) {
            return Settings.System.putFloatForUser(cr, FONT_SCALE, config.fontScale, userHandle) &&
                    Settings.System.putStringForUser(
                            cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle);
                            cr, SYSTEM_LOCALES, config.getLocales().toLanguageTags(), userHandle,
                            DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /** @hide */
@@ -5210,6 +5248,24 @@ public final class Settings {
            return sNameValueCache.getStringForUser(resolver, name, userHandle);
        }
        /**
         * Store a name/value pair into the database. Values written by this method will be
         * overridden if a restore happens in the future.
         *
         * @param resolver to access the database with
         * @param name to store
         * @param value to associate with the name
         * @return true if the value was set, false on database errors
         *
         * @hide
         */
        @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
        public static boolean putString(ContentResolver resolver, String name,
                String value, boolean overrideableByRestore) {
            return putStringForUser(resolver, name, value, /* tag */ null, /* makeDefault */ false,
                    resolver.getUserId(), overrideableByRestore);
        }
        /**
         * Store a name/value pair into the database.
         * @param resolver to access the database with
@@ -5225,22 +5281,23 @@ public final class Settings {
        @UnsupportedAppUsage
        public static boolean putStringForUser(ContentResolver resolver, String name, String value,
                int userHandle) {
            return putStringForUser(resolver, name, value, null, false, userHandle);
            return putStringForUser(resolver, name, value, null, false, userHandle,
                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /** @hide */
        @UnsupportedAppUsage
        public static boolean putStringForUser(@NonNull ContentResolver resolver,
                @NonNull String name, @Nullable String value, @Nullable String tag,
                boolean makeDefault, @UserIdInt int userHandle) {
                boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore) {
            if (MOVED_TO_GLOBAL.contains(name)) {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Secure"
                        + " to android.provider.Settings.Global");
                return Global.putStringForUser(resolver, name, value,
                        tag, makeDefault, userHandle);
                        tag, makeDefault, userHandle, DEFAULT_OVERRIDEABLE_BY_RESTORE);
            }
            return sNameValueCache.putStringForUser(resolver, name, value, tag,
                    makeDefault, userHandle);
                    makeDefault, userHandle, overrideableByRestore);
        }
        /**
@@ -5289,7 +5346,7 @@ public final class Settings {
                @NonNull String name, @Nullable String value, @Nullable String tag,
                boolean makeDefault) {
            return putStringForUser(resolver, name, value, tag, makeDefault,
                    resolver.getUserId());
                    resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /**
@@ -12972,7 +13029,29 @@ public final class Settings {
         */
        public static boolean putString(ContentResolver resolver,
                String name, String value) {
            return putStringForUser(resolver, name, value, null, false, resolver.getUserId());
            return putStringForUser(resolver, name, value, null, false, resolver.getUserId(),
                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /**
         * Store a name/value pair into the database.
         *
         * @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.
         * @param overrideableByRestore whether restore can override this value
         * @return true if the value was set, false on database errors
         *
         * @hide
         */
        @RequiresPermission(Manifest.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE)
        public static boolean putString(@NonNull ContentResolver resolver,
                @NonNull String name, @Nullable String value, @Nullable String tag,
                boolean makeDefault, boolean overrideableByRestore) {
            return putStringForUser(resolver, name, value, tag, makeDefault,
                    resolver.getUserId(), overrideableByRestore);
        }
        /**
@@ -13021,7 +13100,7 @@ public final class Settings {
                @NonNull String name, @Nullable String value, @Nullable String tag,
                boolean makeDefault) {
            return putStringForUser(resolver, name, value, tag, makeDefault,
                    resolver.getUserId());
                    resolver.getUserId(), DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /**
@@ -13083,13 +13162,14 @@ public final class Settings {
        @UnsupportedAppUsage
        public static boolean putStringForUser(ContentResolver resolver,
                String name, String value, int userHandle) {
            return putStringForUser(resolver, name, value, null, false, userHandle);
            return putStringForUser(resolver, name, value, null, false, userHandle,
                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /** @hide */
        public static boolean putStringForUser(@NonNull ContentResolver resolver,
                @NonNull String name, @Nullable String value, @Nullable String tag,
                boolean makeDefault, @UserIdInt int userHandle) {
                boolean makeDefault, @UserIdInt int userHandle, boolean overrideableByRestore) {
            if (LOCAL_LOGV) {
                Log.v(TAG, "Global.putString(name=" + name + ", value=" + value
                        + " for " + userHandle);
@@ -13099,10 +13179,10 @@ public final class Settings {
                Log.w(TAG, "Setting " + name + " has moved from android.provider.Settings.Global"
                        + " to android.provider.Settings.Secure, value is unchanged.");
                return Secure.putStringForUser(resolver, name, value, tag,
                        makeDefault, userHandle);
                        makeDefault, userHandle, overrideableByRestore);
            }
            return sNameValueCache.putStringForUser(resolver, name, value, tag,
                    makeDefault, userHandle);
                    makeDefault, userHandle, overrideableByRestore);
        }
        /**
@@ -13969,7 +14049,8 @@ public final class Settings {
        static boolean putString(@NonNull ContentResolver resolver, @NonNull String namespace,
                @NonNull String name, @Nullable String value, boolean makeDefault) {
            return sNameValueCache.putStringForUser(resolver, createCompositeName(namespace, name),
                    value, null, makeDefault, resolver.getUserId());
                    value, null, makeDefault, resolver.getUserId(),
                    DEFAULT_OVERRIDEABLE_BY_RESTORE);
        }
        /**
+7 −0
Original line number Diff line number Diff line
@@ -3967,6 +3967,13 @@
    <permission android:name="android.permission.BACKUP"
        android:protectionLevel="signature|privileged" />

    <!-- @SystemApi Allows an application to make modifications to device settings such that these
         modifications will be overridden by settings restore..
    <p>Not for use by third-party applications.
         @hide -->
    <permission android:name="android.permission.MODIFY_SETTINGS_OVERRIDEABLE_BY_RESTORE"
                android:protectionLevel="signature|setup" />

    <!-- @SystemApi Allows application to manage
         {@link android.security.keystore.recovery.RecoveryController}.
         <p>Not for use by third-party applications.
+148 −93

File changed.

Preview size limit exceeded, changes collapsed.

+35 −11
Original line number Diff line number Diff line
@@ -388,17 +388,27 @@ final class SettingsState {
        }
    }

    // The settings provider must hold its lock when calling here.
    @GuardedBy("mLock")
    public boolean insertSettingOverrideableByRestoreLocked(String name, String value, String tag,
            boolean makeDefault, String packageName) {
        return insertSettingLocked(name, value, tag, makeDefault, false, packageName,
                /* overrideableByRestore */ true);
    }

    // The settings provider must hold its lock when calling here.
    @GuardedBy("mLock")
    public boolean insertSettingLocked(String name, String value, String tag,
            boolean makeDefault, String packageName) {
        return insertSettingLocked(name, value, tag, makeDefault, false, packageName);
        return insertSettingLocked(name, value, tag, makeDefault, false, packageName,
                /* overrideableByRestore */ false);
    }

    // The settings provider must hold its lock when calling here.
    @GuardedBy("mLock")
    public boolean insertSettingLocked(String name, String value, String tag,
            boolean makeDefault, boolean forceNonSystemPackage, String packageName) {
            boolean makeDefault, boolean forceNonSystemPackage, String packageName,
            boolean overrideableByRestore) {
        if (TextUtils.isEmpty(name)) {
            return false;
        }
@@ -409,7 +419,8 @@ final class SettingsState {
        Setting newState;

        if (oldState != null) {
            if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage)) {
            if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage,
                    overrideableByRestore)) {
                return false;
            }
            newState = oldState;
@@ -497,7 +508,8 @@ final class SettingsState {
                changedKeys.add(key); // key was added
            } else if (state.value != value) {
                oldValue = state.value;
                state.update(value, false, packageName, null, true);
                state.update(value, false, packageName, null, true,
                        /* overrideableByRestore */ false);
                changedKeys.add(key); // key was updated
            } else {
                // this key/value already exists, no change and no logging necessary
@@ -1144,7 +1156,7 @@ final class SettingsState {
        private String tag;
        // Whether the default is set by the system
        private boolean defaultFromSystem;
        // Whether the value of this setting will be preserved when restore happens..
        // Whether the value of this setting will be preserved when restore happens.
        private boolean isValuePreservedInRestore;

        public Setting(Setting other) {
@@ -1155,17 +1167,22 @@ final class SettingsState {
            id = other.id;
            defaultFromSystem = other.defaultFromSystem;
            tag = other.tag;
            isValuePreservedInRestore = other.isValuePreservedInRestore;
        }

        public Setting(String name, String value, boolean makeDefault, String packageName,
                String tag) {
            this.name = name;
            update(value, makeDefault, packageName, tag, false);
            // overrideableByRestore = true as the first initialization isn't considered a
            // modification.
            update(value, makeDefault, packageName, tag, false,
                    /* overrideableByRestore */ true);
        }

        public Setting(String name, String value, String defaultValue,
                String packageName, String tag, boolean fromSystem, String id) {
            this(name, value, defaultValue, packageName, tag, fromSystem, id, false);
            this(name, value, defaultValue, packageName, tag, fromSystem, id,
                    /* isOverrideableByRestore */ false);
        }

        Setting(String name, String value, String defaultValue,
@@ -1234,7 +1251,9 @@ final class SettingsState {

        /** @return whether the value changed */
        public boolean reset() {
            return update(this.defaultValue, false, packageName, null, true);
            // overrideableByRestore = true as resetting to default value isn't considered a
            // modification.
            return update(this.defaultValue, false, packageName, null, true, true);
        }

        public boolean isTransient() {
@@ -1246,7 +1265,7 @@ final class SettingsState {
        }

        public boolean update(String value, boolean setDefault, String packageName, String tag,
                boolean forceNonSystemPackage) {
                boolean forceNonSystemPackage, boolean overrideableByRestore) {
            if (NULL_VALUE.equals(value)) {
                value = null;
            }
@@ -1279,17 +1298,22 @@ final class SettingsState {
                }
            }

            // isValuePreservedInRestore shouldn't change back to false if it has been set to true.
            boolean isPreserved = this.isValuePreservedInRestore || !overrideableByRestore;

            // Is something gonna change?
            if (Objects.equals(value, this.value)
                    && Objects.equals(defaultValue, this.defaultValue)
                    && Objects.equals(packageName, this.packageName)
                    && Objects.equals(tag, this.tag)
                    && defaultFromSystem == this.defaultFromSystem) {
                    && defaultFromSystem == this.defaultFromSystem
                    && isPreserved == this.isValuePreservedInRestore) {
                return false;
            }

            init(name, value, tag, defaultValue, packageName, defaultFromSystem,
                    String.valueOf(mNextId++), /* isValuePreservedInRestore */ true);
                    String.valueOf(mNextId++), isPreserved);

            return true;
        }

Loading