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:
@@ -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,
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
Reference in New Issue
Block a user