blob: ae882275de7c379179826b1406ca0becfef26d33 [file] [log] [blame]
Amith Yamasani220f4d62009-07-02 02:34:14 -07001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.providers.settings;
18
Christopher Tate1d0fca32017-06-06 13:30:00 -070019import android.annotation.Nullable;
Bryan Mawhinneye483b562017-05-15 14:46:05 +010020import android.annotation.UserIdInt;
Svetoslav Ganova571a582011-09-20 18:32:20 -070021import android.app.backup.BackupAgentHelper;
22import android.app.backup.BackupDataInput;
23import android.app.backup.BackupDataOutput;
24import android.app.backup.FullBackupDataOutput;
Christopher Tate87bc7e72013-06-10 16:55:02 -070025import android.content.ContentResolver;
Svetoslav Ganova571a582011-09-20 18:32:20 -070026import android.content.ContentValues;
27import android.content.Context;
28import android.database.Cursor;
Ritesh Reddyadca34a2016-02-04 18:33:30 +000029import android.net.NetworkPolicy;
30import android.net.NetworkPolicyManager;
Svetoslav Ganova571a582011-09-20 18:32:20 -070031import android.net.Uri;
Christopher Tatecab915a2015-01-08 12:50:00 -080032import android.net.wifi.WifiConfiguration;
Svetoslav Ganova571a582011-09-20 18:32:20 -070033import android.net.wifi.WifiManager;
Svetoslav Ganova571a582011-09-20 18:32:20 -070034import android.os.ParcelFileDescriptor;
Amith Yamasani072543f2015-02-13 11:09:45 -080035import android.os.UserHandle;
Svetoslav Ganova571a582011-09-20 18:32:20 -070036import android.provider.Settings;
Svet Ganovaabc9632017-07-28 19:37:15 -070037import android.util.ArrayMap;
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000038import android.util.BackupUtils;
Svetoslav Ganova571a582011-09-20 18:32:20 -070039import android.util.Log;
40
Amith Yamasani072543f2015-02-13 11:09:45 -080041import com.android.internal.widget.LockPatternUtils;
42
Brad Fitzpatrick70787892010-11-17 11:31:12 -080043import java.io.BufferedOutputStream;
Amith Yamasani072543f2015-02-13 11:09:45 -080044import java.io.ByteArrayInputStream;
Christopher Tatecab915a2015-01-08 12:50:00 -080045import java.io.ByteArrayOutputStream;
Amith Yamasanid1582142009-07-08 20:04:55 -070046import java.io.DataInputStream;
47import java.io.DataOutputStream;
Amith Yamasani2cfab842009-09-09 18:27:31 -070048import java.io.EOFException;
Amith Yamasani220f4d62009-07-02 02:34:14 -070049import java.io.File;
50import java.io.FileInputStream;
51import java.io.FileOutputStream;
52import java.io.IOException;
Svetoslav Ganova571a582011-09-20 18:32:20 -070053import java.util.HashMap;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070054import java.util.HashSet;
Svetoslav Ganova571a582011-09-20 18:32:20 -070055import java.util.Map;
Amith Yamasanid1582142009-07-08 20:04:55 -070056import java.util.zip.CRC32;
Amith Yamasani220f4d62009-07-02 02:34:14 -070057
Amith Yamasani220f4d62009-07-02 02:34:14 -070058/**
59 * Performs backup and restore of the System and Secure settings.
60 * List of settings that are backed up are stored in the Settings.java file
61 */
Christopher Tatecc84c692010-03-29 14:54:02 -070062public class SettingsBackupAgent extends BackupAgentHelper {
Christopher Tate436344a2009-09-30 16:17:37 -070063 private static final boolean DEBUG = false;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070064 private static final boolean DEBUG_BACKUP = DEBUG || false;
Amith Yamasani220f4d62009-07-02 02:34:14 -070065
Svet Ganovaabc9632017-07-28 19:37:15 -070066 private static final byte[] NULL_VALUE = new byte[0];
67 private static final int NULL_SIZE = -1;
68
Amith Yamasani220f4d62009-07-02 02:34:14 -070069 private static final String KEY_SYSTEM = "system";
70 private static final String KEY_SECURE = "secure";
Christopher Tate66488d62012-10-02 11:58:01 -070071 private static final String KEY_GLOBAL = "global";
Amith Yamasani8823c0a82009-07-07 14:30:17 -070072 private static final String KEY_LOCALE = "locale";
Amith Yamasani072543f2015-02-13 11:09:45 -080073 private static final String KEY_LOCK_SETTINGS = "lock_settings";
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000074 private static final String KEY_SOFTAP_CONFIG = "softap_config";
Ritesh Reddyadca34a2016-02-04 18:33:30 +000075 private static final String KEY_NETWORK_POLICIES = "network_policies";
Roshan Pius7a2491f2016-06-02 09:22:55 -070076 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
Amith Yamasani220f4d62009-07-02 02:34:14 -070077
Christopher Tatea286f412009-09-18 15:51:15 -070078 // Versioning of the state file. Increment this version
79 // number any time the set of state items is altered.
Roshan Pius7a2491f2016-06-02 09:22:55 -070080 private static final int STATE_VERSION = 7;
Ritesh Reddyadca34a2016-02-04 18:33:30 +000081
82 // Versioning of the Network Policies backup payload.
83 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
84
Christopher Tatea286f412009-09-18 15:51:15 -070085
Christopher Tate66488d62012-10-02 11:58:01 -070086 // Slots in the checksum array. Never insert new items in the middle
87 // of this array; new slots must be appended.
Ritesh Reddyadca34a2016-02-04 18:33:30 +000088 private static final int STATE_SYSTEM = 0;
89 private static final int STATE_SECURE = 1;
90 private static final int STATE_LOCALE = 2;
91 private static final int STATE_WIFI_SUPPLICANT = 3;
92 private static final int STATE_WIFI_CONFIG = 4;
93 private static final int STATE_GLOBAL = 5;
94 private static final int STATE_LOCK_SETTINGS = 6;
95 private static final int STATE_SOFTAP_CONFIG = 7;
96 private static final int STATE_NETWORK_POLICIES = 8;
Roshan Pius7a2491f2016-06-02 09:22:55 -070097 private static final int STATE_WIFI_NEW_CONFIG = 9;
Christopher Tate66488d62012-10-02 11:58:01 -070098
Roshan Pius7a2491f2016-06-02 09:22:55 -070099 private static final int STATE_SIZE = 10; // The current number of state items
Christopher Tate66488d62012-10-02 11:58:01 -0700100
101 // Number of entries in the checksum array at various version numbers
102 private static final int STATE_SIZES[] = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000103 0,
104 4, // version 1
105 5, // version 2 added STATE_WIFI_CONFIG
106 6, // version 3 added STATE_GLOBAL
107 7, // version 4 added STATE_LOCK_SETTINGS
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000108 8, // version 5 added STATE_SOFTAP_CONFIG
Roshan Pius7a2491f2016-06-02 09:22:55 -0700109 9, // version 6 added STATE_NETWORK_POLICIES
110 STATE_SIZE // version 7 added STATE_WIFI_NEW_CONFIG
Christopher Tate66488d62012-10-02 11:58:01 -0700111 };
Amith Yamasanid1582142009-07-08 20:04:55 -0700112
Christopher Tate75a99702011-05-18 16:28:19 -0700113 // Versioning of the 'full backup' format
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000114 // Increment this version any time a new item is added
Roshan Pius7a2491f2016-06-02 09:22:55 -0700115 private static final int FULL_BACKUP_VERSION = 6;
Christopher Tate66488d62012-10-02 11:58:01 -0700116 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
Amith Yamasani072543f2015-02-13 11:09:45 -0800117 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000118 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000119 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
Roshan Pius7a2491f2016-06-02 09:22:55 -0700120 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry
Christopher Tate75a99702011-05-18 16:28:19 -0700121
Svetoslav Ganova571a582011-09-20 18:32:20 -0700122 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700123
124 private static final byte[] EMPTY_DATA = new byte[0];
125
126 private static final String TAG = "SettingsBackupAgent";
127
Amith Yamasani220f4d62009-07-02 02:34:14 -0700128 private static final String[] PROJECTION = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000129 Settings.NameValueTable.NAME,
130 Settings.NameValueTable.VALUE
Amith Yamasani220f4d62009-07-02 02:34:14 -0700131 };
132
Christian Sonntag92c17522009-08-07 15:16:17 -0700133 // the key to store the WIFI data under, should be sorted as last, so restore happens last.
134 // use very late unicode character to quasi-guarantee last sort position.
Amith Yamasani2cfab842009-09-09 18:27:31 -0700135 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800136 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
Amith Yamasani220f4d62009-07-02 02:34:14 -0700137
Amith Yamasani072543f2015-02-13 11:09:45 -0800138 // Keys within the lock settings section
139 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
140 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100141 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED =
142 "visible_pattern_enabled";
143 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS =
144 "power_button_instantly_locks";
Amith Yamasani072543f2015-02-13 11:09:45 -0800145
Christopher Tate4a627c72011-04-01 14:43:32 -0700146 // Name of the temporary file we use during full backup/restore. This is
147 // stored in the full-backup tarfile as well, so should not be changed.
148 private static final String STAGE_FILE = "flattened-data";
149
Amith Yamasani220f4d62009-07-02 02:34:14 -0700150 private SettingsHelper mSettingsHelper;
151
Roshan Pius7a2491f2016-06-02 09:22:55 -0700152 private WifiManager mWifiManager;
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700153
Michal Karpinski6135a262017-08-11 10:45:58 +0100154 // Version of the SDK that com.android.providers.settings package has been restored from.
155 // Populated in onRestore().
156 private int mRestoredFromSdkInt;
157
Svetoslav Ganova571a582011-09-20 18:32:20 -0700158 @Override
Amith Yamasani220f4d62009-07-02 02:34:14 -0700159 public void onCreate() {
Christopher Tate75a99702011-05-18 16:28:19 -0700160 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
161
Amith Yamasani220f4d62009-07-02 02:34:14 -0700162 mSettingsHelper = new SettingsHelper(this);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700163 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700164 super.onCreate();
165 }
166
167 @Override
168 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000169 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700170
171 byte[] systemSettingsData = getSystemSettings();
172 byte[] secureSettingsData = getSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700173 byte[] globalSettingsData = getGlobalSettings();
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100174 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId());
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700175 byte[] locale = mSettingsHelper.getLocaleData();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000176 byte[] softApConfigData = getSoftAPConfiguration();
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000177 byte[] netPoliciesData = getNetworkPolicies();
Roshan Pius7a2491f2016-06-02 09:22:55 -0700178 byte[] wifiFullConfigData = getNewWifiConfigData();
Amith Yamasani220f4d62009-07-02 02:34:14 -0700179
Christopher Tate79ec80d2011-06-24 14:58:49 -0700180 long[] stateChecksums = readOldChecksums(oldState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700181
Christopher Tate79ec80d2011-06-24 14:58:49 -0700182 stateChecksums[STATE_SYSTEM] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000183 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700184 stateChecksums[STATE_SECURE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000185 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
Christopher Tate66488d62012-10-02 11:58:01 -0700186 stateChecksums[STATE_GLOBAL] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000187 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700188 stateChecksums[STATE_LOCALE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000189 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700190 stateChecksums[STATE_WIFI_SUPPLICANT] = 0;
191 stateChecksums[STATE_WIFI_CONFIG] = 0;
Amith Yamasani072543f2015-02-13 11:09:45 -0800192 stateChecksums[STATE_LOCK_SETTINGS] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000193 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
194 lockSettingsData, data);
195 stateChecksums[STATE_SOFTAP_CONFIG] =
196 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
197 softApConfigData, data);
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000198 stateChecksums[STATE_NETWORK_POLICIES] =
199 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
200 netPoliciesData, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700201 stateChecksums[STATE_WIFI_NEW_CONFIG] =
202 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG,
203 wifiFullConfigData, data);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700204
Christopher Tate79ec80d2011-06-24 14:58:49 -0700205 writeNewChecksums(stateChecksums, newState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700206 }
207
208 @Override
209 public void onRestore(BackupDataInput data, int appVersionCode,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000210 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700211
Michal Karpinski6135a262017-08-11 10:45:58 +0100212 // versionCode of com.android.providers.settings corresponds to SDK_INT
213 mRestoredFromSdkInt = appVersionCode;
214
Christopher Tate66488d62012-10-02 11:58:01 -0700215 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800216 Settings.System.getMovedToGlobalSettings(movedToGlobal);
217 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700218 byte[] restoredWifiSupplicantData = null;
219 byte[] restoredWifiIpConfigData = null;
Christopher Tate66488d62012-10-02 11:58:01 -0700220
Amith Yamasani220f4d62009-07-02 02:34:14 -0700221 while (data.readNextHeader()) {
222 final String key = data.getKey();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700223 final int size = data.getDataSize();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000224 switch (key) {
225 case KEY_SYSTEM :
226 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
227 mSettingsHelper.applyAudioSettings();
228 break;
229
230 case KEY_SECURE :
231 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
232 break;
233
234 case KEY_GLOBAL :
235 restoreSettings(data, Settings.Global.CONTENT_URI, null);
236 break;
237
238 case KEY_WIFI_SUPPLICANT :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700239 restoredWifiSupplicantData = new byte[size];
240 data.readEntityData(restoredWifiSupplicantData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000241 break;
242
243 case KEY_LOCALE :
244 byte[] localeData = new byte[size];
245 data.readEntityData(localeData, 0, size);
246 mSettingsHelper.setLocaleData(localeData, size);
247 break;
248
249 case KEY_WIFI_CONFIG :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700250 restoredWifiIpConfigData = new byte[size];
251 data.readEntityData(restoredWifiIpConfigData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000252 break;
253
254 case KEY_LOCK_SETTINGS :
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100255 restoreLockSettings(UserHandle.myUserId(), data);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000256 break;
257
258 case KEY_SOFTAP_CONFIG :
259 byte[] softapData = new byte[size];
260 data.readEntityData(softapData, 0, size);
261 restoreSoftApConfiguration(softapData);
262 break;
263
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000264 case KEY_NETWORK_POLICIES:
265 byte[] netPoliciesData = new byte[size];
266 data.readEntityData(netPoliciesData, 0, size);
267 restoreNetworkPolicies(netPoliciesData);
268 break;
269
Roshan Pius7a2491f2016-06-02 09:22:55 -0700270 case KEY_WIFI_NEW_CONFIG:
271 byte[] restoredWifiNewConfigData = new byte[size];
272 data.readEntityData(restoredWifiNewConfigData, 0, size);
Roshan Pius5db739c2016-06-17 16:51:36 -0700273 restoreNewWifiConfigData(restoredWifiNewConfigData);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700274 break;
275
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000276 default :
277 data.skipEntityData();
278
Amith Yamasani220f4d62009-07-02 02:34:14 -0700279 }
280 }
Christopher Tated488bc02012-10-09 14:06:30 -0700281
Roshan Pius7a2491f2016-06-02 09:22:55 -0700282 // Do this at the end so that we also pull in the ipconfig data.
283 if (restoredWifiSupplicantData != null) {
284 restoreSupplicantWifiConfigData(
Roshan Pius5db739c2016-06-17 16:51:36 -0700285 restoredWifiSupplicantData, restoredWifiIpConfigData);
Christopher Tated488bc02012-10-09 14:06:30 -0700286 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700287 }
288
Christopher Tate75a99702011-05-18 16:28:19 -0700289 @Override
Christopher Tate79ec80d2011-06-24 14:58:49 -0700290 public void onFullBackup(FullBackupDataOutput data) throws IOException {
Michal Karpinskifbcb24582018-01-09 17:06:19 +0000291 // Full backup of SettingsBackupAgent support was removed in Android P. If you want to adb
292 // backup com.android.providers.settings package use \"-keyvalue\" flag.
293 // Full restore of SettingsBackupAgent is still available for backwards compatibility.
Christopher Tate79ec80d2011-06-24 14:58:49 -0700294 }
295
296 @Override
Christopher Tate75a99702011-05-18 16:28:19 -0700297 public void onRestoreFile(ParcelFileDescriptor data, long size,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000298 int type, String domain, String relpath, long mode, long mtime)
Christopher Tate75a99702011-05-18 16:28:19 -0700299 throws IOException {
300 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
301 // Our data is actually a blob of flattened settings data identical to that
302 // produced during incremental backups. Just unpack and apply it all in
303 // turn.
304 FileInputStream instream = new FileInputStream(data.getFileDescriptor());
305 DataInputStream in = new DataInputStream(instream);
306
307 int version = in.readInt();
308 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
Christopher Tate66488d62012-10-02 11:58:01 -0700309 if (version <= FULL_BACKUP_VERSION) {
310 // Generate the moved-to-global lookup table
311 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800312 Settings.System.getMovedToGlobalSettings(movedToGlobal);
313 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Christopher Tate66488d62012-10-02 11:58:01 -0700314
Christopher Tate75a99702011-05-18 16:28:19 -0700315 // system settings data first
316 int nBytes = in.readInt();
317 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
318 byte[] buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700319 in.readFully(buffer, 0, nBytes);
Christopher Tate66488d62012-10-02 11:58:01 -0700320 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
Christopher Tate75a99702011-05-18 16:28:19 -0700321
322 // secure settings
323 nBytes = in.readInt();
324 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
325 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700326 in.readFully(buffer, 0, nBytes);
Christopher Tate66488d62012-10-02 11:58:01 -0700327 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
328
329 // Global only if sufficiently new
330 if (version >= FULL_BACKUP_ADDED_GLOBAL) {
331 nBytes = in.readInt();
332 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
333 if (nBytes > buffer.length) buffer = new byte[nBytes];
334 in.readFully(buffer, 0, nBytes);
335 movedToGlobal.clear(); // no redirection; this *is* the global namespace
336 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
337 }
Christopher Tate75a99702011-05-18 16:28:19 -0700338
339 // locale
340 nBytes = in.readInt();
341 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
342 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700343 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700344 mSettingsHelper.setLocaleData(buffer, nBytes);
345
Roshan Pius7a2491f2016-06-02 09:22:55 -0700346 // Restore older backups performing the necessary migrations.
347 if (version < FULL_BACKUP_ADDED_WIFI_NEW) {
348 // wifi supplicant
349 int supplicant_size = in.readInt();
350 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data");
351 byte[] supplicant_buffer = new byte[supplicant_size];
352 in.readFully(supplicant_buffer, 0, supplicant_size);
Christopher Tate75a99702011-05-18 16:28:19 -0700353
Roshan Pius7a2491f2016-06-02 09:22:55 -0700354 // ip config
355 int ipconfig_size = in.readInt();
356 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data");
357 byte[] ipconfig_buffer = new byte[ipconfig_size];
358 in.readFully(ipconfig_buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700359 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700360 }
Christopher Tate75a99702011-05-18 16:28:19 -0700361
Amith Yamasani072543f2015-02-13 11:09:45 -0800362 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
363 nBytes = in.readInt();
364 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
365 if (nBytes > buffer.length) buffer = new byte[nBytes];
366 if (nBytes > 0) {
367 in.readFully(buffer, 0, nBytes);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100368 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes);
Amith Yamasani072543f2015-02-13 11:09:45 -0800369 }
370 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000371 // softap config
372 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
373 nBytes = in.readInt();
374 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
375 if (nBytes > buffer.length) buffer = new byte[nBytes];
376 if (nBytes > 0) {
377 in.readFully(buffer, 0, nBytes);
378 restoreSoftApConfiguration(buffer);
379 }
380 }
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000381 // network policies
382 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
383 nBytes = in.readInt();
384 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
385 if (nBytes > buffer.length) buffer = new byte[nBytes];
386 if (nBytes > 0) {
387 in.readFully(buffer, 0, nBytes);
388 restoreNetworkPolicies(buffer);
389 }
390 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700391 // Restore full wifi config data
392 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) {
393 nBytes = in.readInt();
394 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data");
395 if (nBytes > buffer.length) buffer = new byte[nBytes];
396 in.readFully(buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700397 restoreNewWifiConfigData(buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700398 }
399
Christopher Tate75a99702011-05-18 16:28:19 -0700400 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
401 } else {
402 data.close();
403 throw new IOException("Invalid file schema");
404 }
405 }
406
Amith Yamasanid1582142009-07-08 20:04:55 -0700407 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
408 long[] stateChecksums = new long[STATE_SIZE];
409
410 DataInputStream dataInput = new DataInputStream(
411 new FileInputStream(oldState.getFileDescriptor()));
Christopher Tatea286f412009-09-18 15:51:15 -0700412
413 try {
414 int stateVersion = dataInput.readInt();
Ritesh Reddy2400d272016-02-02 11:42:26 +0000415 if (stateVersion > STATE_VERSION) {
416 // Constrain the maximum state version this backup agent
417 // can handle in case a newer or corrupt backup set existed
418 stateVersion = STATE_VERSION;
419 }
Christopher Tate66488d62012-10-02 11:58:01 -0700420 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
421 stateChecksums[i] = dataInput.readLong();
Amith Yamasanid1582142009-07-08 20:04:55 -0700422 }
Christopher Tatea286f412009-09-18 15:51:15 -0700423 } catch (EOFException eof) {
424 // With the default 0 checksum we'll wind up forcing a backup of
425 // any unhandled data sets, which is appropriate.
Amith Yamasanid1582142009-07-08 20:04:55 -0700426 }
427 dataInput.close();
428 return stateChecksums;
429 }
430
431 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
432 throws IOException {
433 DataOutputStream dataOutput = new DataOutputStream(
Marvin Paul68795552014-12-16 14:12:33 -0800434 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
Christopher Tatea286f412009-09-18 15:51:15 -0700435
436 dataOutput.writeInt(STATE_VERSION);
Amith Yamasanid1582142009-07-08 20:04:55 -0700437 for (int i = 0; i < STATE_SIZE; i++) {
438 dataOutput.writeLong(checksums[i]);
439 }
440 dataOutput.close();
441 }
442
443 private long writeIfChanged(long oldChecksum, String key, byte[] data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000444 BackupDataOutput output) {
Amith Yamasanid1582142009-07-08 20:04:55 -0700445 CRC32 checkSummer = new CRC32();
446 checkSummer.update(data);
447 long newChecksum = checkSummer.getValue();
448 if (oldChecksum == newChecksum) {
449 return oldChecksum;
450 }
451 try {
Amith Yamasani072543f2015-02-13 11:09:45 -0800452 if (DEBUG_BACKUP) {
453 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
454 }
Amith Yamasanid1582142009-07-08 20:04:55 -0700455 output.writeEntityHeader(key, data.length);
456 output.writeEntityData(data, data.length);
457 } catch (IOException ioe) {
458 // Bail
459 }
460 return newChecksum;
461 }
462
Amith Yamasani220f4d62009-07-02 02:34:14 -0700463 private byte[] getSystemSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700464 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
465 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700466 try {
467 return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
468 } finally {
469 cursor.close();
470 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700471 }
472
473 private byte[] getSecureSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700474 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
475 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700476 try {
477 return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
478 } finally {
479 cursor.close();
480 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700481 }
482
Christopher Tate66488d62012-10-02 11:58:01 -0700483 private byte[] getGlobalSettings() {
484 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
485 null, null);
486 try {
487 return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
488 } finally {
489 cursor.close();
490 }
491 }
492
Amith Yamasani072543f2015-02-13 11:09:45 -0800493 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100494 * Serialize the owner info and other lock settings
Amith Yamasani072543f2015-02-13 11:09:45 -0800495 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100496 private byte[] getLockSettings(@UserIdInt int userId) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800497 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100498 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId);
499 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId);
500 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId);
501 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId);
502 final boolean powerButtonInstantlyLocks =
503 lockPatternUtils.getPowerButtonInstantlyLocks(userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800504
505 ByteArrayOutputStream baos = new ByteArrayOutputStream();
506 DataOutputStream out = new DataOutputStream(baos);
507 try {
508 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
509 out.writeUTF(ownerInfoEnabled ? "1" : "0");
510 if (ownerInfo != null) {
511 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
512 out.writeUTF(ownerInfo != null ? ownerInfo : "");
513 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100514 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) {
515 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED);
516 out.writeUTF(visiblePatternEnabled ? "1" : "0");
517 }
518 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) {
519 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS);
520 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0");
521 }
Amith Yamasani072543f2015-02-13 11:09:45 -0800522 // End marker
523 out.writeUTF("");
524 out.flush();
525 } catch (IOException ioe) {
526 }
527 return baos.toByteArray();
528 }
529
Christopher Tate66488d62012-10-02 11:58:01 -0700530 private void restoreSettings(BackupDataInput data, Uri contentUri,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000531 HashSet<String> movedToGlobal) {
Christopher Tate75a99702011-05-18 16:28:19 -0700532 byte[] settings = new byte[data.getDataSize()];
533 try {
534 data.readEntityData(settings, 0, settings.length);
535 } catch (IOException ioe) {
536 Log.e(TAG, "Couldn't read entity data");
537 return;
538 }
Christopher Tate66488d62012-10-02 11:58:01 -0700539 restoreSettings(settings, settings.length, contentUri, movedToGlobal);
Christopher Tate75a99702011-05-18 16:28:19 -0700540 }
541
Christopher Tate66488d62012-10-02 11:58:01 -0700542 private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000543 HashSet<String> movedToGlobal) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700544 if (DEBUG) {
545 Log.i(TAG, "restoreSettings: " + contentUri);
546 }
547
Christopher Tate1d0fca32017-06-06 13:30:00 -0700548 // Figure out the white list and redirects to the global table. We restore anything
549 // in either the backup whitelist or the legacy-restore whitelist for this table.
Christopher Tate6597e342015-02-17 12:15:25 -0800550 final String[] whitelist;
Christopher Tate796e0f02009-09-22 11:57:58 -0700551 if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700552 whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
553 Settings.Secure.LEGACY_RESTORE_SETTINGS);
Christopher Tate796e0f02009-09-22 11:57:58 -0700554 } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700555 whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
556 Settings.System.LEGACY_RESTORE_SETTINGS);
Christopher Tate66488d62012-10-02 11:58:01 -0700557 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700558 whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
559 Settings.Global.LEGACY_RESTORE_SETTINGS);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700560 } else {
561 throw new IllegalArgumentException("Unknown URI: " + contentUri);
Christopher Tate796e0f02009-09-22 11:57:58 -0700562 }
563
Svetoslav Ganova571a582011-09-20 18:32:20 -0700564 // Restore only the white list data.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700565 int pos = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700566 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700567 ContentValues contentValues = new ContentValues(2);
568 SettingsHelper settingsHelper = mSettingsHelper;
Christopher Tate6597e342015-02-17 12:15:25 -0800569 ContentResolver cr = getContentResolver();
Christopher Tate0738e882009-09-11 16:35:39 -0700570
Svetoslav Ganova571a582011-09-20 18:32:20 -0700571 final int whiteListSize = whitelist.length;
572 for (int i = 0; i < whiteListSize; i++) {
573 String key = whitelist[i];
Christopher Tate0738e882009-09-11 16:35:39 -0700574
Svet Ganovaabc9632017-07-28 19:37:15 -0700575 String value = null;
576 boolean hasValueToRestore = false;
577 if (cachedEntries.indexOfKey(key) >= 0) {
578 value = cachedEntries.remove(key);
579 hasValueToRestore = true;
580 } else {
581 // If the value not cached, let us look it up.
Svetoslav Ganova571a582011-09-20 18:32:20 -0700582 while (pos < bytes) {
583 int length = readInt(settings, pos);
584 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700585 String dataKey = length >= 0 ? new String(settings, pos, length) : null;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700586 pos += length;
587 length = readInt(settings, pos);
588 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700589 String dataValue = null;
590 if (length >= 0) {
591 dataValue = new String(settings, pos, length);
592 pos += length;
593 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700594 if (key.equals(dataKey)) {
595 value = dataValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700596 hasValueToRestore = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700597 break;
598 }
599 cachedEntries.put(dataKey, dataValue);
Amith Yamasani70c874b2009-07-06 14:53:25 -0700600 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700601 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700602
Svet Ganovaabc9632017-07-28 19:37:15 -0700603 if (!hasValueToRestore) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700604 continue;
605 }
Christopher Tate796e0f02009-09-22 11:57:58 -0700606
Christopher Tate3543beb2012-10-05 13:35:12 -0700607 final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
Christopher Tate66488d62012-10-02 11:58:01 -0700608 ? Settings.Global.CONTENT_URI
609 : contentUri;
Michal Karpinski6135a262017-08-11 10:45:58 +0100610 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
611 mRestoredFromSdkInt);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700612
Christopher Tated488bc02012-10-09 14:06:30 -0700613 if (DEBUG) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000614 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
Christopher Tate0738e882009-09-11 16:35:39 -0700615 }
616 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700617 }
618
Christopher Tate1d0fca32017-06-06 13:30:00 -0700619 private final String[] concat(String[] first, @Nullable String[] second) {
620 if (second == null || second.length == 0) {
621 return first;
622 }
623 final int firstLen = first.length;
624 final int secondLen = second.length;
625 String[] both = new String[firstLen + secondLen];
626 System.arraycopy(first, 0, both, 0, firstLen);
627 System.arraycopy(second, 0, both, firstLen, secondLen);
628 return both;
629 }
630
Amith Yamasani220f4d62009-07-02 02:34:14 -0700631 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100632 * Restores the owner info enabled and other settings in LockSettings.
Amith Yamasani072543f2015-02-13 11:09:45 -0800633 *
634 * @param buffer
635 * @param nBytes
636 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100637 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800638 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
639
640 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
641 DataInputStream in = new DataInputStream(bais);
642 try {
643 String key;
644 // Read until empty string marker
645 while ((key = in.readUTF()).length() > 0) {
646 final String value = in.readUTF();
647 if (DEBUG_BACKUP) {
648 Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
649 }
650 switch (key) {
651 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100652 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800653 break;
654 case KEY_LOCK_SETTINGS_OWNER_INFO:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100655 lockPatternUtils.setOwnerInfo(value, userId);
656 break;
657 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED:
658 lockPatternUtils.reportPatternWasChosen(userId);
659 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId);
660 break;
661 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
662 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800663 break;
664 }
665 }
666 in.close();
667 } catch (IOException ioe) {
668 }
669 }
670
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100671 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800672 final byte[] settings = new byte[data.getDataSize()];
673 try {
674 data.readEntityData(settings, 0, settings.length);
675 } catch (IOException ioe) {
676 Log.e(TAG, "Couldn't read entity data");
677 return;
678 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100679 restoreLockSettings(userId, settings, settings.length);
Amith Yamasani072543f2015-02-13 11:09:45 -0800680 }
681
682 /**
Svetoslav Ganova571a582011-09-20 18:32:20 -0700683 * Given a cursor and a set of keys, extract the required keys and
684 * values and write them to a byte array.
685 *
686 * @param cursor A cursor with settings data.
687 * @param settings The settings to extract.
688 * @return The byte array of extracted values.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700689 */
Svetoslav Ganova571a582011-09-20 18:32:20 -0700690 private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700691 if (!cursor.moveToFirst()) {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700692 Log.e(TAG, "Couldn't read from the cursor");
693 return new byte[0];
694 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700695
Svet Ganovaabc9632017-07-28 19:37:15 -0700696 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
697 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
698
Svetoslav Ganova571a582011-09-20 18:32:20 -0700699 // Obtain the relevant data in a temporary array.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700700 int totalSize = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700701 int backedUpSettingIndex = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700702 final int settingsCount = settings.length;
703 final byte[][] values = new byte[settingsCount * 2][]; // keys and values
704 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700705 for (int i = 0; i < settingsCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700706 final String key = settings[i];
Svetoslav683914b2015-01-15 14:22:26 -0800707
Svetoslav Ganova571a582011-09-20 18:32:20 -0700708 // If the value not cached, let us look it up.
Svet Ganovaabc9632017-07-28 19:37:15 -0700709 String value = null;
710 boolean hasValueToBackup = false;
711 if (cachedEntries.indexOfKey(key) >= 0) {
712 value = cachedEntries.remove(key);
713 hasValueToBackup = true;
714 } else {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700715 while (!cursor.isAfterLast()) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700716 final String cursorKey = cursor.getString(nameColumnIndex);
717 final String cursorValue = cursor.getString(valueColumnIndex);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700718 cursor.moveToNext();
719 if (key.equals(cursorKey)) {
720 value = cursorValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700721 hasValueToBackup = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700722 break;
723 }
724 cachedEntries.put(cursorKey, cursorValue);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700725 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700726 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700727
Svet Ganovaabc9632017-07-28 19:37:15 -0700728 if (!hasValueToBackup) {
729 continue;
730 }
731
Amith Yamasani622bf2222013-09-06 13:54:28 -0700732 // Intercept the keys and see if they need special handling
733 value = mSettingsHelper.onBackupValue(key, value);
734
Svetoslav Ganova571a582011-09-20 18:32:20 -0700735 // Write the key and value in the intermediary array.
Svet Ganovaabc9632017-07-28 19:37:15 -0700736 final byte[] keyBytes = key.getBytes();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700737 totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
738 values[backedUpSettingIndex * 2] = keyBytes;
739
Svet Ganovaabc9632017-07-28 19:37:15 -0700740 final byte[] valueBytes = (value != null) ? value.getBytes() : NULL_VALUE;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700741 totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
742 values[backedUpSettingIndex * 2 + 1] = valueBytes;
743
744 backedUpSettingIndex++;
745
746 if (DEBUG) {
747 Log.d(TAG, "Backed up setting: " + key + "=" + value);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700748 }
749 }
750
Svetoslav Ganova571a582011-09-20 18:32:20 -0700751 // Aggregate the result.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700752 byte[] result = new byte[totalSize];
753 int pos = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700754 final int keyValuePairCount = backedUpSettingIndex * 2;
755 for (int i = 0; i < keyValuePairCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700756 final byte[] value = values[i];
757 if (value != NULL_VALUE) {
758 pos = writeInt(result, pos, value.length);
759 pos = writeBytes(result, pos, value);
760 } else {
761 pos = writeInt(result, pos, NULL_SIZE);
762 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700763 }
764 return result;
765 }
766
Roshan Pius5db739c2016-06-17 16:51:36 -0700767 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700768 if (DEBUG_BACKUP) {
769 Log.v(TAG, "Applying restored supplicant wifi data");
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800770 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700771 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes);
Amith Yamasani2cfab842009-09-09 18:27:31 -0700772 }
773
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000774 private byte[] getSoftAPConfiguration() {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000775 try {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700776 return mWifiManager.getWifiApConfiguration().getBytesForBackup();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000777 } catch (IOException ioe) {
778 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
779 return new byte[0];
780 }
781 }
782
783 private void restoreSoftApConfiguration(byte[] data) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000784 try {
785 WifiConfiguration config = WifiConfiguration
786 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
787 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
Roshan Pius7a2491f2016-06-02 09:22:55 -0700788 mWifiManager.setWifiApConfiguration(config);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000789 } catch (IOException | BackupUtils.BadVersionException e) {
790 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
791 }
792 }
793
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000794 private byte[] getNetworkPolicies() {
795 NetworkPolicyManager networkPolicyManager =
796 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
797 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
798 ByteArrayOutputStream baos = new ByteArrayOutputStream();
799 if (policies != null && policies.length != 0) {
800 DataOutputStream out = new DataOutputStream(baos);
801 try {
802 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
803 out.writeInt(policies.length);
804 for (NetworkPolicy policy : policies) {
805 if (policy != null) {
806 byte[] marshaledPolicy = policy.getBytesForBackup();
807 out.writeByte(BackupUtils.NOT_NULL);
808 out.writeInt(marshaledPolicy.length);
809 out.write(marshaledPolicy);
810 } else {
811 out.writeByte(BackupUtils.NULL);
812 }
813 }
814 } catch (IOException ioe) {
815 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
816 baos.reset();
817 }
818 }
819 return baos.toByteArray();
820 }
821
Roshan Pius7a2491f2016-06-02 09:22:55 -0700822 private byte[] getNewWifiConfigData() {
823 return mWifiManager.retrieveBackupData();
824 }
825
Roshan Pius5db739c2016-06-17 16:51:36 -0700826 private void restoreNewWifiConfigData(byte[] bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700827 if (DEBUG_BACKUP) {
828 Log.v(TAG, "Applying restored wifi data");
829 }
830 mWifiManager.restoreBackupData(bytes);
831 }
832
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000833 private void restoreNetworkPolicies(byte[] data) {
834 NetworkPolicyManager networkPolicyManager =
835 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
836 if (data != null && data.length != 0) {
837 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
838 try {
839 int version = in.readInt();
840 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
841 throw new BackupUtils.BadVersionException(
842 "Unknown Backup Serialization Version");
843 }
844 int length = in.readInt();
845 NetworkPolicy[] policies = new NetworkPolicy[length];
846 for (int i = 0; i < length; i++) {
847 byte isNull = in.readByte();
848 if (isNull == BackupUtils.NULL) continue;
849 int byteLength = in.readInt();
850 byte[] policyData = new byte[byteLength];
851 in.read(policyData, 0, byteLength);
852 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
853 new DataInputStream(new ByteArrayInputStream(policyData)));
854 }
855 // Only set the policies if there was no error in the restore operation
856 networkPolicyManager.setNetworkPolicies(policies);
857 } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
858 // NPE can be thrown when trying to instantiate a NetworkPolicy
859 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
860 }
861 }
862 }
863
Amith Yamasani220f4d62009-07-02 02:34:14 -0700864 /**
865 * Write an int in BigEndian into the byte array.
866 * @param out byte array
867 * @param pos current pos in array
868 * @param value integer to write
Svetoslav Ganova571a582011-09-20 18:32:20 -0700869 * @return the index after adding the size of an int (4) in bytes.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700870 */
871 private int writeInt(byte[] out, int pos, int value) {
872 out[pos + 0] = (byte) ((value >> 24) & 0xFF);
873 out[pos + 1] = (byte) ((value >> 16) & 0xFF);
874 out[pos + 2] = (byte) ((value >> 8) & 0xFF);
875 out[pos + 3] = (byte) ((value >> 0) & 0xFF);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700876 return pos + INTEGER_BYTE_COUNT;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700877 }
878
879 private int writeBytes(byte[] out, int pos, byte[] value) {
880 System.arraycopy(value, 0, out, pos, value.length);
881 return pos + value.length;
882 }
883
884 private int readInt(byte[] in, int pos) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000885 int result = ((in[pos] & 0xFF) << 24)
886 | ((in[pos + 1] & 0xFF) << 16)
887 | ((in[pos + 2] & 0xFF) << 8)
888 | ((in[pos + 3] & 0xFF) << 0);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700889 return result;
890 }
Paul Stewart45e6fec2016-05-20 08:14:30 -0700891}