Skip to content

Commit a571a58

Browse files
committed
Settings are restored in alphabetical order rather in order of dependency.
Settings were restore in alphabetical order and capturing dependency among them required keys to be chosen in such a way that after sorting they apprear in dependency order. Now settings are exported and restored in the order they are declared in the arrays of settings to backup. Hence, the order in this array will capture the dependency order. bug:5343351 Change-Id: I93a40bcdd194943cd6f85aa18f1557d546e38274
1 parent aff24a5 commit a571a58

2 files changed

Lines changed: 137 additions & 122 deletions

File tree

core/java/android/provider/Settings.java

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1882,6 +1882,11 @@ public static void setShowGTalkServiceStatus(ContentResolver cr, boolean flag) {
18821882
/**
18831883
* Settings to backup. This is here so that it's in the same place as the settings
18841884
* keys and easy to update.
1885+
*
1886+
* NOTE: Settings are backed up and restored in the order they appear
1887+
* in this array. If you have one setting depending on another,
1888+
* make sure that they are ordered appropriately.
1889+
*
18851890
* @hide
18861891
*/
18871892
public static final String[] SETTINGS_TO_BACKUP = {
@@ -4048,6 +4053,12 @@ public static final String getBluetoothInputDevicePriorityKey(String address) {
40484053
public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
40494054

40504055
/**
4056+
* This are the settings to be backed up.
4057+
*
4058+
* NOTE: Settings are backed up and restored in the order they appear
4059+
* in this array. If you have one setting depending on another,
4060+
* make sure that they are ordered appropriately.
4061+
*
40514062
* @hide
40524063
*/
40534064
public static final String[] SETTINGS_TO_BACKUP = {
@@ -4056,11 +4067,11 @@ public static final String getBluetoothInputDevicePriorityKey(String address) {
40564067
PARENTAL_CONTROL_ENABLED,
40574068
PARENTAL_CONTROL_REDIRECT_URL,
40584069
USB_MASS_STORAGE_ENABLED,
4059-
ACCESSIBILITY_ENABLED,
40604070
ACCESSIBILITY_SCRIPT_INJECTION,
40614071
BACKUP_AUTO_RESTORE,
40624072
ENABLED_ACCESSIBILITY_SERVICES,
40634073
TOUCH_EXPLORATION_ENABLED,
4074+
ACCESSIBILITY_ENABLED,
40644075
TTS_USE_DEFAULTS,
40654076
TTS_DEFAULT_RATE,
40664077
TTS_DEFAULT_PITCH,

packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java

Lines changed: 125 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@
1616

1717
package com.android.providers.settings;
1818

19+
import android.app.backup.BackupAgentHelper;
20+
import android.app.backup.BackupDataInput;
21+
import android.app.backup.BackupDataOutput;
22+
import android.app.backup.FullBackupDataOutput;
23+
import android.content.ContentValues;
24+
import android.content.Context;
25+
import android.database.Cursor;
26+
import android.net.Uri;
27+
import android.net.wifi.WifiManager;
28+
import android.os.FileUtils;
29+
import android.os.ParcelFileDescriptor;
30+
import android.os.Process;
31+
import android.provider.Settings;
32+
import android.util.Log;
33+
1934
import java.io.BufferedOutputStream;
2035
import java.io.BufferedReader;
2136
import java.io.BufferedWriter;
@@ -27,28 +42,13 @@
2742
import java.io.FileOutputStream;
2843
import java.io.FileReader;
2944
import java.io.FileWriter;
30-
import java.io.InputStream;
3145
import java.io.IOException;
46+
import java.io.InputStream;
3247
import java.io.OutputStream;
33-
import java.util.Arrays;
48+
import java.util.HashMap;
49+
import java.util.Map;
3450
import java.util.zip.CRC32;
3551

36-
import android.app.backup.BackupDataInput;
37-
import android.app.backup.BackupDataOutput;
38-
import android.app.backup.BackupAgentHelper;
39-
import android.app.backup.FullBackupDataOutput;
40-
import android.content.ContentValues;
41-
import android.content.Context;
42-
import android.database.Cursor;
43-
import android.net.Uri;
44-
import android.net.wifi.WifiManager;
45-
import android.os.FileUtils;
46-
import android.os.ParcelFileDescriptor;
47-
import android.os.Process;
48-
import android.provider.Settings;
49-
import android.text.TextUtils;
50-
import android.util.Log;
51-
5252
/**
5353
* Performs backup and restore of the System and Secure settings.
5454
* List of settings that are backed up are stored in the Settings.java file
@@ -79,8 +79,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
7979
// Versioning of the 'full backup' format
8080
private static final int FULL_BACKUP_VERSION = 1;
8181

82-
private static String[] sortedSystemKeys = null;
83-
private static String[] sortedSecureKeys = null;
82+
private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
8483

8584
private static final byte[] EMPTY_DATA = new byte[0];
8685

@@ -112,6 +111,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
112111
private WifiManager mWfm;
113112
private static String mWifiConfigFile;
114113

114+
@Override
115115
public void onCreate() {
116116
if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
117117

@@ -348,26 +348,17 @@ private long writeIfChanged(long oldChecksum, String key, byte[] data,
348348
}
349349

350350
private byte[] getSystemSettings() {
351-
Cursor sortedCursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION,
352-
null, null, Settings.NameValueTable.NAME);
353-
// Copy and sort the array
354-
if (sortedSystemKeys == null) {
355-
sortedSystemKeys = copyAndSort(Settings.System.SETTINGS_TO_BACKUP);
356-
}
357-
byte[] result = extractRelevantValues(sortedCursor, sortedSystemKeys);
358-
sortedCursor.close();
351+
Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
352+
null, null);
353+
byte[] result = extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
354+
cursor.close();
359355
return result;
360356
}
361357

362358
private byte[] getSecureSettings() {
363-
Cursor sortedCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION,
364-
null, null, Settings.NameValueTable.NAME);
365-
// Copy and sort the array
366-
if (sortedSecureKeys == null) {
367-
sortedSecureKeys = copyAndSort(Settings.Secure.SETTINGS_TO_BACKUP);
368-
}
369-
byte[] result = extractRelevantValues(sortedCursor, sortedSecureKeys);
370-
sortedCursor.close();
359+
Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
360+
null, null);
361+
byte[] result = extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
371362
return result;
372363
}
373364

@@ -383,119 +374,132 @@ private void restoreSettings(BackupDataInput data, Uri contentUri) {
383374
}
384375

385376
private void restoreSettings(byte[] settings, int bytes, Uri contentUri) {
386-
if (DEBUG) Log.i(TAG, "restoreSettings: " + contentUri);
377+
if (DEBUG) {
378+
Log.i(TAG, "restoreSettings: " + contentUri);
379+
}
380+
381+
// Figure out the white list.
387382
String[] whitelist = null;
388383
if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
389384
whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
390385
} else if (contentUri.equals(Settings.System.CONTENT_URI)) {
391386
whitelist = Settings.System.SETTINGS_TO_BACKUP;
387+
} else {
388+
throw new IllegalArgumentException("Unknown URI: " + contentUri);
392389
}
393390

394-
ContentValues cv = new ContentValues(2);
391+
// Restore only the white list data.
395392
int pos = 0;
396-
while (pos < bytes) {
397-
int length = readInt(settings, pos);
398-
pos += 4;
399-
String settingName = length > 0? new String(settings, pos, length) : null;
400-
pos += length;
401-
length = readInt(settings, pos);
402-
pos += 4;
403-
String settingValue = length > 0? new String(settings, pos, length) : null;
404-
pos += length;
405-
if (!TextUtils.isEmpty(settingName) && !TextUtils.isEmpty(settingValue)) {
406-
//Log.i(TAG, "Restore " + settingName + " = " + settingValue);
407-
408-
// Only restore settings in our list of known-acceptable data
409-
if (invalidSavedSetting(whitelist, settingName)) {
410-
continue;
393+
Map<String, String> cachedEntries = new HashMap<String, String>();
394+
ContentValues contentValues = new ContentValues(2);
395+
SettingsHelper settingsHelper = mSettingsHelper;
396+
397+
final int whiteListSize = whitelist.length;
398+
for (int i = 0; i < whiteListSize; i++) {
399+
String key = whitelist[i];
400+
String value = cachedEntries.remove(key);
401+
402+
// If the value not cached, let us look it up.
403+
if (value == null) {
404+
while (pos < bytes) {
405+
int length = readInt(settings, pos);
406+
pos += INTEGER_BYTE_COUNT;
407+
String dataKey = length > 0 ? new String(settings, pos, length) : null;
408+
pos += length;
409+
length = readInt(settings, pos);
410+
pos += INTEGER_BYTE_COUNT;
411+
String dataValue = length > 0 ? new String(settings, pos, length) : null;
412+
pos += length;
413+
if (key.equals(dataKey)) {
414+
value = dataValue;
415+
break;
416+
}
417+
cachedEntries.put(dataKey, dataValue);
411418
}
419+
}
412420

413-
if (mSettingsHelper.restoreValue(settingName, settingValue)) {
414-
cv.clear();
415-
cv.put(Settings.NameValueTable.NAME, settingName);
416-
cv.put(Settings.NameValueTable.VALUE, settingValue);
417-
getContentResolver().insert(contentUri, cv);
418-
}
421+
if (value == null) {
422+
continue;
419423
}
420-
}
421-
}
422424

423-
// Returns 'true' if the given setting is one that we refuse to restore
424-
private boolean invalidSavedSetting(String[] knownNames, String candidate) {
425-
// no filter? allow everything
426-
if (knownNames == null) {
427-
return false;
428-
}
425+
if (settingsHelper.restoreValue(key, value)) {
426+
contentValues.clear();
427+
contentValues.put(Settings.NameValueTable.NAME, key);
428+
contentValues.put(Settings.NameValueTable.VALUE, value);
429+
getContentResolver().insert(contentUri, contentValues);
430+
}
429431

430-
// whitelisted setting? allow it
431-
for (String name : knownNames) {
432-
if (name.equals(candidate)) {
433-
return false;
432+
if (DEBUG) {
433+
Log.d(TAG, "Restored setting: " + key + "=" + value);
434434
}
435435
}
436-
437-
// refuse everything else
438-
if (DEBUG) Log.v(TAG, "Ignoring restore datum: " + candidate);
439-
return true;
440-
}
441-
442-
private String[] copyAndSort(String[] keys) {
443-
String[] sortedKeys = new String[keys.length];
444-
System.arraycopy(keys, 0, sortedKeys, 0, keys.length);
445-
Arrays.sort(sortedKeys);
446-
return sortedKeys;
447436
}
448437

449438
/**
450-
* Given a cursor sorted by key name and a set of keys sorted by name,
451-
* extract the required keys and values and write them to a byte array.
452-
* @param sortedCursor
453-
* @param sortedKeys
454-
* @return
439+
* Given a cursor and a set of keys, extract the required keys and
440+
* values and write them to a byte array.
441+
*
442+
* @param cursor A cursor with settings data.
443+
* @param settings The settings to extract.
444+
* @return The byte array of extracted values.
455445
*/
456-
byte[] extractRelevantValues(Cursor sortedCursor, String[] sortedKeys) {
457-
byte[][] values = new byte[sortedKeys.length * 2][]; // keys and values
458-
if (!sortedCursor.moveToFirst()) {
446+
private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
447+
final int settingsCount = settings.length;
448+
byte[][] values = new byte[settingsCount * 2][]; // keys and values
449+
if (!cursor.moveToFirst()) {
459450
Log.e(TAG, "Couldn't read from the cursor");
460451
return new byte[0];
461452
}
462-
int keyIndex = 0;
453+
454+
// Obtain the relevant data in a temporary array.
463455
int totalSize = 0;
464-
while (!sortedCursor.isAfterLast()) {
465-
String name = sortedCursor.getString(COLUMN_NAME);
466-
while (sortedKeys[keyIndex].compareTo(name.toString()) < 0) {
467-
keyIndex++;
468-
if (keyIndex == sortedKeys.length) break;
469-
}
470-
if (keyIndex < sortedKeys.length && name.equals(sortedKeys[keyIndex])) {
471-
String value = sortedCursor.getString(COLUMN_VALUE);
472-
byte[] nameBytes = name.toString().getBytes();
473-
totalSize += 4 + nameBytes.length;
474-
values[keyIndex * 2] = nameBytes;
475-
byte[] valueBytes;
476-
if (TextUtils.isEmpty(value)) {
477-
valueBytes = null;
478-
totalSize += 4;
479-
} else {
480-
valueBytes = value.toString().getBytes();
481-
totalSize += 4 + valueBytes.length;
482-
//Log.i(TAG, "Backing up " + name + " = " + value);
456+
int backedUpSettingIndex = 0;
457+
Map<String, String> cachedEntries = new HashMap<String, String>();
458+
for (int i = 0; i < settingsCount; i++) {
459+
String key = settings[i];
460+
String value = cachedEntries.remove(key);
461+
462+
// If the value not cached, let us look it up.
463+
if (value == null) {
464+
while (!cursor.isAfterLast()) {
465+
String cursorKey = cursor.getString(COLUMN_NAME);
466+
String cursorValue = cursor.getString(COLUMN_VALUE);
467+
cursor.moveToNext();
468+
if (key.equals(cursorKey)) {
469+
value = cursorValue;
470+
break;
471+
}
472+
cachedEntries.put(cursorKey, cursorValue);
483473
}
484-
values[keyIndex * 2 + 1] = valueBytes;
485-
keyIndex++;
486474
}
487-
if (keyIndex == sortedKeys.length || !sortedCursor.moveToNext()) {
488-
break;
475+
476+
if (value == null) {
477+
continue;
478+
}
479+
480+
// Write the key and value in the intermediary array.
481+
byte[] keyBytes = key.getBytes();
482+
totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
483+
values[backedUpSettingIndex * 2] = keyBytes;
484+
485+
byte[] valueBytes = value.getBytes();
486+
totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
487+
values[backedUpSettingIndex * 2 + 1] = valueBytes;
488+
489+
backedUpSettingIndex++;
490+
491+
if (DEBUG) {
492+
Log.d(TAG, "Backed up setting: " + key + "=" + value);
489493
}
490494
}
491495

496+
// Aggregate the result.
492497
byte[] result = new byte[totalSize];
493498
int pos = 0;
494-
for (int i = 0; i < sortedKeys.length * 2; i++) {
495-
if (values[i] != null) {
496-
pos = writeInt(result, pos, values[i].length);
497-
pos = writeBytes(result, pos, values[i]);
498-
}
499+
final int keyValuePairCount = backedUpSettingIndex * 2;
500+
for (int i = 0; i < keyValuePairCount; i++) {
501+
pos = writeInt(result, pos, values[i].length);
502+
pos = writeBytes(result, pos, values[i]);
499503
}
500504
return result;
501505
}
@@ -647,14 +651,14 @@ private void copyWifiSupplicantTemplate() {
647651
* @param out byte array
648652
* @param pos current pos in array
649653
* @param value integer to write
650-
* @return the index after adding the size of an int (4)
654+
* @return the index after adding the size of an int (4) in bytes.
651655
*/
652656
private int writeInt(byte[] out, int pos, int value) {
653657
out[pos + 0] = (byte) ((value >> 24) & 0xFF);
654658
out[pos + 1] = (byte) ((value >> 16) & 0xFF);
655659
out[pos + 2] = (byte) ((value >> 8) & 0xFF);
656660
out[pos + 3] = (byte) ((value >> 0) & 0xFF);
657-
return pos + 4;
661+
return pos + INTEGER_BYTE_COUNT;
658662
}
659663

660664
private int writeBytes(byte[] out, int pos, byte[] value) {

0 commit comments

Comments
 (0)