diff options
Diffstat (limited to 'packages/SettingsProvider')
-rw-r--r-- | packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java | 246 |
1 files changed, 125 insertions, 121 deletions
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java index 4f39e69..b851ab7 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java @@ -16,6 +16,21 @@ 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.BufferedReader; import java.io.BufferedWriter; @@ -27,28 +42,13 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; -import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; 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. * 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 private static final int FULL_BACKUP_VERSION = 1; - private static String[] sortedSystemKeys = null; - private static String[] sortedSecureKeys = null; + private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE; private static final byte[] EMPTY_DATA = new byte[0]; @@ -112,6 +111,7 @@ public class SettingsBackupAgent extends BackupAgentHelper { private WifiManager mWfm; private static String mWifiConfigFile; + @Override public void onCreate() { if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); @@ -348,26 +348,17 @@ public class SettingsBackupAgent extends BackupAgentHelper { } private byte[] getSystemSettings() { - Cursor sortedCursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, - null, null, Settings.NameValueTable.NAME); - // Copy and sort the array - if (sortedSystemKeys == null) { - sortedSystemKeys = copyAndSort(Settings.System.SETTINGS_TO_BACKUP); - } - byte[] result = extractRelevantValues(sortedCursor, sortedSystemKeys); - sortedCursor.close(); + Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null, + null, null); + byte[] result = extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP); + cursor.close(); return result; } private byte[] getSecureSettings() { - Cursor sortedCursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, - null, null, Settings.NameValueTable.NAME); - // Copy and sort the array - if (sortedSecureKeys == null) { - sortedSecureKeys = copyAndSort(Settings.Secure.SETTINGS_TO_BACKUP); - } - byte[] result = extractRelevantValues(sortedCursor, sortedSecureKeys); - sortedCursor.close(); + Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null, + null, null); + byte[] result = extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP); return result; } @@ -383,119 +374,132 @@ public class SettingsBackupAgent extends BackupAgentHelper { } 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; if (contentUri.equals(Settings.Secure.CONTENT_URI)) { whitelist = Settings.Secure.SETTINGS_TO_BACKUP; } else if (contentUri.equals(Settings.System.CONTENT_URI)) { 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; - while (pos < bytes) { - int length = readInt(settings, pos); - pos += 4; - 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 - if (invalidSavedSetting(whitelist, settingName)) { - continue; + Map<String, String> cachedEntries = new HashMap<String, String>(); + ContentValues contentValues = new ContentValues(2); + SettingsHelper settingsHelper = mSettingsHelper; + + final int whiteListSize = whitelist.length; + for (int i = 0; i < whiteListSize; i++) { + String key = whitelist[i]; + String value = cachedEntries.remove(key); + + // If the value not cached, let us look it up. + if (value == null) { + while (pos < bytes) { + int length = readInt(settings, pos); + 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); } + } - if (mSettingsHelper.restoreValue(settingName, settingValue)) { - cv.clear(); - cv.put(Settings.NameValueTable.NAME, settingName); - cv.put(Settings.NameValueTable.VALUE, settingValue); - getContentResolver().insert(contentUri, cv); - } + if (value == null) { + continue; } - } - } - // Returns 'true' if the given setting is one that we refuse to restore - private boolean invalidSavedSetting(String[] knownNames, String candidate) { - // no filter? allow everything - if (knownNames == null) { - return false; - } + if (settingsHelper.restoreValue(key, value)) { + contentValues.clear(); + contentValues.put(Settings.NameValueTable.NAME, key); + contentValues.put(Settings.NameValueTable.VALUE, value); + getContentResolver().insert(contentUri, contentValues); + } - // whitelisted setting? allow it - for (String name : knownNames) { - if (name.equals(candidate)) { - return false; + 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, - * extract the required keys and values and write them to a byte array. - * @param sortedCursor - * @param sortedKeys - * @return + * Given a cursor and a set of keys, extract the required keys and + * values and write them to a byte array. + * + * @param cursor A cursor with settings data. + * @param settings The settings to extract. + * @return The byte array of extracted values. */ - byte[] extractRelevantValues(Cursor sortedCursor, String[] sortedKeys) { - byte[][] values = new byte[sortedKeys.length * 2][]; // keys and values - if (!sortedCursor.moveToFirst()) { + private byte[] extractRelevantValues(Cursor cursor, String[] settings) { + final int settingsCount = settings.length; + byte[][] values = new byte[settingsCount * 2][]; // keys and values + if (!cursor.moveToFirst()) { Log.e(TAG, "Couldn't read from the cursor"); return new byte[0]; } - int keyIndex = 0; + + // Obtain the relevant data in a temporary array. int totalSize = 0; - while (!sortedCursor.isAfterLast()) { - String name = sortedCursor.getString(COLUMN_NAME); - while (sortedKeys[keyIndex].compareTo(name.toString()) < 0) { - keyIndex++; - if (keyIndex == sortedKeys.length) break; - } - if (keyIndex < sortedKeys.length && name.equals(sortedKeys[keyIndex])) { - String value = sortedCursor.getString(COLUMN_VALUE); - byte[] nameBytes = name.toString().getBytes(); - totalSize += 4 + nameBytes.length; - values[keyIndex * 2] = nameBytes; - byte[] valueBytes; - if (TextUtils.isEmpty(value)) { - valueBytes = null; - totalSize += 4; - } else { - valueBytes = value.toString().getBytes(); - totalSize += 4 + valueBytes.length; - //Log.i(TAG, "Backing up " + name + " = " + value); + int backedUpSettingIndex = 0; + Map<String, String> cachedEntries = new HashMap<String, String>(); + for (int i = 0; i < settingsCount; i++) { + String key = settings[i]; + String value = cachedEntries.remove(key); + + // If the value not cached, let us look it up. + if (value == null) { + while (!cursor.isAfterLast()) { + String cursorKey = cursor.getString(COLUMN_NAME); + String cursorValue = cursor.getString(COLUMN_VALUE); + cursor.moveToNext(); + if (key.equals(cursorKey)) { + value = cursorValue; + break; + } + cachedEntries.put(cursorKey, cursorValue); } - 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]; int pos = 0; - for (int i = 0; i < sortedKeys.length * 2; i++) { - if (values[i] != null) { - pos = writeInt(result, pos, values[i].length); - pos = writeBytes(result, pos, values[i]); - } + final int keyValuePairCount = backedUpSettingIndex * 2; + for (int i = 0; i < keyValuePairCount; i++) { + pos = writeInt(result, pos, values[i].length); + pos = writeBytes(result, pos, values[i]); } return result; } @@ -647,14 +651,14 @@ public class SettingsBackupAgent extends BackupAgentHelper { * @param out byte array * @param pos current pos in array * @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) { out[pos + 0] = (byte) ((value >> 24) & 0xFF); out[pos + 1] = (byte) ((value >> 16) & 0xFF); out[pos + 2] = (byte) ((value >> 8) & 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) { |