2 * Copyright (C) 2008 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.providers.settings;
19 import android.annotation.UserIdInt;
20 import android.app.backup.BackupAgentHelper;
21 import android.app.backup.BackupDataInput;
22 import android.app.backup.BackupDataOutput;
23 import android.app.backup.FullBackupDataOutput;
24 import android.content.ContentResolver;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.database.Cursor;
28 import android.net.NetworkPolicy;
29 import android.net.NetworkPolicyManager;
30 import android.net.Uri;
31 import android.net.wifi.WifiConfiguration;
32 import android.net.wifi.WifiManager;
33 import android.os.Handler;
34 import android.os.ParcelFileDescriptor;
35 import android.os.UserHandle;
36 import android.provider.Settings;
37 import android.util.BackupUtils;
38 import android.util.Log;
40 import com.android.internal.widget.LockPatternUtils;
42 import java.io.BufferedOutputStream;
43 import java.io.ByteArrayInputStream;
44 import java.io.ByteArrayOutputStream;
45 import java.io.DataInputStream;
46 import java.io.DataOutputStream;
47 import java.io.EOFException;
49 import java.io.FileInputStream;
50 import java.io.FileOutputStream;
51 import java.io.IOException;
52 import java.util.HashMap;
53 import java.util.HashSet;
55 import java.util.zip.CRC32;
58 * Performs backup and restore of the System and Secure settings.
59 * List of settings that are backed up are stored in the Settings.java file
61 public class SettingsBackupAgent extends BackupAgentHelper {
62 private static final boolean DEBUG = false;
63 private static final boolean DEBUG_BACKUP = DEBUG || false;
65 private static final String KEY_SYSTEM = "system";
66 private static final String KEY_SECURE = "secure";
67 private static final String KEY_GLOBAL = "global";
68 private static final String KEY_LOCALE = "locale";
69 private static final String KEY_LOCK_SETTINGS = "lock_settings";
70 private static final String KEY_SOFTAP_CONFIG = "softap_config";
71 private static final String KEY_NETWORK_POLICIES = "network_policies";
72 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
74 // Versioning of the state file. Increment this version
75 // number any time the set of state items is altered.
76 private static final int STATE_VERSION = 7;
78 // Versioning of the Network Policies backup payload.
79 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
82 // Slots in the checksum array. Never insert new items in the middle
83 // of this array; new slots must be appended.
84 private static final int STATE_SYSTEM = 0;
85 private static final int STATE_SECURE = 1;
86 private static final int STATE_LOCALE = 2;
87 private static final int STATE_WIFI_SUPPLICANT = 3;
88 private static final int STATE_WIFI_CONFIG = 4;
89 private static final int STATE_GLOBAL = 5;
90 private static final int STATE_LOCK_SETTINGS = 6;
91 private static final int STATE_SOFTAP_CONFIG = 7;
92 private static final int STATE_NETWORK_POLICIES = 8;
93 private static final int STATE_WIFI_NEW_CONFIG = 9;
95 private static final int STATE_SIZE = 10; // The current number of state items
97 // Number of entries in the checksum array at various version numbers
98 private static final int STATE_SIZES[] = {
101 5, // version 2 added STATE_WIFI_CONFIG
102 6, // version 3 added STATE_GLOBAL
103 7, // version 4 added STATE_LOCK_SETTINGS
104 8, // version 5 added STATE_SOFTAP_CONFIG
105 9, // version 6 added STATE_NETWORK_POLICIES
106 STATE_SIZE // version 7 added STATE_WIFI_NEW_CONFIG
109 // Versioning of the 'full backup' format
110 // Increment this version any time a new item is added
111 private static final int FULL_BACKUP_VERSION = 6;
112 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
113 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
114 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
115 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
116 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry
118 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
120 private static final byte[] EMPTY_DATA = new byte[0];
122 private static final String TAG = "SettingsBackupAgent";
124 private static final String[] PROJECTION = {
125 Settings.NameValueTable.NAME,
126 Settings.NameValueTable.VALUE
129 // the key to store the WIFI data under, should be sorted as last, so restore happens last.
130 // use very late unicode character to quasi-guarantee last sort position.
131 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
132 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
134 // Keys within the lock settings section
135 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
136 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
137 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED =
138 "visible_pattern_enabled";
139 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS =
140 "power_button_instantly_locks";
142 // Name of the temporary file we use during full backup/restore. This is
143 // stored in the full-backup tarfile as well, so should not be changed.
144 private static final String STAGE_FILE = "flattened-data";
146 private SettingsHelper mSettingsHelper;
148 private WifiManager mWifiManager;
151 public void onCreate() {
152 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
154 mSettingsHelper = new SettingsHelper(this);
155 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
160 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
161 ParcelFileDescriptor newState) throws IOException {
163 byte[] systemSettingsData = getSystemSettings();
164 byte[] secureSettingsData = getSecureSettings();
165 byte[] globalSettingsData = getGlobalSettings();
166 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId());
167 byte[] locale = mSettingsHelper.getLocaleData();
168 byte[] softApConfigData = getSoftAPConfiguration();
169 byte[] netPoliciesData = getNetworkPolicies();
170 byte[] wifiFullConfigData = getNewWifiConfigData();
172 long[] stateChecksums = readOldChecksums(oldState);
174 stateChecksums[STATE_SYSTEM] =
175 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
176 stateChecksums[STATE_SECURE] =
177 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
178 stateChecksums[STATE_GLOBAL] =
179 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
180 stateChecksums[STATE_LOCALE] =
181 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
182 stateChecksums[STATE_WIFI_SUPPLICANT] = 0;
183 stateChecksums[STATE_WIFI_CONFIG] = 0;
184 stateChecksums[STATE_LOCK_SETTINGS] =
185 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
186 lockSettingsData, data);
187 stateChecksums[STATE_SOFTAP_CONFIG] =
188 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
189 softApConfigData, data);
190 stateChecksums[STATE_NETWORK_POLICIES] =
191 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
192 netPoliciesData, data);
193 stateChecksums[STATE_WIFI_NEW_CONFIG] =
194 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG,
195 wifiFullConfigData, data);
197 writeNewChecksums(stateChecksums, newState);
201 public void onRestore(BackupDataInput data, int appVersionCode,
202 ParcelFileDescriptor newState) throws IOException {
204 HashSet<String> movedToGlobal = new HashSet<String>();
205 Settings.System.getMovedToGlobalSettings(movedToGlobal);
206 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
207 byte[] restoredWifiSupplicantData = null;
208 byte[] restoredWifiIpConfigData = null;
210 while (data.readNextHeader()) {
211 final String key = data.getKey();
212 final int size = data.getDataSize();
215 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
216 mSettingsHelper.applyAudioSettings();
220 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
224 restoreSettings(data, Settings.Global.CONTENT_URI, null);
227 case KEY_WIFI_SUPPLICANT :
228 restoredWifiSupplicantData = new byte[size];
229 data.readEntityData(restoredWifiSupplicantData, 0, size);
233 byte[] localeData = new byte[size];
234 data.readEntityData(localeData, 0, size);
235 mSettingsHelper.setLocaleData(localeData, size);
238 case KEY_WIFI_CONFIG :
239 restoredWifiIpConfigData = new byte[size];
240 data.readEntityData(restoredWifiIpConfigData, 0, size);
243 case KEY_LOCK_SETTINGS :
244 restoreLockSettings(UserHandle.myUserId(), data);
247 case KEY_SOFTAP_CONFIG :
248 byte[] softapData = new byte[size];
249 data.readEntityData(softapData, 0, size);
250 restoreSoftApConfiguration(softapData);
253 case KEY_NETWORK_POLICIES:
254 byte[] netPoliciesData = new byte[size];
255 data.readEntityData(netPoliciesData, 0, size);
256 restoreNetworkPolicies(netPoliciesData);
259 case KEY_WIFI_NEW_CONFIG:
260 byte[] restoredWifiNewConfigData = new byte[size];
261 data.readEntityData(restoredWifiNewConfigData, 0, size);
262 restoreNewWifiConfigData(restoredWifiNewConfigData);
266 data.skipEntityData();
271 // Do this at the end so that we also pull in the ipconfig data.
272 if (restoredWifiSupplicantData != null) {
273 restoreSupplicantWifiConfigData(
274 restoredWifiSupplicantData, restoredWifiIpConfigData);
279 public void onFullBackup(FullBackupDataOutput data) throws IOException {
280 byte[] systemSettingsData = getSystemSettings();
281 byte[] secureSettingsData = getSecureSettings();
282 byte[] globalSettingsData = getGlobalSettings();
283 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId());
284 byte[] locale = mSettingsHelper.getLocaleData();
285 byte[] softApConfigData = getSoftAPConfiguration();
286 byte[] netPoliciesData = getNetworkPolicies();
287 byte[] wifiFullConfigData = getNewWifiConfigData();
289 // Write the data to the staging file, then emit that as our tarfile
290 // representation of the backed-up settings.
291 String root = getFilesDir().getAbsolutePath();
292 File stage = new File(root, STAGE_FILE);
294 FileOutputStream filestream = new FileOutputStream(stage);
295 BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
296 DataOutputStream out = new DataOutputStream(bufstream);
298 if (DEBUG_BACKUP) Log.d(TAG, "Writing flattened data version " + FULL_BACKUP_VERSION);
299 out.writeInt(FULL_BACKUP_VERSION);
301 if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
302 out.writeInt(systemSettingsData.length);
303 out.write(systemSettingsData);
305 Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
307 out.writeInt(secureSettingsData.length);
308 out.write(secureSettingsData);
310 Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
312 out.writeInt(globalSettingsData.length);
313 out.write(globalSettingsData);
314 if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
315 out.writeInt(locale.length);
317 if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
318 out.writeInt(lockSettingsData.length);
319 out.write(lockSettingsData);
320 if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
321 out.writeInt(softApConfigData.length);
322 out.write(softApConfigData);
323 if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of net policies data");
324 out.writeInt(netPoliciesData.length);
325 out.write(netPoliciesData);
327 Log.d(TAG, wifiFullConfigData.length + " bytes of wifi config data");
329 out.writeInt(wifiFullConfigData.length);
330 out.write(wifiFullConfigData);
332 out.flush(); // also flushes downstream
334 // now we're set to emit the tar stream
335 fullBackupFile(stage, data);
342 public void onRestoreFile(ParcelFileDescriptor data, long size,
343 int type, String domain, String relpath, long mode, long mtime)
345 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
346 // Our data is actually a blob of flattened settings data identical to that
347 // produced during incremental backups. Just unpack and apply it all in
349 FileInputStream instream = new FileInputStream(data.getFileDescriptor());
350 DataInputStream in = new DataInputStream(instream);
352 int version = in.readInt();
353 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
354 if (version <= FULL_BACKUP_VERSION) {
355 // Generate the moved-to-global lookup table
356 HashSet<String> movedToGlobal = new HashSet<String>();
357 Settings.System.getMovedToGlobalSettings(movedToGlobal);
358 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
360 // system settings data first
361 int nBytes = in.readInt();
362 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
363 byte[] buffer = new byte[nBytes];
364 in.readFully(buffer, 0, nBytes);
365 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
368 nBytes = in.readInt();
369 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
370 if (nBytes > buffer.length) buffer = new byte[nBytes];
371 in.readFully(buffer, 0, nBytes);
372 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
374 // Global only if sufficiently new
375 if (version >= FULL_BACKUP_ADDED_GLOBAL) {
376 nBytes = in.readInt();
377 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
378 if (nBytes > buffer.length) buffer = new byte[nBytes];
379 in.readFully(buffer, 0, nBytes);
380 movedToGlobal.clear(); // no redirection; this *is* the global namespace
381 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
385 nBytes = in.readInt();
386 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
387 if (nBytes > buffer.length) buffer = new byte[nBytes];
388 in.readFully(buffer, 0, nBytes);
389 mSettingsHelper.setLocaleData(buffer, nBytes);
391 // Restore older backups performing the necessary migrations.
392 if (version < FULL_BACKUP_ADDED_WIFI_NEW) {
394 int supplicant_size = in.readInt();
395 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data");
396 byte[] supplicant_buffer = new byte[supplicant_size];
397 in.readFully(supplicant_buffer, 0, supplicant_size);
400 int ipconfig_size = in.readInt();
401 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data");
402 byte[] ipconfig_buffer = new byte[ipconfig_size];
403 in.readFully(ipconfig_buffer, 0, nBytes);
404 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer);
407 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
408 nBytes = in.readInt();
409 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
410 if (nBytes > buffer.length) buffer = new byte[nBytes];
412 in.readFully(buffer, 0, nBytes);
413 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes);
417 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
418 nBytes = in.readInt();
419 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
420 if (nBytes > buffer.length) buffer = new byte[nBytes];
422 in.readFully(buffer, 0, nBytes);
423 restoreSoftApConfiguration(buffer);
427 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
428 nBytes = in.readInt();
429 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
430 if (nBytes > buffer.length) buffer = new byte[nBytes];
432 in.readFully(buffer, 0, nBytes);
433 restoreNetworkPolicies(buffer);
436 // Restore full wifi config data
437 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) {
438 nBytes = in.readInt();
439 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data");
440 if (nBytes > buffer.length) buffer = new byte[nBytes];
441 in.readFully(buffer, 0, nBytes);
442 restoreNewWifiConfigData(buffer);
445 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
448 throw new IOException("Invalid file schema");
452 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
453 long[] stateChecksums = new long[STATE_SIZE];
455 DataInputStream dataInput = new DataInputStream(
456 new FileInputStream(oldState.getFileDescriptor()));
459 int stateVersion = dataInput.readInt();
460 if (stateVersion > STATE_VERSION) {
461 // Constrain the maximum state version this backup agent
462 // can handle in case a newer or corrupt backup set existed
463 stateVersion = STATE_VERSION;
465 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
466 stateChecksums[i] = dataInput.readLong();
468 } catch (EOFException eof) {
469 // With the default 0 checksum we'll wind up forcing a backup of
470 // any unhandled data sets, which is appropriate.
473 return stateChecksums;
476 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
478 DataOutputStream dataOutput = new DataOutputStream(
479 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
481 dataOutput.writeInt(STATE_VERSION);
482 for (int i = 0; i < STATE_SIZE; i++) {
483 dataOutput.writeLong(checksums[i]);
488 private long writeIfChanged(long oldChecksum, String key, byte[] data,
489 BackupDataOutput output) {
490 CRC32 checkSummer = new CRC32();
491 checkSummer.update(data);
492 long newChecksum = checkSummer.getValue();
493 if (oldChecksum == newChecksum) {
498 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
500 output.writeEntityHeader(key, data.length);
501 output.writeEntityData(data, data.length);
502 } catch (IOException ioe) {
508 private byte[] getSystemSettings() {
509 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
512 return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
518 private byte[] getSecureSettings() {
519 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
522 return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
528 private byte[] getGlobalSettings() {
529 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
532 return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
539 * Serialize the owner info and other lock settings
541 private byte[] getLockSettings(@UserIdInt int userId) {
542 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
543 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId);
544 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId);
545 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId);
546 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId);
547 final boolean powerButtonInstantlyLocks =
548 lockPatternUtils.getPowerButtonInstantlyLocks(userId);
550 ByteArrayOutputStream baos = new ByteArrayOutputStream();
551 DataOutputStream out = new DataOutputStream(baos);
553 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
554 out.writeUTF(ownerInfoEnabled ? "1" : "0");
555 if (ownerInfo != null) {
556 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
557 out.writeUTF(ownerInfo != null ? ownerInfo : "");
559 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) {
560 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED);
561 out.writeUTF(visiblePatternEnabled ? "1" : "0");
563 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) {
564 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS);
565 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0");
570 } catch (IOException ioe) {
572 return baos.toByteArray();
575 private void restoreSettings(BackupDataInput data, Uri contentUri,
576 HashSet<String> movedToGlobal) {
577 byte[] settings = new byte[data.getDataSize()];
579 data.readEntityData(settings, 0, settings.length);
580 } catch (IOException ioe) {
581 Log.e(TAG, "Couldn't read entity data");
584 restoreSettings(settings, settings.length, contentUri, movedToGlobal);
587 private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
588 HashSet<String> movedToGlobal) {
590 Log.i(TAG, "restoreSettings: " + contentUri);
593 // Figure out the white list and redirects to the global table.
594 final String[] whitelist;
595 if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
596 whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
597 } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
598 whitelist = Settings.System.SETTINGS_TO_BACKUP;
599 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
600 whitelist = Settings.Global.SETTINGS_TO_BACKUP;
602 throw new IllegalArgumentException("Unknown URI: " + contentUri);
605 // Restore only the white list data.
607 Map<String, String> cachedEntries = new HashMap<String, String>();
608 ContentValues contentValues = new ContentValues(2);
609 SettingsHelper settingsHelper = mSettingsHelper;
610 ContentResolver cr = getContentResolver();
612 final int whiteListSize = whitelist.length;
613 for (int i = 0; i < whiteListSize; i++) {
614 String key = whitelist[i];
615 String value = cachedEntries.remove(key);
617 // If the value not cached, let us look it up.
619 while (pos < bytes) {
620 int length = readInt(settings, pos);
621 pos += INTEGER_BYTE_COUNT;
622 String dataKey = length > 0 ? new String(settings, pos, length) : null;
624 length = readInt(settings, pos);
625 pos += INTEGER_BYTE_COUNT;
626 String dataValue = length > 0 ? new String(settings, pos, length) : null;
628 if (key.equals(dataKey)) {
632 cachedEntries.put(dataKey, dataValue);
640 final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
641 ? Settings.Global.CONTENT_URI
643 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
646 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
652 * Restores the owner info enabled and other settings in LockSettings.
657 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) {
658 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
660 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
661 DataInputStream in = new DataInputStream(bais);
664 // Read until empty string marker
665 while ((key = in.readUTF()).length() > 0) {
666 final String value = in.readUTF();
668 Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
671 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
672 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId);
674 case KEY_LOCK_SETTINGS_OWNER_INFO:
675 lockPatternUtils.setOwnerInfo(value, userId);
677 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED:
678 lockPatternUtils.reportPatternWasChosen(userId);
679 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId);
681 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
682 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId);
687 } catch (IOException ioe) {
691 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) {
692 final byte[] settings = new byte[data.getDataSize()];
694 data.readEntityData(settings, 0, settings.length);
695 } catch (IOException ioe) {
696 Log.e(TAG, "Couldn't read entity data");
699 restoreLockSettings(userId, settings, settings.length);
703 * Given a cursor and a set of keys, extract the required keys and
704 * values and write them to a byte array.
706 * @param cursor A cursor with settings data.
707 * @param settings The settings to extract.
708 * @return The byte array of extracted values.
710 private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
711 final int settingsCount = settings.length;
712 byte[][] values = new byte[settingsCount * 2][]; // keys and values
713 if (!cursor.moveToFirst()) {
714 Log.e(TAG, "Couldn't read from the cursor");
718 // Obtain the relevant data in a temporary array.
720 int backedUpSettingIndex = 0;
721 Map<String, String> cachedEntries = new HashMap<String, String>();
722 for (int i = 0; i < settingsCount; i++) {
723 String key = settings[i];
724 String value = cachedEntries.remove(key);
726 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
727 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
729 // If the value not cached, let us look it up.
731 while (!cursor.isAfterLast()) {
732 String cursorKey = cursor.getString(nameColumnIndex);
733 String cursorValue = cursor.getString(valueColumnIndex);
735 if (key.equals(cursorKey)) {
739 cachedEntries.put(cursorKey, cursorValue);
743 // Intercept the keys and see if they need special handling
744 value = mSettingsHelper.onBackupValue(key, value);
749 // Write the key and value in the intermediary array.
750 byte[] keyBytes = key.getBytes();
751 totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
752 values[backedUpSettingIndex * 2] = keyBytes;
754 byte[] valueBytes = value.getBytes();
755 totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
756 values[backedUpSettingIndex * 2 + 1] = valueBytes;
758 backedUpSettingIndex++;
761 Log.d(TAG, "Backed up setting: " + key + "=" + value);
765 // Aggregate the result.
766 byte[] result = new byte[totalSize];
768 final int keyValuePairCount = backedUpSettingIndex * 2;
769 for (int i = 0; i < keyValuePairCount; i++) {
770 pos = writeInt(result, pos, values[i].length);
771 pos = writeBytes(result, pos, values[i]);
776 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) {
778 Log.v(TAG, "Applying restored supplicant wifi data");
780 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes);
783 private byte[] getSoftAPConfiguration() {
785 return mWifiManager.getWifiApConfiguration().getBytesForBackup();
786 } catch (IOException ioe) {
787 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
792 private void restoreSoftApConfiguration(byte[] data) {
794 WifiConfiguration config = WifiConfiguration
795 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
796 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
797 mWifiManager.setWifiApConfiguration(config);
798 } catch (IOException | BackupUtils.BadVersionException e) {
799 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
803 private byte[] getNetworkPolicies() {
804 NetworkPolicyManager networkPolicyManager =
805 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
806 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
807 ByteArrayOutputStream baos = new ByteArrayOutputStream();
808 if (policies != null && policies.length != 0) {
809 DataOutputStream out = new DataOutputStream(baos);
811 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
812 out.writeInt(policies.length);
813 for (NetworkPolicy policy : policies) {
814 if (policy != null) {
815 byte[] marshaledPolicy = policy.getBytesForBackup();
816 out.writeByte(BackupUtils.NOT_NULL);
817 out.writeInt(marshaledPolicy.length);
818 out.write(marshaledPolicy);
820 out.writeByte(BackupUtils.NULL);
823 } catch (IOException ioe) {
824 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
828 return baos.toByteArray();
831 private byte[] getNewWifiConfigData() {
832 return mWifiManager.retrieveBackupData();
835 private void restoreNewWifiConfigData(byte[] bytes) {
837 Log.v(TAG, "Applying restored wifi data");
839 mWifiManager.restoreBackupData(bytes);
842 private void restoreNetworkPolicies(byte[] data) {
843 NetworkPolicyManager networkPolicyManager =
844 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
845 if (data != null && data.length != 0) {
846 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
848 int version = in.readInt();
849 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
850 throw new BackupUtils.BadVersionException(
851 "Unknown Backup Serialization Version");
853 int length = in.readInt();
854 NetworkPolicy[] policies = new NetworkPolicy[length];
855 for (int i = 0; i < length; i++) {
856 byte isNull = in.readByte();
857 if (isNull == BackupUtils.NULL) continue;
858 int byteLength = in.readInt();
859 byte[] policyData = new byte[byteLength];
860 in.read(policyData, 0, byteLength);
861 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
862 new DataInputStream(new ByteArrayInputStream(policyData)));
864 // Only set the policies if there was no error in the restore operation
865 networkPolicyManager.setNetworkPolicies(policies);
866 } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
867 // NPE can be thrown when trying to instantiate a NetworkPolicy
868 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
874 * Write an int in BigEndian into the byte array.
875 * @param out byte array
876 * @param pos current pos in array
877 * @param value integer to write
878 * @return the index after adding the size of an int (4) in bytes.
880 private int writeInt(byte[] out, int pos, int value) {
881 out[pos + 0] = (byte) ((value >> 24) & 0xFF);
882 out[pos + 1] = (byte) ((value >> 16) & 0xFF);
883 out[pos + 2] = (byte) ((value >> 8) & 0xFF);
884 out[pos + 3] = (byte) ((value >> 0) & 0xFF);
885 return pos + INTEGER_BYTE_COUNT;
888 private int writeBytes(byte[] out, int pos, byte[] value) {
889 System.arraycopy(value, 0, out, pos, value.length);
890 return pos + value.length;
893 private int readInt(byte[] in, int pos) {
894 int result = ((in[pos] & 0xFF) << 24)
895 | ((in[pos + 1] & 0xFF) << 16)
896 | ((in[pos + 2] & 0xFF) << 8)
897 | ((in[pos + 3] & 0xFF) << 0);