am 624181af: Merge "Settings are restored in alphabetical order rather in order of dependency." into ics-factoryrom

* commit '624181af38f7f9e4fe4a18ca3e15204f30609312':
  Settings are restored in alphabetical order rather in order of dependency.
This commit is contained in:
Svetoslav Ganov
2011-09-21 19:08:28 -07:00
committed by Android Git Automerger
2 changed files with 136 additions and 121 deletions

View File

@@ -1882,6 +1882,11 @@ public final class Settings {
/** /**
* Settings to backup. This is here so that it's in the same place as the settings * Settings to backup. This is here so that it's in the same place as the settings
* keys and easy to update. * keys and easy to update.
*
* NOTE: Settings are backed up and restored in the order they appear
* in this array. If you have one setting depending on another,
* make sure that they are ordered appropriately.
*
* @hide * @hide
*/ */
public static final String[] SETTINGS_TO_BACKUP = { public static final String[] SETTINGS_TO_BACKUP = {
@@ -4048,6 +4053,12 @@ public final class Settings {
public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout"; public static final String PACKAGE_VERIFIER_TIMEOUT = "verifier_timeout";
/** /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
* in this array. If you have one setting depending on another,
* make sure that they are ordered appropriately.
*
* @hide * @hide
*/ */
public static final String[] SETTINGS_TO_BACKUP = { public static final String[] SETTINGS_TO_BACKUP = {
@@ -4056,11 +4067,11 @@ public final class Settings {
PARENTAL_CONTROL_ENABLED, PARENTAL_CONTROL_ENABLED,
PARENTAL_CONTROL_REDIRECT_URL, PARENTAL_CONTROL_REDIRECT_URL,
USB_MASS_STORAGE_ENABLED, USB_MASS_STORAGE_ENABLED,
ACCESSIBILITY_ENABLED,
ACCESSIBILITY_SCRIPT_INJECTION, ACCESSIBILITY_SCRIPT_INJECTION,
BACKUP_AUTO_RESTORE, BACKUP_AUTO_RESTORE,
ENABLED_ACCESSIBILITY_SERVICES, ENABLED_ACCESSIBILITY_SERVICES,
TOUCH_EXPLORATION_ENABLED, TOUCH_EXPLORATION_ENABLED,
ACCESSIBILITY_ENABLED,
TTS_USE_DEFAULTS, TTS_USE_DEFAULTS,
TTS_DEFAULT_RATE, TTS_DEFAULT_RATE,
TTS_DEFAULT_PITCH, TTS_DEFAULT_PITCH,

View File

@@ -16,6 +16,21 @@
package com.android.providers.settings; package com.android.providers.settings;
import android.app.backup.BackupAgentHelper;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.FullBackupDataOutput;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.provider.Settings;
import android.util.Log;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.BufferedWriter; import java.io.BufferedWriter;
@@ -27,28 +42,13 @@ import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.FileReader; import java.io.FileReader;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.InputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Arrays; import java.util.HashMap;
import java.util.Map;
import java.util.zip.CRC32; import java.util.zip.CRC32;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
import android.app.backup.BackupAgentHelper;
import android.app.backup.FullBackupDataOutput;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
/** /**
* Performs backup and restore of the System and Secure settings. * Performs backup and restore of the System and Secure settings.
* List of settings that are backed up are stored in the Settings.java file * List of settings that are backed up are stored in the Settings.java file
@@ -79,8 +79,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
// Versioning of the 'full backup' format // Versioning of the 'full backup' format
private static final int FULL_BACKUP_VERSION = 1; private static final int FULL_BACKUP_VERSION = 1;
private static String[] sortedSystemKeys = null; private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
private static String[] sortedSecureKeys = null;
private static final byte[] EMPTY_DATA = new byte[0]; private static final byte[] EMPTY_DATA = new byte[0];
@@ -112,6 +111,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
private WifiManager mWfm; private WifiManager mWfm;
private static String mWifiConfigFile; private static String mWifiConfigFile;
@Override
public void onCreate() { public void onCreate() {
if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
@@ -348,26 +348,17 @@ public class SettingsBackupAgent extends BackupAgentHelper {
} }
private byte[] getSystemSettings() { private byte[] getSystemSettings() {
Cursor sortedCursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
null, null, Settings.NameValueTable.NAME); null, null);
// Copy and sort the array byte[] result = extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
if (sortedSystemKeys == null) { cursor.close();
sortedSystemKeys = copyAndSort(Settings.System.SETTINGS_TO_BACKUP);
}
byte[] result = extractRelevantValues(sortedCursor, sortedSystemKeys);
sortedCursor.close();
return result; return result;
} }
private byte[] getSecureSettings() { private byte[] getSecureSettings() {
Cursor sortedCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
null, null, Settings.NameValueTable.NAME); null, null);
// Copy and sort the array byte[] result = extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
if (sortedSecureKeys == null) {
sortedSecureKeys = copyAndSort(Settings.Secure.SETTINGS_TO_BACKUP);
}
byte[] result = extractRelevantValues(sortedCursor, sortedSecureKeys);
sortedCursor.close();
return result; return result;
} }
@@ -383,119 +374,132 @@ public class SettingsBackupAgent extends BackupAgentHelper {
} }
private void restoreSettings(byte[] settings, int bytes, Uri contentUri) { private void restoreSettings(byte[] settings, int bytes, Uri contentUri) {
if (DEBUG) Log.i(TAG, "restoreSettings: " + contentUri); if (DEBUG) {
Log.i(TAG, "restoreSettings: " + contentUri);
}
// Figure out the white list.
String[] whitelist = null; String[] whitelist = null;
if (contentUri.equals(Settings.Secure.CONTENT_URI)) { if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
whitelist = Settings.Secure.SETTINGS_TO_BACKUP; whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
} else if (contentUri.equals(Settings.System.CONTENT_URI)) { } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
whitelist = Settings.System.SETTINGS_TO_BACKUP; whitelist = Settings.System.SETTINGS_TO_BACKUP;
} else {
throw new IllegalArgumentException("Unknown URI: " + contentUri);
} }
ContentValues cv = new ContentValues(2); // Restore only the white list data.
int pos = 0; int pos = 0;
while (pos < bytes) { Map<String, String> cachedEntries = new HashMap<String, String>();
int length = readInt(settings, pos); ContentValues contentValues = new ContentValues(2);
pos += 4; SettingsHelper settingsHelper = mSettingsHelper;
String settingName = length > 0? new String(settings, pos, length) : null;
pos += length;
length = readInt(settings, pos);
pos += 4;
String settingValue = length > 0? new String(settings, pos, length) : null;
pos += length;
if (!TextUtils.isEmpty(settingName) && !TextUtils.isEmpty(settingValue)) {
//Log.i(TAG, "Restore " + settingName + " = " + settingValue);
// Only restore settings in our list of known-acceptable data final int whiteListSize = whitelist.length;
if (invalidSavedSetting(whitelist, settingName)) { for (int i = 0; i < whiteListSize; i++) {
continue; String key = whitelist[i];
} String value = cachedEntries.remove(key);
if (mSettingsHelper.restoreValue(settingName, settingValue)) { // If the value not cached, let us look it up.
cv.clear(); if (value == null) {
cv.put(Settings.NameValueTable.NAME, settingName); while (pos < bytes) {
cv.put(Settings.NameValueTable.VALUE, settingValue); int length = readInt(settings, pos);
getContentResolver().insert(contentUri, cv); pos += INTEGER_BYTE_COUNT;
String dataKey = length > 0 ? new String(settings, pos, length) : null;
pos += length;
length = readInt(settings, pos);
pos += INTEGER_BYTE_COUNT;
String dataValue = length > 0 ? new String(settings, pos, length) : null;
pos += length;
if (key.equals(dataKey)) {
value = dataValue;
break;
}
cachedEntries.put(dataKey, dataValue);
} }
} }
}
}
// Returns 'true' if the given setting is one that we refuse to restore if (value == null) {
private boolean invalidSavedSetting(String[] knownNames, String candidate) { continue;
// no filter? allow everything }
if (knownNames == null) {
return false;
}
// whitelisted setting? allow it if (settingsHelper.restoreValue(key, value)) {
for (String name : knownNames) { contentValues.clear();
if (name.equals(candidate)) { contentValues.put(Settings.NameValueTable.NAME, key);
return false; contentValues.put(Settings.NameValueTable.VALUE, value);
getContentResolver().insert(contentUri, contentValues);
}
if (DEBUG) {
Log.d(TAG, "Restored setting: " + key + "=" + value);
} }
} }
// refuse everything else
if (DEBUG) Log.v(TAG, "Ignoring restore datum: " + candidate);
return true;
}
private String[] copyAndSort(String[] keys) {
String[] sortedKeys = new String[keys.length];
System.arraycopy(keys, 0, sortedKeys, 0, keys.length);
Arrays.sort(sortedKeys);
return sortedKeys;
} }
/** /**
* Given a cursor sorted by key name and a set of keys sorted by name, * Given a cursor and a set of keys, extract the required keys and
* extract the required keys and values and write them to a byte array. * values and write them to a byte array.
* @param sortedCursor *
* @param sortedKeys * @param cursor A cursor with settings data.
* @return * @param settings The settings to extract.
* @return The byte array of extracted values.
*/ */
byte[] extractRelevantValues(Cursor sortedCursor, String[] sortedKeys) { private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
byte[][] values = new byte[sortedKeys.length * 2][]; // keys and values final int settingsCount = settings.length;
if (!sortedCursor.moveToFirst()) { byte[][] values = new byte[settingsCount * 2][]; // keys and values
if (!cursor.moveToFirst()) {
Log.e(TAG, "Couldn't read from the cursor"); Log.e(TAG, "Couldn't read from the cursor");
return new byte[0]; return new byte[0];
} }
int keyIndex = 0;
// Obtain the relevant data in a temporary array.
int totalSize = 0; int totalSize = 0;
while (!sortedCursor.isAfterLast()) { int backedUpSettingIndex = 0;
String name = sortedCursor.getString(COLUMN_NAME); Map<String, String> cachedEntries = new HashMap<String, String>();
while (sortedKeys[keyIndex].compareTo(name.toString()) < 0) { for (int i = 0; i < settingsCount; i++) {
keyIndex++; String key = settings[i];
if (keyIndex == sortedKeys.length) break; String value = cachedEntries.remove(key);
}
if (keyIndex < sortedKeys.length && name.equals(sortedKeys[keyIndex])) { // If the value not cached, let us look it up.
String value = sortedCursor.getString(COLUMN_VALUE); if (value == null) {
byte[] nameBytes = name.toString().getBytes(); while (!cursor.isAfterLast()) {
totalSize += 4 + nameBytes.length; String cursorKey = cursor.getString(COLUMN_NAME);
values[keyIndex * 2] = nameBytes; String cursorValue = cursor.getString(COLUMN_VALUE);
byte[] valueBytes; cursor.moveToNext();
if (TextUtils.isEmpty(value)) { if (key.equals(cursorKey)) {
valueBytes = null; value = cursorValue;
totalSize += 4; break;
} else { }
valueBytes = value.toString().getBytes(); cachedEntries.put(cursorKey, cursorValue);
totalSize += 4 + valueBytes.length;
//Log.i(TAG, "Backing up " + name + " = " + value);
} }
values[keyIndex * 2 + 1] = valueBytes;
keyIndex++;
} }
if (keyIndex == sortedKeys.length || !sortedCursor.moveToNext()) {
break; if (value == null) {
continue;
}
// Write the key and value in the intermediary array.
byte[] keyBytes = key.getBytes();
totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
values[backedUpSettingIndex * 2] = keyBytes;
byte[] valueBytes = value.getBytes();
totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
values[backedUpSettingIndex * 2 + 1] = valueBytes;
backedUpSettingIndex++;
if (DEBUG) {
Log.d(TAG, "Backed up setting: " + key + "=" + value);
} }
} }
// Aggregate the result.
byte[] result = new byte[totalSize]; byte[] result = new byte[totalSize];
int pos = 0; int pos = 0;
for (int i = 0; i < sortedKeys.length * 2; i++) { final int keyValuePairCount = backedUpSettingIndex * 2;
if (values[i] != null) { for (int i = 0; i < keyValuePairCount; i++) {
pos = writeInt(result, pos, values[i].length); pos = writeInt(result, pos, values[i].length);
pos = writeBytes(result, pos, values[i]); pos = writeBytes(result, pos, values[i]);
}
} }
return result; return result;
} }
@@ -647,14 +651,14 @@ public class SettingsBackupAgent extends BackupAgentHelper {
* @param out byte array * @param out byte array
* @param pos current pos in array * @param pos current pos in array
* @param value integer to write * @param value integer to write
* @return the index after adding the size of an int (4) * @return the index after adding the size of an int (4) in bytes.
*/ */
private int writeInt(byte[] out, int pos, int value) { private int writeInt(byte[] out, int pos, int value) {
out[pos + 0] = (byte) ((value >> 24) & 0xFF); out[pos + 0] = (byte) ((value >> 24) & 0xFF);
out[pos + 1] = (byte) ((value >> 16) & 0xFF); out[pos + 1] = (byte) ((value >> 16) & 0xFF);
out[pos + 2] = (byte) ((value >> 8) & 0xFF); out[pos + 2] = (byte) ((value >> 8) & 0xFF);
out[pos + 3] = (byte) ((value >> 0) & 0xFF); out[pos + 3] = (byte) ((value >> 0) & 0xFF);
return pos + 4; return pos + INTEGER_BYTE_COUNT;
} }
private int writeBytes(byte[] out, int pos, byte[] value) { private int writeBytes(byte[] out, int pos, byte[] value) {