blob: d884fab518ced25814c45b588e748c43a134205f [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;
Michal Karpinski6517d882018-01-08 15:23:03 +000034import android.os.Build;
Svetoslav Ganova571a582011-09-20 18:32:20 -070035import android.os.ParcelFileDescriptor;
Amith Yamasani072543f2015-02-13 11:09:45 -080036import android.os.UserHandle;
Svetoslav Ganova571a582011-09-20 18:32:20 -070037import android.provider.Settings;
Michal Karpinskib52575c2018-01-19 17:38:45 +000038import android.provider.SettingsValidators.Validator;
Svet Ganovaabc9632017-07-28 19:37:15 -070039import android.util.ArrayMap;
Michal Karpinski6517d882018-01-08 15:23:03 +000040import android.util.ArraySet;
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000041import android.util.BackupUtils;
Svetoslav Ganova571a582011-09-20 18:32:20 -070042import android.util.Log;
43
Amith Yamasani072543f2015-02-13 11:09:45 -080044import com.android.internal.widget.LockPatternUtils;
45
Brad Fitzpatrick70787892010-11-17 11:31:12 -080046import java.io.BufferedOutputStream;
Amith Yamasani072543f2015-02-13 11:09:45 -080047import java.io.ByteArrayInputStream;
Christopher Tatecab915a2015-01-08 12:50:00 -080048import java.io.ByteArrayOutputStream;
Amith Yamasanid1582142009-07-08 20:04:55 -070049import java.io.DataInputStream;
50import java.io.DataOutputStream;
Amith Yamasani2cfab842009-09-09 18:27:31 -070051import java.io.EOFException;
Amith Yamasani220f4d62009-07-02 02:34:14 -070052import java.io.FileInputStream;
53import java.io.FileOutputStream;
54import java.io.IOException;
Annie Meng47f5c9c2018-02-27 14:48:21 +000055import java.time.DateTimeException;
Michal Karpinski6517d882018-01-08 15:23:03 +000056import java.util.Arrays;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070057import java.util.HashSet;
Svetoslav Ganova571a582011-09-20 18:32:20 -070058import java.util.Map;
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +010059import java.util.Set;
Amith Yamasanid1582142009-07-08 20:04:55 -070060import java.util.zip.CRC32;
Amith Yamasani220f4d62009-07-02 02:34:14 -070061
Amith Yamasani220f4d62009-07-02 02:34:14 -070062/**
63 * Performs backup and restore of the System and Secure settings.
64 * List of settings that are backed up are stored in the Settings.java file
65 */
Christopher Tatecc84c692010-03-29 14:54:02 -070066public class SettingsBackupAgent extends BackupAgentHelper {
Christopher Tate436344a2009-09-30 16:17:37 -070067 private static final boolean DEBUG = false;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070068 private static final boolean DEBUG_BACKUP = DEBUG || false;
Amith Yamasani220f4d62009-07-02 02:34:14 -070069
Svet Ganovaabc9632017-07-28 19:37:15 -070070 private static final byte[] NULL_VALUE = new byte[0];
71 private static final int NULL_SIZE = -1;
72
Amith Yamasani220f4d62009-07-02 02:34:14 -070073 private static final String KEY_SYSTEM = "system";
74 private static final String KEY_SECURE = "secure";
Christopher Tate66488d62012-10-02 11:58:01 -070075 private static final String KEY_GLOBAL = "global";
Amith Yamasani8823c0a82009-07-07 14:30:17 -070076 private static final String KEY_LOCALE = "locale";
Amith Yamasani072543f2015-02-13 11:09:45 -080077 private static final String KEY_LOCK_SETTINGS = "lock_settings";
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000078 private static final String KEY_SOFTAP_CONFIG = "softap_config";
Ritesh Reddyadca34a2016-02-04 18:33:30 +000079 private static final String KEY_NETWORK_POLICIES = "network_policies";
Roshan Pius7a2491f2016-06-02 09:22:55 -070080 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
Amith Yamasani220f4d62009-07-02 02:34:14 -070081
Christopher Tatea286f412009-09-18 15:51:15 -070082 // Versioning of the state file. Increment this version
83 // number any time the set of state items is altered.
Roshan Pius7a2491f2016-06-02 09:22:55 -070084 private static final int STATE_VERSION = 7;
Ritesh Reddyadca34a2016-02-04 18:33:30 +000085
86 // Versioning of the Network Policies backup payload.
87 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
88
Christopher Tatea286f412009-09-18 15:51:15 -070089
Christopher Tate66488d62012-10-02 11:58:01 -070090 // Slots in the checksum array. Never insert new items in the middle
91 // of this array; new slots must be appended.
Ritesh Reddyadca34a2016-02-04 18:33:30 +000092 private static final int STATE_SYSTEM = 0;
93 private static final int STATE_SECURE = 1;
94 private static final int STATE_LOCALE = 2;
95 private static final int STATE_WIFI_SUPPLICANT = 3;
96 private static final int STATE_WIFI_CONFIG = 4;
97 private static final int STATE_GLOBAL = 5;
98 private static final int STATE_LOCK_SETTINGS = 6;
99 private static final int STATE_SOFTAP_CONFIG = 7;
100 private static final int STATE_NETWORK_POLICIES = 8;
Roshan Pius7a2491f2016-06-02 09:22:55 -0700101 private static final int STATE_WIFI_NEW_CONFIG = 9;
Christopher Tate66488d62012-10-02 11:58:01 -0700102
Roshan Pius7a2491f2016-06-02 09:22:55 -0700103 private static final int STATE_SIZE = 10; // The current number of state items
Christopher Tate66488d62012-10-02 11:58:01 -0700104
105 // Number of entries in the checksum array at various version numbers
106 private static final int STATE_SIZES[] = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000107 0,
108 4, // version 1
109 5, // version 2 added STATE_WIFI_CONFIG
110 6, // version 3 added STATE_GLOBAL
111 7, // version 4 added STATE_LOCK_SETTINGS
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000112 8, // version 5 added STATE_SOFTAP_CONFIG
Roshan Pius7a2491f2016-06-02 09:22:55 -0700113 9, // version 6 added STATE_NETWORK_POLICIES
114 STATE_SIZE // version 7 added STATE_WIFI_NEW_CONFIG
Christopher Tate66488d62012-10-02 11:58:01 -0700115 };
Amith Yamasanid1582142009-07-08 20:04:55 -0700116
Christopher Tate75a99702011-05-18 16:28:19 -0700117 // Versioning of the 'full backup' format
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000118 // Increment this version any time a new item is added
Roshan Pius7a2491f2016-06-02 09:22:55 -0700119 private static final int FULL_BACKUP_VERSION = 6;
Christopher Tate66488d62012-10-02 11:58:01 -0700120 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
Amith Yamasani072543f2015-02-13 11:09:45 -0800121 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000122 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000123 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
Roshan Pius7a2491f2016-06-02 09:22:55 -0700124 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry
Christopher Tate75a99702011-05-18 16:28:19 -0700125
Svetoslav Ganova571a582011-09-20 18:32:20 -0700126 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700127
128 private static final byte[] EMPTY_DATA = new byte[0];
129
130 private static final String TAG = "SettingsBackupAgent";
131
Amith Yamasani220f4d62009-07-02 02:34:14 -0700132 private static final String[] PROJECTION = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000133 Settings.NameValueTable.NAME,
134 Settings.NameValueTable.VALUE
Amith Yamasani220f4d62009-07-02 02:34:14 -0700135 };
136
Christian Sonntag92c17522009-08-07 15:16:17 -0700137 // the key to store the WIFI data under, should be sorted as last, so restore happens last.
138 // use very late unicode character to quasi-guarantee last sort position.
Amith Yamasani2cfab842009-09-09 18:27:31 -0700139 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800140 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
Amith Yamasani220f4d62009-07-02 02:34:14 -0700141
Amith Yamasani072543f2015-02-13 11:09:45 -0800142 // Keys within the lock settings section
143 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
144 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100145 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED =
146 "visible_pattern_enabled";
147 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS =
148 "power_button_instantly_locks";
Amith Yamasani072543f2015-02-13 11:09:45 -0800149
Christopher Tate4a627c72011-04-01 14:43:32 -0700150 // Name of the temporary file we use during full backup/restore. This is
151 // stored in the full-backup tarfile as well, so should not be changed.
152 private static final String STAGE_FILE = "flattened-data";
153
Michal Karpinski6517d882018-01-08 15:23:03 +0000154 // List of keys that support restore to lower version of the SDK, introduced in Android P
155 private static final ArraySet<String> RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS =
156 new ArraySet<String>(Arrays.asList(new String[] {
157 KEY_NETWORK_POLICIES,
158 KEY_WIFI_NEW_CONFIG,
Michal Karpinskib52575c2018-01-19 17:38:45 +0000159 KEY_SYSTEM,
160 KEY_SECURE,
161 KEY_GLOBAL,
Michal Karpinski6517d882018-01-08 15:23:03 +0000162 }));
163
Amith Yamasani220f4d62009-07-02 02:34:14 -0700164 private SettingsHelper mSettingsHelper;
165
Roshan Pius7a2491f2016-06-02 09:22:55 -0700166 private WifiManager mWifiManager;
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700167
Michal Karpinski6135a262017-08-11 10:45:58 +0100168 // Version of the SDK that com.android.providers.settings package has been restored from.
169 // Populated in onRestore().
170 private int mRestoredFromSdkInt;
171
Svetoslav Ganova571a582011-09-20 18:32:20 -0700172 @Override
Amith Yamasani220f4d62009-07-02 02:34:14 -0700173 public void onCreate() {
Christopher Tate75a99702011-05-18 16:28:19 -0700174 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
175
Amith Yamasani220f4d62009-07-02 02:34:14 -0700176 mSettingsHelper = new SettingsHelper(this);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700177 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700178 super.onCreate();
179 }
180
181 @Override
182 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000183 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700184
185 byte[] systemSettingsData = getSystemSettings();
186 byte[] secureSettingsData = getSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700187 byte[] globalSettingsData = getGlobalSettings();
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100188 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId());
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700189 byte[] locale = mSettingsHelper.getLocaleData();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000190 byte[] softApConfigData = getSoftAPConfiguration();
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000191 byte[] netPoliciesData = getNetworkPolicies();
Roshan Pius7a2491f2016-06-02 09:22:55 -0700192 byte[] wifiFullConfigData = getNewWifiConfigData();
Amith Yamasani220f4d62009-07-02 02:34:14 -0700193
Christopher Tate79ec80d2011-06-24 14:58:49 -0700194 long[] stateChecksums = readOldChecksums(oldState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700195
Christopher Tate79ec80d2011-06-24 14:58:49 -0700196 stateChecksums[STATE_SYSTEM] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000197 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700198 stateChecksums[STATE_SECURE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000199 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
Christopher Tate66488d62012-10-02 11:58:01 -0700200 stateChecksums[STATE_GLOBAL] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000201 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700202 stateChecksums[STATE_LOCALE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000203 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700204 stateChecksums[STATE_WIFI_SUPPLICANT] = 0;
205 stateChecksums[STATE_WIFI_CONFIG] = 0;
Amith Yamasani072543f2015-02-13 11:09:45 -0800206 stateChecksums[STATE_LOCK_SETTINGS] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000207 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
208 lockSettingsData, data);
209 stateChecksums[STATE_SOFTAP_CONFIG] =
210 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
211 softApConfigData, data);
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000212 stateChecksums[STATE_NETWORK_POLICIES] =
213 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
214 netPoliciesData, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700215 stateChecksums[STATE_WIFI_NEW_CONFIG] =
216 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG,
217 wifiFullConfigData, data);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700218
Christopher Tate79ec80d2011-06-24 14:58:49 -0700219 writeNewChecksums(stateChecksums, newState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700220 }
221
222 @Override
223 public void onRestore(BackupDataInput data, int appVersionCode,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000224 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700225
Michal Karpinski6517d882018-01-08 15:23:03 +0000226 if (DEBUG) {
227 Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode
228 + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT);
229 }
Michal Karpinskib52575c2018-01-19 17:38:45 +0000230
231 boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(),
232 Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1;
233 if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) {
234 Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API"
235 + Build.VERSION.SDK_INT + " due to settings flag override.");
236 return;
237 }
238
Michal Karpinski6135a262017-08-11 10:45:58 +0100239 // versionCode of com.android.providers.settings corresponds to SDK_INT
240 mRestoredFromSdkInt = appVersionCode;
241
Christopher Tate66488d62012-10-02 11:58:01 -0700242 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800243 Settings.System.getMovedToGlobalSettings(movedToGlobal);
244 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100245 Set<String> movedToSecure = getMovedToSecureSettings();
246
Roshan Pius7a2491f2016-06-02 09:22:55 -0700247 byte[] restoredWifiSupplicantData = null;
248 byte[] restoredWifiIpConfigData = null;
Christopher Tate66488d62012-10-02 11:58:01 -0700249
Amith Yamasani220f4d62009-07-02 02:34:14 -0700250 while (data.readNextHeader()) {
251 final String key = data.getKey();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700252 final int size = data.getDataSize();
Michal Karpinski6517d882018-01-08 15:23:03 +0000253
254 // bail out of restoring from higher SDK_INT version for unsupported keys
255 if (appVersionCode > Build.VERSION.SDK_INT
256 && !RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS.contains(key)) {
257 Log.w(TAG, "Not restoring unrecognized key '"
258 + key + "' from future version " + appVersionCode);
Anton Philippov54c6d6c2018-04-10 22:52:28 +0100259 data.skipEntityData();
Michal Karpinski6517d882018-01-08 15:23:03 +0000260 continue;
261 }
262
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000263 switch (key) {
264 case KEY_SYSTEM :
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100265 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
266 movedToSecure);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000267 mSettingsHelper.applyAudioSettings();
268 break;
269
270 case KEY_SECURE :
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100271 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, null);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000272 break;
273
274 case KEY_GLOBAL :
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100275 restoreSettings(data, Settings.Global.CONTENT_URI, null, movedToSecure);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000276 break;
277
278 case KEY_WIFI_SUPPLICANT :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700279 restoredWifiSupplicantData = new byte[size];
280 data.readEntityData(restoredWifiSupplicantData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000281 break;
282
283 case KEY_LOCALE :
284 byte[] localeData = new byte[size];
285 data.readEntityData(localeData, 0, size);
286 mSettingsHelper.setLocaleData(localeData, size);
287 break;
288
289 case KEY_WIFI_CONFIG :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700290 restoredWifiIpConfigData = new byte[size];
291 data.readEntityData(restoredWifiIpConfigData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000292 break;
293
294 case KEY_LOCK_SETTINGS :
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100295 restoreLockSettings(UserHandle.myUserId(), data);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000296 break;
297
298 case KEY_SOFTAP_CONFIG :
299 byte[] softapData = new byte[size];
300 data.readEntityData(softapData, 0, size);
301 restoreSoftApConfiguration(softapData);
302 break;
303
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000304 case KEY_NETWORK_POLICIES:
305 byte[] netPoliciesData = new byte[size];
306 data.readEntityData(netPoliciesData, 0, size);
307 restoreNetworkPolicies(netPoliciesData);
308 break;
309
Roshan Pius7a2491f2016-06-02 09:22:55 -0700310 case KEY_WIFI_NEW_CONFIG:
311 byte[] restoredWifiNewConfigData = new byte[size];
312 data.readEntityData(restoredWifiNewConfigData, 0, size);
Roshan Pius5db739c2016-06-17 16:51:36 -0700313 restoreNewWifiConfigData(restoredWifiNewConfigData);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700314 break;
315
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000316 default :
317 data.skipEntityData();
318
Amith Yamasani220f4d62009-07-02 02:34:14 -0700319 }
320 }
Christopher Tated488bc02012-10-09 14:06:30 -0700321
Roshan Pius7a2491f2016-06-02 09:22:55 -0700322 // Do this at the end so that we also pull in the ipconfig data.
323 if (restoredWifiSupplicantData != null) {
324 restoreSupplicantWifiConfigData(
Roshan Pius5db739c2016-06-17 16:51:36 -0700325 restoredWifiSupplicantData, restoredWifiIpConfigData);
Christopher Tated488bc02012-10-09 14:06:30 -0700326 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700327 }
328
Christopher Tate75a99702011-05-18 16:28:19 -0700329 @Override
Christopher Tate79ec80d2011-06-24 14:58:49 -0700330 public void onFullBackup(FullBackupDataOutput data) throws IOException {
Michal Karpinskifbcb24582018-01-09 17:06:19 +0000331 // Full backup of SettingsBackupAgent support was removed in Android P. If you want to adb
332 // backup com.android.providers.settings package use \"-keyvalue\" flag.
333 // Full restore of SettingsBackupAgent is still available for backwards compatibility.
Christopher Tate79ec80d2011-06-24 14:58:49 -0700334 }
335
336 @Override
Christopher Tate75a99702011-05-18 16:28:19 -0700337 public void onRestoreFile(ParcelFileDescriptor data, long size,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000338 int type, String domain, String relpath, long mode, long mtime)
Christopher Tate75a99702011-05-18 16:28:19 -0700339 throws IOException {
340 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
341 // Our data is actually a blob of flattened settings data identical to that
342 // produced during incremental backups. Just unpack and apply it all in
343 // turn.
344 FileInputStream instream = new FileInputStream(data.getFileDescriptor());
345 DataInputStream in = new DataInputStream(instream);
346
347 int version = in.readInt();
348 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
Christopher Tate66488d62012-10-02 11:58:01 -0700349 if (version <= FULL_BACKUP_VERSION) {
350 // Generate the moved-to-global lookup table
351 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800352 Settings.System.getMovedToGlobalSettings(movedToGlobal);
353 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100354 Set<String> movedToSecure = getMovedToSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700355
Christopher Tate75a99702011-05-18 16:28:19 -0700356 // system settings data first
357 int nBytes = in.readInt();
358 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
359 byte[] buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700360 in.readFully(buffer, 0, nBytes);
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100361 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
362 movedToSecure);
Christopher Tate75a99702011-05-18 16:28:19 -0700363
364 // secure settings
365 nBytes = in.readInt();
366 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
367 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700368 in.readFully(buffer, 0, nBytes);
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100369 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, null);
Christopher Tate66488d62012-10-02 11:58:01 -0700370
371 // Global only if sufficiently new
372 if (version >= FULL_BACKUP_ADDED_GLOBAL) {
373 nBytes = in.readInt();
374 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
375 if (nBytes > buffer.length) buffer = new byte[nBytes];
376 in.readFully(buffer, 0, nBytes);
377 movedToGlobal.clear(); // no redirection; this *is* the global namespace
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100378 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
379 movedToSecure);
Christopher Tate66488d62012-10-02 11:58:01 -0700380 }
Christopher Tate75a99702011-05-18 16:28:19 -0700381
382 // locale
383 nBytes = in.readInt();
384 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
385 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700386 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700387 mSettingsHelper.setLocaleData(buffer, nBytes);
388
Roshan Pius7a2491f2016-06-02 09:22:55 -0700389 // Restore older backups performing the necessary migrations.
390 if (version < FULL_BACKUP_ADDED_WIFI_NEW) {
391 // wifi supplicant
392 int supplicant_size = in.readInt();
393 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data");
394 byte[] supplicant_buffer = new byte[supplicant_size];
395 in.readFully(supplicant_buffer, 0, supplicant_size);
Christopher Tate75a99702011-05-18 16:28:19 -0700396
Roshan Pius7a2491f2016-06-02 09:22:55 -0700397 // ip config
398 int ipconfig_size = in.readInt();
399 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data");
400 byte[] ipconfig_buffer = new byte[ipconfig_size];
401 in.readFully(ipconfig_buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700402 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700403 }
Christopher Tate75a99702011-05-18 16:28:19 -0700404
Amith Yamasani072543f2015-02-13 11:09:45 -0800405 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
406 nBytes = in.readInt();
407 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
408 if (nBytes > buffer.length) buffer = new byte[nBytes];
409 if (nBytes > 0) {
410 in.readFully(buffer, 0, nBytes);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100411 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes);
Amith Yamasani072543f2015-02-13 11:09:45 -0800412 }
413 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000414 // softap config
415 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
416 nBytes = in.readInt();
417 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
418 if (nBytes > buffer.length) buffer = new byte[nBytes];
419 if (nBytes > 0) {
420 in.readFully(buffer, 0, nBytes);
421 restoreSoftApConfiguration(buffer);
422 }
423 }
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000424 // network policies
425 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
426 nBytes = in.readInt();
427 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
428 if (nBytes > buffer.length) buffer = new byte[nBytes];
429 if (nBytes > 0) {
430 in.readFully(buffer, 0, nBytes);
431 restoreNetworkPolicies(buffer);
432 }
433 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700434 // Restore full wifi config data
435 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) {
436 nBytes = in.readInt();
437 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data");
438 if (nBytes > buffer.length) buffer = new byte[nBytes];
439 in.readFully(buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700440 restoreNewWifiConfigData(buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700441 }
442
Christopher Tate75a99702011-05-18 16:28:19 -0700443 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
444 } else {
445 data.close();
446 throw new IOException("Invalid file schema");
447 }
448 }
449
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100450 private Set<String> getMovedToSecureSettings() {
451 Set<String> movedToSecureSettings = new HashSet<>();
452 Settings.Global.getMovedToSecureSettings(movedToSecureSettings);
453 Settings.System.getMovedToSecureSettings(movedToSecureSettings);
454 return movedToSecureSettings;
455 }
456
Amith Yamasanid1582142009-07-08 20:04:55 -0700457 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
458 long[] stateChecksums = new long[STATE_SIZE];
459
460 DataInputStream dataInput = new DataInputStream(
461 new FileInputStream(oldState.getFileDescriptor()));
Christopher Tatea286f412009-09-18 15:51:15 -0700462
463 try {
464 int stateVersion = dataInput.readInt();
Ritesh Reddy2400d272016-02-02 11:42:26 +0000465 if (stateVersion > STATE_VERSION) {
466 // Constrain the maximum state version this backup agent
467 // can handle in case a newer or corrupt backup set existed
468 stateVersion = STATE_VERSION;
469 }
Christopher Tate66488d62012-10-02 11:58:01 -0700470 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
471 stateChecksums[i] = dataInput.readLong();
Amith Yamasanid1582142009-07-08 20:04:55 -0700472 }
Christopher Tatea286f412009-09-18 15:51:15 -0700473 } catch (EOFException eof) {
474 // With the default 0 checksum we'll wind up forcing a backup of
475 // any unhandled data sets, which is appropriate.
Amith Yamasanid1582142009-07-08 20:04:55 -0700476 }
477 dataInput.close();
478 return stateChecksums;
479 }
480
481 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
482 throws IOException {
483 DataOutputStream dataOutput = new DataOutputStream(
Marvin Paul68795552014-12-16 14:12:33 -0800484 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
Christopher Tatea286f412009-09-18 15:51:15 -0700485
486 dataOutput.writeInt(STATE_VERSION);
Amith Yamasanid1582142009-07-08 20:04:55 -0700487 for (int i = 0; i < STATE_SIZE; i++) {
488 dataOutput.writeLong(checksums[i]);
489 }
490 dataOutput.close();
491 }
492
493 private long writeIfChanged(long oldChecksum, String key, byte[] data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000494 BackupDataOutput output) {
Amith Yamasanid1582142009-07-08 20:04:55 -0700495 CRC32 checkSummer = new CRC32();
496 checkSummer.update(data);
497 long newChecksum = checkSummer.getValue();
498 if (oldChecksum == newChecksum) {
499 return oldChecksum;
500 }
501 try {
Amith Yamasani072543f2015-02-13 11:09:45 -0800502 if (DEBUG_BACKUP) {
503 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
504 }
Amith Yamasanid1582142009-07-08 20:04:55 -0700505 output.writeEntityHeader(key, data.length);
506 output.writeEntityData(data, data.length);
507 } catch (IOException ioe) {
508 // Bail
509 }
510 return newChecksum;
511 }
512
Amith Yamasani220f4d62009-07-02 02:34:14 -0700513 private byte[] getSystemSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700514 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
515 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700516 try {
517 return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
518 } finally {
519 cursor.close();
520 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700521 }
522
523 private byte[] getSecureSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700524 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
525 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700526 try {
527 return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
528 } finally {
529 cursor.close();
530 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700531 }
532
Christopher Tate66488d62012-10-02 11:58:01 -0700533 private byte[] getGlobalSettings() {
534 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
535 null, null);
536 try {
537 return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
538 } finally {
539 cursor.close();
540 }
541 }
542
Amith Yamasani072543f2015-02-13 11:09:45 -0800543 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100544 * Serialize the owner info and other lock settings
Amith Yamasani072543f2015-02-13 11:09:45 -0800545 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100546 private byte[] getLockSettings(@UserIdInt int userId) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800547 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100548 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId);
549 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId);
550 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId);
551 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId);
552 final boolean powerButtonInstantlyLocks =
553 lockPatternUtils.getPowerButtonInstantlyLocks(userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800554
555 ByteArrayOutputStream baos = new ByteArrayOutputStream();
556 DataOutputStream out = new DataOutputStream(baos);
557 try {
558 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
559 out.writeUTF(ownerInfoEnabled ? "1" : "0");
560 if (ownerInfo != null) {
561 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
562 out.writeUTF(ownerInfo != null ? ownerInfo : "");
563 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100564 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) {
565 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED);
566 out.writeUTF(visiblePatternEnabled ? "1" : "0");
567 }
568 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) {
569 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS);
570 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0");
571 }
Amith Yamasani072543f2015-02-13 11:09:45 -0800572 // End marker
573 out.writeUTF("");
574 out.flush();
575 } catch (IOException ioe) {
576 }
577 return baos.toByteArray();
578 }
579
Christopher Tate66488d62012-10-02 11:58:01 -0700580 private void restoreSettings(BackupDataInput data, Uri contentUri,
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100581 HashSet<String> movedToGlobal, Set<String> movedToSecure) {
Christopher Tate75a99702011-05-18 16:28:19 -0700582 byte[] settings = new byte[data.getDataSize()];
583 try {
584 data.readEntityData(settings, 0, settings.length);
585 } catch (IOException ioe) {
586 Log.e(TAG, "Couldn't read entity data");
587 return;
588 }
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100589 restoreSettings(settings, settings.length, contentUri, movedToGlobal, movedToSecure);
Christopher Tate75a99702011-05-18 16:28:19 -0700590 }
591
Christopher Tate66488d62012-10-02 11:58:01 -0700592 private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100593 HashSet<String> movedToGlobal, Set<String> movedToSecure) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700594 if (DEBUG) {
595 Log.i(TAG, "restoreSettings: " + contentUri);
596 }
597
Christopher Tate1d0fca32017-06-06 13:30:00 -0700598 // Figure out the white list and redirects to the global table. We restore anything
599 // in either the backup whitelist or the legacy-restore whitelist for this table.
Christopher Tate6597e342015-02-17 12:15:25 -0800600 final String[] whitelist;
Michal Karpinskib52575c2018-01-19 17:38:45 +0000601 Map<String, Validator> validators = null;
Christopher Tate796e0f02009-09-22 11:57:58 -0700602 if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700603 whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
604 Settings.Secure.LEGACY_RESTORE_SETTINGS);
Michal Karpinskib52575c2018-01-19 17:38:45 +0000605 validators = Settings.Secure.VALIDATORS;
Christopher Tate796e0f02009-09-22 11:57:58 -0700606 } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700607 whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
608 Settings.System.LEGACY_RESTORE_SETTINGS);
Michal Karpinskib52575c2018-01-19 17:38:45 +0000609 validators = Settings.System.VALIDATORS;
Christopher Tate66488d62012-10-02 11:58:01 -0700610 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700611 whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
612 Settings.Global.LEGACY_RESTORE_SETTINGS);
Michal Karpinskib52575c2018-01-19 17:38:45 +0000613 validators = Settings.Global.VALIDATORS;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700614 } else {
615 throw new IllegalArgumentException("Unknown URI: " + contentUri);
Christopher Tate796e0f02009-09-22 11:57:58 -0700616 }
617
Svetoslav Ganova571a582011-09-20 18:32:20 -0700618 // Restore only the white list data.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700619 int pos = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700620 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700621 ContentValues contentValues = new ContentValues(2);
622 SettingsHelper settingsHelper = mSettingsHelper;
Christopher Tate6597e342015-02-17 12:15:25 -0800623 ContentResolver cr = getContentResolver();
Christopher Tate0738e882009-09-11 16:35:39 -0700624
Svetoslav Ganova571a582011-09-20 18:32:20 -0700625 final int whiteListSize = whitelist.length;
626 for (int i = 0; i < whiteListSize; i++) {
627 String key = whitelist[i];
Christopher Tate0738e882009-09-11 16:35:39 -0700628
Svet Ganovaabc9632017-07-28 19:37:15 -0700629 String value = null;
630 boolean hasValueToRestore = false;
631 if (cachedEntries.indexOfKey(key) >= 0) {
632 value = cachedEntries.remove(key);
633 hasValueToRestore = true;
634 } else {
635 // If the value not cached, let us look it up.
Svetoslav Ganova571a582011-09-20 18:32:20 -0700636 while (pos < bytes) {
637 int length = readInt(settings, pos);
638 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700639 String dataKey = length >= 0 ? new String(settings, pos, length) : null;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700640 pos += length;
641 length = readInt(settings, pos);
642 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700643 String dataValue = null;
644 if (length >= 0) {
645 dataValue = new String(settings, pos, length);
646 pos += length;
647 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700648 if (key.equals(dataKey)) {
649 value = dataValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700650 hasValueToRestore = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700651 break;
652 }
653 cachedEntries.put(dataKey, dataValue);
Amith Yamasani70c874b2009-07-06 14:53:25 -0700654 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700655 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700656
Svet Ganovaabc9632017-07-28 19:37:15 -0700657 if (!hasValueToRestore) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700658 continue;
659 }
Christopher Tate796e0f02009-09-22 11:57:58 -0700660
Michal Karpinskib52575c2018-01-19 17:38:45 +0000661 // only restore the settings that have valid values
662 if (!isValidSettingValue(key, value, validators)) {
663 Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass"
664 + " validation, value: " + value);
665 continue;
666 }
667
Ruslan Tkhakokhov55c4a592019-07-24 21:13:35 +0100668 final Uri destination;
669 if (movedToGlobal != null && movedToGlobal.contains(key)) {
670 destination = Settings.Global.CONTENT_URI;
671 } else if (movedToSecure != null && movedToSecure.contains(key)) {
672 destination = Settings.Secure.CONTENT_URI;
673 } else {
674 destination = contentUri;
675 }
Michal Karpinski6135a262017-08-11 10:45:58 +0100676 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
677 mRestoredFromSdkInt);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700678
Christopher Tated488bc02012-10-09 14:06:30 -0700679 if (DEBUG) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000680 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
Christopher Tate0738e882009-09-11 16:35:39 -0700681 }
682 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700683 }
684
Michal Karpinskib52575c2018-01-19 17:38:45 +0000685 private boolean isValidSettingValue(String key, String value,
686 Map<String, Validator> validators) {
687 if (key == null || validators == null) {
688 return false;
689 }
690 Validator validator = validators.get(key);
691 return (validator != null) && validator.validate(value);
692 }
693
Christopher Tate1d0fca32017-06-06 13:30:00 -0700694 private final String[] concat(String[] first, @Nullable String[] second) {
695 if (second == null || second.length == 0) {
696 return first;
697 }
698 final int firstLen = first.length;
699 final int secondLen = second.length;
700 String[] both = new String[firstLen + secondLen];
701 System.arraycopy(first, 0, both, 0, firstLen);
702 System.arraycopy(second, 0, both, firstLen, secondLen);
703 return both;
704 }
705
Amith Yamasani220f4d62009-07-02 02:34:14 -0700706 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100707 * Restores the owner info enabled and other settings in LockSettings.
Amith Yamasani072543f2015-02-13 11:09:45 -0800708 *
709 * @param buffer
710 * @param nBytes
711 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100712 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800713 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
714
715 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
716 DataInputStream in = new DataInputStream(bais);
717 try {
718 String key;
719 // Read until empty string marker
720 while ((key = in.readUTF()).length() > 0) {
721 final String value = in.readUTF();
722 if (DEBUG_BACKUP) {
723 Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
724 }
725 switch (key) {
726 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100727 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800728 break;
729 case KEY_LOCK_SETTINGS_OWNER_INFO:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100730 lockPatternUtils.setOwnerInfo(value, userId);
731 break;
732 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED:
733 lockPatternUtils.reportPatternWasChosen(userId);
734 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId);
735 break;
736 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
737 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800738 break;
739 }
740 }
741 in.close();
742 } catch (IOException ioe) {
743 }
744 }
745
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100746 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800747 final byte[] settings = new byte[data.getDataSize()];
748 try {
749 data.readEntityData(settings, 0, settings.length);
750 } catch (IOException ioe) {
751 Log.e(TAG, "Couldn't read entity data");
752 return;
753 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100754 restoreLockSettings(userId, settings, settings.length);
Amith Yamasani072543f2015-02-13 11:09:45 -0800755 }
756
757 /**
Svetoslav Ganova571a582011-09-20 18:32:20 -0700758 * Given a cursor and a set of keys, extract the required keys and
759 * values and write them to a byte array.
760 *
761 * @param cursor A cursor with settings data.
762 * @param settings The settings to extract.
763 * @return The byte array of extracted values.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700764 */
Svetoslav Ganova571a582011-09-20 18:32:20 -0700765 private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700766 if (!cursor.moveToFirst()) {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700767 Log.e(TAG, "Couldn't read from the cursor");
768 return new byte[0];
769 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700770
Svet Ganovaabc9632017-07-28 19:37:15 -0700771 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
772 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
773
Svetoslav Ganova571a582011-09-20 18:32:20 -0700774 // Obtain the relevant data in a temporary array.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700775 int totalSize = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700776 int backedUpSettingIndex = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700777 final int settingsCount = settings.length;
778 final byte[][] values = new byte[settingsCount * 2][]; // keys and values
779 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700780 for (int i = 0; i < settingsCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700781 final String key = settings[i];
Svetoslav683914b2015-01-15 14:22:26 -0800782
Svetoslav Ganova571a582011-09-20 18:32:20 -0700783 // If the value not cached, let us look it up.
Svet Ganovaabc9632017-07-28 19:37:15 -0700784 String value = null;
785 boolean hasValueToBackup = false;
786 if (cachedEntries.indexOfKey(key) >= 0) {
787 value = cachedEntries.remove(key);
788 hasValueToBackup = true;
789 } else {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700790 while (!cursor.isAfterLast()) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700791 final String cursorKey = cursor.getString(nameColumnIndex);
792 final String cursorValue = cursor.getString(valueColumnIndex);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700793 cursor.moveToNext();
794 if (key.equals(cursorKey)) {
795 value = cursorValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700796 hasValueToBackup = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700797 break;
798 }
799 cachedEntries.put(cursorKey, cursorValue);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700800 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700801 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700802
Svet Ganovaabc9632017-07-28 19:37:15 -0700803 if (!hasValueToBackup) {
804 continue;
805 }
806
Amith Yamasani622bf2222013-09-06 13:54:28 -0700807 // Intercept the keys and see if they need special handling
808 value = mSettingsHelper.onBackupValue(key, value);
809
Svetoslav Ganova571a582011-09-20 18:32:20 -0700810 // Write the key and value in the intermediary array.
Svet Ganovaabc9632017-07-28 19:37:15 -0700811 final byte[] keyBytes = key.getBytes();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700812 totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
813 values[backedUpSettingIndex * 2] = keyBytes;
814
Svet Ganovaabc9632017-07-28 19:37:15 -0700815 final byte[] valueBytes = (value != null) ? value.getBytes() : NULL_VALUE;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700816 totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
817 values[backedUpSettingIndex * 2 + 1] = valueBytes;
818
819 backedUpSettingIndex++;
820
821 if (DEBUG) {
822 Log.d(TAG, "Backed up setting: " + key + "=" + value);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700823 }
824 }
825
Svetoslav Ganova571a582011-09-20 18:32:20 -0700826 // Aggregate the result.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700827 byte[] result = new byte[totalSize];
828 int pos = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700829 final int keyValuePairCount = backedUpSettingIndex * 2;
830 for (int i = 0; i < keyValuePairCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700831 final byte[] value = values[i];
832 if (value != NULL_VALUE) {
833 pos = writeInt(result, pos, value.length);
834 pos = writeBytes(result, pos, value);
835 } else {
836 pos = writeInt(result, pos, NULL_SIZE);
837 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700838 }
839 return result;
840 }
841
Roshan Pius5db739c2016-06-17 16:51:36 -0700842 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700843 if (DEBUG_BACKUP) {
844 Log.v(TAG, "Applying restored supplicant wifi data");
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800845 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700846 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes);
Amith Yamasani2cfab842009-09-09 18:27:31 -0700847 }
848
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000849 private byte[] getSoftAPConfiguration() {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000850 try {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700851 return mWifiManager.getWifiApConfiguration().getBytesForBackup();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000852 } catch (IOException ioe) {
853 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
854 return new byte[0];
855 }
856 }
857
858 private void restoreSoftApConfiguration(byte[] data) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000859 try {
860 WifiConfiguration config = WifiConfiguration
861 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
862 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700863 int originalApBand = config.apBand;
Roshan Pius7a2491f2016-06-02 09:22:55 -0700864 mWifiManager.setWifiApConfiguration(config);
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700865
866 // Depending on device hardware, we may need to notify the user of a setting change for
867 // the apBand preference
868 boolean dualMode = mWifiManager.isDualModeSupported();
869 int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
870 if (dualMode) {
871 if (storedApBand != originalApBand) {
872 Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
873 mWifiManager.notifyUserOfApBandConversion();
874 }
875 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000876 } catch (IOException | BackupUtils.BadVersionException e) {
877 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
878 }
879 }
880
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000881 private byte[] getNetworkPolicies() {
882 NetworkPolicyManager networkPolicyManager =
883 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
884 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
885 ByteArrayOutputStream baos = new ByteArrayOutputStream();
886 if (policies != null && policies.length != 0) {
887 DataOutputStream out = new DataOutputStream(baos);
888 try {
889 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
890 out.writeInt(policies.length);
891 for (NetworkPolicy policy : policies) {
Jeff Sharkey55a3fe72018-02-24 19:09:20 -0700892 // We purposefully only backup policies that the user has
893 // defined; any inferred policies might include
894 // carrier-protected data that we can't export.
895 if (policy != null && !policy.inferred) {
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000896 byte[] marshaledPolicy = policy.getBytesForBackup();
897 out.writeByte(BackupUtils.NOT_NULL);
898 out.writeInt(marshaledPolicy.length);
899 out.write(marshaledPolicy);
900 } else {
901 out.writeByte(BackupUtils.NULL);
902 }
903 }
904 } catch (IOException ioe) {
905 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
906 baos.reset();
907 }
908 }
909 return baos.toByteArray();
910 }
911
Roshan Pius7a2491f2016-06-02 09:22:55 -0700912 private byte[] getNewWifiConfigData() {
913 return mWifiManager.retrieveBackupData();
914 }
915
Roshan Pius5db739c2016-06-17 16:51:36 -0700916 private void restoreNewWifiConfigData(byte[] bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700917 if (DEBUG_BACKUP) {
918 Log.v(TAG, "Applying restored wifi data");
919 }
920 mWifiManager.restoreBackupData(bytes);
921 }
922
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000923 private void restoreNetworkPolicies(byte[] data) {
924 NetworkPolicyManager networkPolicyManager =
925 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
926 if (data != null && data.length != 0) {
927 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
928 try {
929 int version = in.readInt();
930 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
931 throw new BackupUtils.BadVersionException(
932 "Unknown Backup Serialization Version");
933 }
934 int length = in.readInt();
935 NetworkPolicy[] policies = new NetworkPolicy[length];
936 for (int i = 0; i < length; i++) {
937 byte isNull = in.readByte();
938 if (isNull == BackupUtils.NULL) continue;
939 int byteLength = in.readInt();
940 byte[] policyData = new byte[byteLength];
941 in.read(policyData, 0, byteLength);
942 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
943 new DataInputStream(new ByteArrayInputStream(policyData)));
944 }
945 // Only set the policies if there was no error in the restore operation
946 networkPolicyManager.setNetworkPolicies(policies);
Annie Meng47f5c9c2018-02-27 14:48:21 +0000947 } catch (NullPointerException | IOException | BackupUtils.BadVersionException
948 | DateTimeException e) {
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000949 // NPE can be thrown when trying to instantiate a NetworkPolicy
950 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
951 }
952 }
953 }
954
Amith Yamasani220f4d62009-07-02 02:34:14 -0700955 /**
956 * Write an int in BigEndian into the byte array.
957 * @param out byte array
958 * @param pos current pos in array
959 * @param value integer to write
Svetoslav Ganova571a582011-09-20 18:32:20 -0700960 * @return the index after adding the size of an int (4) in bytes.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700961 */
962 private int writeInt(byte[] out, int pos, int value) {
963 out[pos + 0] = (byte) ((value >> 24) & 0xFF);
964 out[pos + 1] = (byte) ((value >> 16) & 0xFF);
965 out[pos + 2] = (byte) ((value >> 8) & 0xFF);
966 out[pos + 3] = (byte) ((value >> 0) & 0xFF);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700967 return pos + INTEGER_BYTE_COUNT;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700968 }
969
970 private int writeBytes(byte[] out, int pos, byte[] value) {
971 System.arraycopy(value, 0, out, pos, value.length);
972 return pos + value.length;
973 }
974
975 private int readInt(byte[] in, int pos) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000976 int result = ((in[pos] & 0xFF) << 24)
977 | ((in[pos + 1] & 0xFF) << 16)
978 | ((in[pos + 2] & 0xFF) << 8)
979 | ((in[pos + 3] & 0xFF) << 0);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700980 return result;
981 }
Paul Stewart45e6fec2016-05-20 08:14:30 -0700982}