diff --git a/packages/SettingsProvider/res/values/blocked_settings.xml b/packages/SettingsProvider/res/values/blocked_settings.xml
new file mode 100644
index 0000000000000..b54b74ee1d3ee
--- /dev/null
+++ b/packages/SettingsProvider/res/values/blocked_settings.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/SettingsProvider/res/values/overlayable.xml b/packages/SettingsProvider/res/values/overlayable.xml
new file mode 100644
index 0000000000000..dc41a77d0e2d6
--- /dev/null
+++ b/packages/SettingsProvider/res/values/overlayable.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index c19a340498e71..fb558abe38658 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -66,6 +66,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.time.DateTimeException;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
@@ -250,7 +251,13 @@ public class SettingsBackupAgent extends BackupAgentHelper {
@Override
public void onRestore(BackupDataInput data, int appVersionCode,
- ParcelFileDescriptor newState) throws IOException {
+ ParcelFileDescriptor newState) {
+ throw new RuntimeException("SettingsBackupAgent has been migrated to use key exclusion");
+ }
+
+ @Override
+ public void onRestore(BackupDataInput data, long appVersionCode,
+ ParcelFileDescriptor newState, Set dynamicBlockList) throws IOException {
if (DEBUG) {
Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode
@@ -266,7 +273,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
// versionCode of com.android.providers.settings corresponds to SDK_INT
- mRestoredFromSdkInt = appVersionCode;
+ mRestoredFromSdkInt = (int) appVersionCode;
HashSet movedToGlobal = new HashSet();
Settings.System.getMovedToGlobalSettings(movedToGlobal);
@@ -292,16 +299,29 @@ public class SettingsBackupAgent extends BackupAgentHelper {
switch (key) {
case KEY_SYSTEM :
restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
- movedToSecure);
+ movedToSecure, R.array.restore_blocked_system_settings,
+ dynamicBlockList);
mSettingsHelper.applyAudioSettings();
break;
case KEY_SECURE :
- restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, null);
+ restoreSettings(
+ data,
+ Settings.Secure.CONTENT_URI,
+ movedToGlobal,
+ null,
+ R.array.restore_blocked_secure_settings,
+ dynamicBlockList);
break;
case KEY_GLOBAL :
- restoreSettings(data, Settings.Global.CONTENT_URI, null, movedToSecure);
+ restoreSettings(
+ data,
+ Settings.Global.CONTENT_URI,
+ null,
+ movedToSecure,
+ R.array.restore_blocked_global_settings,
+ dynamicBlockList);
break;
case KEY_WIFI_SUPPLICANT :
@@ -345,7 +365,10 @@ public class SettingsBackupAgent extends BackupAgentHelper {
case KEY_DEVICE_SPECIFIC_CONFIG:
byte[] restoredDeviceSpecificConfig = new byte[size];
data.readEntityData(restoredDeviceSpecificConfig, 0, size);
- restoreDeviceSpecificConfig(restoredDeviceSpecificConfig);
+ restoreDeviceSpecificConfig(
+ restoredDeviceSpecificConfig,
+ R.array.restore_blocked_device_specific_settings,
+ dynamicBlockList);
break;
default :
@@ -394,14 +417,22 @@ public class SettingsBackupAgent extends BackupAgentHelper {
byte[] buffer = new byte[nBytes];
in.readFully(buffer, 0, nBytes);
restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
- movedToSecure);
+ movedToSecure, R.array.restore_blocked_system_settings,
+ Collections.emptySet());
// secure settings
nBytes = in.readInt();
if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
if (nBytes > buffer.length) buffer = new byte[nBytes];
in.readFully(buffer, 0, nBytes);
- restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, null);
+ restoreSettings(
+ buffer,
+ nBytes,
+ Settings.Secure.CONTENT_URI,
+ movedToGlobal,
+ null,
+ R.array.restore_blocked_secure_settings,
+ Collections.emptySet());
// Global only if sufficiently new
if (version >= FULL_BACKUP_ADDED_GLOBAL) {
@@ -411,7 +442,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
in.readFully(buffer, 0, nBytes);
movedToGlobal.clear(); // no redirection; this *is* the global namespace
restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
- movedToSecure);
+ movedToSecure, R.array.restore_blocked_global_settings,
+ Collections.emptySet());
}
// locale
@@ -612,8 +644,13 @@ public class SettingsBackupAgent extends BackupAgentHelper {
return baos.toByteArray();
}
- private void restoreSettings(BackupDataInput data, Uri contentUri,
- HashSet movedToGlobal, Set movedToSecure) {
+ private void restoreSettings(
+ BackupDataInput data,
+ Uri contentUri,
+ HashSet movedToGlobal,
+ Set movedToSecure,
+ int blockedSettingsArrayId,
+ Set dynamicBlockList) {
byte[] settings = new byte[data.getDataSize()];
try {
data.readEntityData(settings, 0, settings.length);
@@ -621,16 +658,44 @@ public class SettingsBackupAgent extends BackupAgentHelper {
Log.e(TAG, "Couldn't read entity data");
return;
}
- restoreSettings(settings, settings.length, contentUri, movedToGlobal, movedToSecure);
+ restoreSettings(
+ settings,
+ settings.length,
+ contentUri,
+ movedToGlobal,
+ movedToSecure,
+ blockedSettingsArrayId,
+ dynamicBlockList);
}
- private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
- HashSet movedToGlobal, Set movedToSecure) {
- restoreSettings(settings, 0, bytes, contentUri, movedToGlobal, movedToSecure);
+ private void restoreSettings(
+ byte[] settings,
+ int bytes,
+ Uri contentUri,
+ HashSet movedToGlobal,
+ Set movedToSecure,
+ int blockedSettingsArrayId,
+ Set dynamicBlockList) {
+ restoreSettings(
+ settings,
+ 0,
+ bytes,
+ contentUri,
+ movedToGlobal,
+ movedToSecure,
+ blockedSettingsArrayId,
+ dynamicBlockList);
}
- private void restoreSettings(byte[] settings, int pos, int bytes, Uri contentUri,
- HashSet movedToGlobal, Set movedToSecure) {
+ private void restoreSettings(
+ byte[] settings,
+ int pos,
+ int bytes,
+ Uri contentUri,
+ HashSet movedToGlobal,
+ Set movedToSecure,
+ int blockedSettingsArrayId,
+ Set dynamicBlockList) {
if (DEBUG) {
Log.i(TAG, "restoreSettings: " + contentUri);
}
@@ -662,9 +727,20 @@ public class SettingsBackupAgent extends BackupAgentHelper {
SettingsHelper settingsHelper = mSettingsHelper;
ContentResolver cr = getContentResolver();
- final int whiteListSize = whitelist.length;
- for (int i = 0; i < whiteListSize; i++) {
- String key = whitelist[i];
+ Set blockedSettings = getBlockedSettings(blockedSettingsArrayId);
+
+ for (String key : whitelist) {
+ boolean isBlockedBySystem = blockedSettings != null && blockedSettings.contains(key);
+ if (isBlockedBySystem || isBlockedByDynamicList(dynamicBlockList, contentUri, key)) {
+ Log.i(
+ TAG,
+ "Key "
+ + key
+ + " removed from restore by "
+ + (isBlockedBySystem ? "system" : "dynamic")
+ + " block list");
+ continue;
+ }
String value = null;
boolean hasValueToRestore = false;
@@ -722,6 +798,19 @@ public class SettingsBackupAgent extends BackupAgentHelper {
}
}
+ private boolean isBlockedByDynamicList(Set dynamicBlockList, Uri areaUri, String key) {
+ String contentKey = Uri.withAppendedPath(areaUri, key).toString();
+ return dynamicBlockList.contains(contentKey);
+ }
+
+ // There may be other sources of blocked settings, so I'm separating out this
+ // code to make it easy to modify in the future.
+ @VisibleForTesting
+ protected Set getBlockedSettings(int blockedSettingsArrayId) {
+ String[] blockedSettings = getResources().getStringArray(blockedSettingsArrayId);
+ return new HashSet<>(Arrays.asList(blockedSettings));
+ }
+
private boolean isValidSettingValue(String key, String value,
Map validators) {
if (key == null || validators == null) {
@@ -998,10 +1087,13 @@ public class SettingsBackupAgent extends BackupAgentHelper {
* Restore the device specific settings.
*
* @param data The byte array holding a backed up version of another devices settings.
+ * @param blockedSettingsArrayId The string array resource holding the settings not to restore.
+ * @param dynamicBlocklist The dynamic list of settings not to restore fed into this agent.
* @return true if the restore succeeded, false if it was stopped.
*/
@VisibleForTesting
- boolean restoreDeviceSpecificConfig(byte[] data) {
+ boolean restoreDeviceSpecificConfig(byte[] data, int blockedSettingsArrayId,
+ Set dynamicBlocklist) {
// We're using an AtomicInteger to wrap the position int and allow called methods to
// modify it.
AtomicInteger pos = new AtomicInteger(0);
@@ -1013,7 +1105,14 @@ public class SettingsBackupAgent extends BackupAgentHelper {
int dataStart = pos.get();
restoreSettings(
- data, dataStart, data.length, Settings.Secure.CONTENT_URI, null, null);
+ data,
+ dataStart,
+ data.length,
+ Settings.Secure.CONTENT_URI,
+ null,
+ null,
+ blockedSettingsArrayId,
+ dynamicBlocklist);
updateWindowManagerIfNeeded(originalDensity);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
index 57e22db6a55cd..e6508823c7e3c 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
@@ -37,14 +37,14 @@ import android.test.mock.MockContentResolver;
import androidx.test.runner.AndroidJUnit4;
-import com.android.internal.annotations.VisibleForTesting;
-
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -85,11 +85,32 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest {
assertEquals("Not all values backed up.", TEST_VALUES.keySet(), helper.mReadEntries);
- mAgentUnderTest.restoreDeviceSpecificConfig(settingsBackup);
+ mAgentUnderTest.restoreDeviceSpecificConfig(
+ settingsBackup,
+ R.array.restore_blocked_device_specific_settings,
+ Collections.emptySet());
assertEquals("Not all values were restored.", TEST_VALUES, helper.mWrittenValues);
}
+ @Test
+ public void testRoundTripDeviceSpecificSettingsWithBlock() throws IOException {
+ TestSettingsHelper helper = new TestSettingsHelper(mContext);
+ mAgentUnderTest.mSettingsHelper = helper;
+
+ byte[] settingsBackup = mAgentUnderTest.getDeviceSpecificConfiguration();
+
+ assertEquals("Not all values backed up.", TEST_VALUES.keySet(), helper.mReadEntries);
+ mAgentUnderTest.setBlockedSettings(TEST_VALUES.keySet().toArray(new String[0]));
+
+ mAgentUnderTest.restoreDeviceSpecificConfig(
+ settingsBackup,
+ R.array.restore_blocked_device_specific_settings,
+ Collections.emptySet());
+
+ assertTrue("Not all values were blocked.", helper.mWrittenValues.isEmpty());
+ }
+
@Test
public void testGeneratedHeaderMatchesCurrentDevice() throws IOException {
mAgentUnderTest.mSettingsHelper = new TestSettingsHelper(mContext);
@@ -148,7 +169,10 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest {
assertFalse(
"Blocking isSourceAcceptable did not stop restore",
- mAgentUnderTest.restoreDeviceSpecificConfig(data));
+ mAgentUnderTest.restoreDeviceSpecificConfig(
+ data,
+ R.array.restore_blocked_device_specific_settings,
+ Collections.emptySet()));
}
private byte[] generateUncorruptedHeader() throws IOException {
@@ -184,14 +208,34 @@ public class SettingsBackupAgentTest extends BaseSettingsProviderTest {
}
}
+ private byte[] generateSingleKeyTestBackupData(String key, String value) throws IOException {
+ try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
+ os.write(SettingsBackupAgent.toByteArray(key));
+ os.write(SettingsBackupAgent.toByteArray(value));
+ return os.toByteArray();
+ }
+ }
+
private static class TestFriendlySettingsBackupAgent extends SettingsBackupAgent {
private Boolean mForcedDeviceInfoRestoreAcceptability = null;
+ private String[] mBlockedSettings = null;
void setForcedDeviceInfoRestoreAcceptability(boolean value) {
mForcedDeviceInfoRestoreAcceptability = value;
}
- @VisibleForTesting
+ void setBlockedSettings(String... blockedSettings) {
+ mBlockedSettings = blockedSettings;
+ }
+
+ @Override
+ protected Set getBlockedSettings(int blockedSettingsArrayId) {
+ return mBlockedSettings == null
+ ? super.getBlockedSettings(blockedSettingsArrayId)
+ : new HashSet<>(Arrays.asList(mBlockedSettings));
+ }
+
+ @Override
boolean isSourceAcceptable(byte[] data, AtomicInteger pos) {
return mForcedDeviceInfoRestoreAcceptability == null
? super.isSourceAcceptable(data, pos)