blob: 9d398b5b69a1dfc5ae240e31e46da1164253ec8b [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;
Amith Yamasanid1582142009-07-08 20:04:55 -070059import java.util.zip.CRC32;
Amith Yamasani220f4d62009-07-02 02:34:14 -070060
Amith Yamasani220f4d62009-07-02 02:34:14 -070061/**
62 * Performs backup and restore of the System and Secure settings.
63 * List of settings that are backed up are stored in the Settings.java file
64 */
Christopher Tatecc84c692010-03-29 14:54:02 -070065public class SettingsBackupAgent extends BackupAgentHelper {
Christopher Tate436344a2009-09-30 16:17:37 -070066 private static final boolean DEBUG = false;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070067 private static final boolean DEBUG_BACKUP = DEBUG || false;
Amith Yamasani220f4d62009-07-02 02:34:14 -070068
Svet Ganovaabc9632017-07-28 19:37:15 -070069 private static final byte[] NULL_VALUE = new byte[0];
70 private static final int NULL_SIZE = -1;
71
Amith Yamasani220f4d62009-07-02 02:34:14 -070072 private static final String KEY_SYSTEM = "system";
73 private static final String KEY_SECURE = "secure";
Christopher Tate66488d62012-10-02 11:58:01 -070074 private static final String KEY_GLOBAL = "global";
Amith Yamasani8823c0a82009-07-07 14:30:17 -070075 private static final String KEY_LOCALE = "locale";
Amith Yamasani072543f2015-02-13 11:09:45 -080076 private static final String KEY_LOCK_SETTINGS = "lock_settings";
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000077 private static final String KEY_SOFTAP_CONFIG = "softap_config";
Ritesh Reddyadca34a2016-02-04 18:33:30 +000078 private static final String KEY_NETWORK_POLICIES = "network_policies";
Roshan Pius7a2491f2016-06-02 09:22:55 -070079 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
Amith Yamasani220f4d62009-07-02 02:34:14 -070080
Christopher Tatea286f412009-09-18 15:51:15 -070081 // Versioning of the state file. Increment this version
82 // number any time the set of state items is altered.
Roshan Pius7a2491f2016-06-02 09:22:55 -070083 private static final int STATE_VERSION = 7;
Ritesh Reddyadca34a2016-02-04 18:33:30 +000084
85 // Versioning of the Network Policies backup payload.
86 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
87
Christopher Tatea286f412009-09-18 15:51:15 -070088
Christopher Tate66488d62012-10-02 11:58:01 -070089 // Slots in the checksum array. Never insert new items in the middle
90 // of this array; new slots must be appended.
Ritesh Reddyadca34a2016-02-04 18:33:30 +000091 private static final int STATE_SYSTEM = 0;
92 private static final int STATE_SECURE = 1;
93 private static final int STATE_LOCALE = 2;
94 private static final int STATE_WIFI_SUPPLICANT = 3;
95 private static final int STATE_WIFI_CONFIG = 4;
96 private static final int STATE_GLOBAL = 5;
97 private static final int STATE_LOCK_SETTINGS = 6;
98 private static final int STATE_SOFTAP_CONFIG = 7;
99 private static final int STATE_NETWORK_POLICIES = 8;
Roshan Pius7a2491f2016-06-02 09:22:55 -0700100 private static final int STATE_WIFI_NEW_CONFIG = 9;
Christopher Tate66488d62012-10-02 11:58:01 -0700101
Roshan Pius7a2491f2016-06-02 09:22:55 -0700102 private static final int STATE_SIZE = 10; // The current number of state items
Christopher Tate66488d62012-10-02 11:58:01 -0700103
104 // Number of entries in the checksum array at various version numbers
105 private static final int STATE_SIZES[] = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000106 0,
107 4, // version 1
108 5, // version 2 added STATE_WIFI_CONFIG
109 6, // version 3 added STATE_GLOBAL
110 7, // version 4 added STATE_LOCK_SETTINGS
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000111 8, // version 5 added STATE_SOFTAP_CONFIG
Roshan Pius7a2491f2016-06-02 09:22:55 -0700112 9, // version 6 added STATE_NETWORK_POLICIES
113 STATE_SIZE // version 7 added STATE_WIFI_NEW_CONFIG
Christopher Tate66488d62012-10-02 11:58:01 -0700114 };
Amith Yamasanid1582142009-07-08 20:04:55 -0700115
Christopher Tate75a99702011-05-18 16:28:19 -0700116 // Versioning of the 'full backup' format
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000117 // Increment this version any time a new item is added
Roshan Pius7a2491f2016-06-02 09:22:55 -0700118 private static final int FULL_BACKUP_VERSION = 6;
Christopher Tate66488d62012-10-02 11:58:01 -0700119 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
Amith Yamasani072543f2015-02-13 11:09:45 -0800120 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000121 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000122 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
Roshan Pius7a2491f2016-06-02 09:22:55 -0700123 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry
Christopher Tate75a99702011-05-18 16:28:19 -0700124
Svetoslav Ganova571a582011-09-20 18:32:20 -0700125 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700126
127 private static final byte[] EMPTY_DATA = new byte[0];
128
129 private static final String TAG = "SettingsBackupAgent";
130
Amith Yamasani220f4d62009-07-02 02:34:14 -0700131 private static final String[] PROJECTION = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000132 Settings.NameValueTable.NAME,
133 Settings.NameValueTable.VALUE
Amith Yamasani220f4d62009-07-02 02:34:14 -0700134 };
135
Christian Sonntag92c17522009-08-07 15:16:17 -0700136 // the key to store the WIFI data under, should be sorted as last, so restore happens last.
137 // use very late unicode character to quasi-guarantee last sort position.
Amith Yamasani2cfab842009-09-09 18:27:31 -0700138 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800139 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
Amith Yamasani220f4d62009-07-02 02:34:14 -0700140
Amith Yamasani072543f2015-02-13 11:09:45 -0800141 // Keys within the lock settings section
142 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
143 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100144 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED =
145 "visible_pattern_enabled";
146 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS =
147 "power_button_instantly_locks";
Amith Yamasani072543f2015-02-13 11:09:45 -0800148
Christopher Tate4a627c72011-04-01 14:43:32 -0700149 // Name of the temporary file we use during full backup/restore. This is
150 // stored in the full-backup tarfile as well, so should not be changed.
151 private static final String STAGE_FILE = "flattened-data";
152
Michal Karpinski6517d882018-01-08 15:23:03 +0000153 // List of keys that support restore to lower version of the SDK, introduced in Android P
154 private static final ArraySet<String> RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS =
155 new ArraySet<String>(Arrays.asList(new String[] {
156 KEY_NETWORK_POLICIES,
157 KEY_WIFI_NEW_CONFIG,
Michal Karpinskib52575c2018-01-19 17:38:45 +0000158 KEY_SYSTEM,
159 KEY_SECURE,
160 KEY_GLOBAL,
Michal Karpinski6517d882018-01-08 15:23:03 +0000161 }));
162
Amith Yamasani220f4d62009-07-02 02:34:14 -0700163 private SettingsHelper mSettingsHelper;
164
Roshan Pius7a2491f2016-06-02 09:22:55 -0700165 private WifiManager mWifiManager;
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700166
Michal Karpinski6135a262017-08-11 10:45:58 +0100167 // Version of the SDK that com.android.providers.settings package has been restored from.
168 // Populated in onRestore().
169 private int mRestoredFromSdkInt;
170
Svetoslav Ganova571a582011-09-20 18:32:20 -0700171 @Override
Amith Yamasani220f4d62009-07-02 02:34:14 -0700172 public void onCreate() {
Christopher Tate75a99702011-05-18 16:28:19 -0700173 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
174
Amith Yamasani220f4d62009-07-02 02:34:14 -0700175 mSettingsHelper = new SettingsHelper(this);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700176 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700177 super.onCreate();
178 }
179
180 @Override
181 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000182 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700183
184 byte[] systemSettingsData = getSystemSettings();
185 byte[] secureSettingsData = getSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700186 byte[] globalSettingsData = getGlobalSettings();
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100187 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId());
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700188 byte[] locale = mSettingsHelper.getLocaleData();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000189 byte[] softApConfigData = getSoftAPConfiguration();
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000190 byte[] netPoliciesData = getNetworkPolicies();
Roshan Pius7a2491f2016-06-02 09:22:55 -0700191 byte[] wifiFullConfigData = getNewWifiConfigData();
Amith Yamasani220f4d62009-07-02 02:34:14 -0700192
Christopher Tate79ec80d2011-06-24 14:58:49 -0700193 long[] stateChecksums = readOldChecksums(oldState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700194
Christopher Tate79ec80d2011-06-24 14:58:49 -0700195 stateChecksums[STATE_SYSTEM] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000196 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700197 stateChecksums[STATE_SECURE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000198 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
Christopher Tate66488d62012-10-02 11:58:01 -0700199 stateChecksums[STATE_GLOBAL] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000200 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700201 stateChecksums[STATE_LOCALE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000202 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700203 stateChecksums[STATE_WIFI_SUPPLICANT] = 0;
204 stateChecksums[STATE_WIFI_CONFIG] = 0;
Amith Yamasani072543f2015-02-13 11:09:45 -0800205 stateChecksums[STATE_LOCK_SETTINGS] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000206 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
207 lockSettingsData, data);
208 stateChecksums[STATE_SOFTAP_CONFIG] =
209 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
210 softApConfigData, data);
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000211 stateChecksums[STATE_NETWORK_POLICIES] =
212 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
213 netPoliciesData, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700214 stateChecksums[STATE_WIFI_NEW_CONFIG] =
215 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG,
216 wifiFullConfigData, data);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700217
Christopher Tate79ec80d2011-06-24 14:58:49 -0700218 writeNewChecksums(stateChecksums, newState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700219 }
220
221 @Override
222 public void onRestore(BackupDataInput data, int appVersionCode,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000223 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700224
Michal Karpinski6517d882018-01-08 15:23:03 +0000225 if (DEBUG) {
226 Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode
227 + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT);
228 }
Michal Karpinskib52575c2018-01-19 17:38:45 +0000229
230 boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(),
231 Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1;
232 if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) {
233 Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API"
234 + Build.VERSION.SDK_INT + " due to settings flag override.");
235 return;
236 }
237
Michal Karpinski6135a262017-08-11 10:45:58 +0100238 // versionCode of com.android.providers.settings corresponds to SDK_INT
239 mRestoredFromSdkInt = appVersionCode;
240
Christopher Tate66488d62012-10-02 11:58:01 -0700241 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800242 Settings.System.getMovedToGlobalSettings(movedToGlobal);
243 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700244 byte[] restoredWifiSupplicantData = null;
245 byte[] restoredWifiIpConfigData = null;
Christopher Tate66488d62012-10-02 11:58:01 -0700246
Amith Yamasani220f4d62009-07-02 02:34:14 -0700247 while (data.readNextHeader()) {
248 final String key = data.getKey();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700249 final int size = data.getDataSize();
Michal Karpinski6517d882018-01-08 15:23:03 +0000250
251 // bail out of restoring from higher SDK_INT version for unsupported keys
252 if (appVersionCode > Build.VERSION.SDK_INT
253 && !RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS.contains(key)) {
254 Log.w(TAG, "Not restoring unrecognized key '"
255 + key + "' from future version " + appVersionCode);
Anton Philippov54c6d6c2018-04-10 22:52:28 +0100256 data.skipEntityData();
Michal Karpinski6517d882018-01-08 15:23:03 +0000257 continue;
258 }
259
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000260 switch (key) {
261 case KEY_SYSTEM :
262 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
263 mSettingsHelper.applyAudioSettings();
264 break;
265
266 case KEY_SECURE :
267 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
268 break;
269
270 case KEY_GLOBAL :
271 restoreSettings(data, Settings.Global.CONTENT_URI, null);
272 break;
273
274 case KEY_WIFI_SUPPLICANT :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700275 restoredWifiSupplicantData = new byte[size];
276 data.readEntityData(restoredWifiSupplicantData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000277 break;
278
279 case KEY_LOCALE :
280 byte[] localeData = new byte[size];
281 data.readEntityData(localeData, 0, size);
282 mSettingsHelper.setLocaleData(localeData, size);
283 break;
284
285 case KEY_WIFI_CONFIG :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700286 restoredWifiIpConfigData = new byte[size];
287 data.readEntityData(restoredWifiIpConfigData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000288 break;
289
290 case KEY_LOCK_SETTINGS :
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100291 restoreLockSettings(UserHandle.myUserId(), data);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000292 break;
293
294 case KEY_SOFTAP_CONFIG :
295 byte[] softapData = new byte[size];
296 data.readEntityData(softapData, 0, size);
297 restoreSoftApConfiguration(softapData);
298 break;
299
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000300 case KEY_NETWORK_POLICIES:
301 byte[] netPoliciesData = new byte[size];
302 data.readEntityData(netPoliciesData, 0, size);
303 restoreNetworkPolicies(netPoliciesData);
304 break;
305
Roshan Pius7a2491f2016-06-02 09:22:55 -0700306 case KEY_WIFI_NEW_CONFIG:
307 byte[] restoredWifiNewConfigData = new byte[size];
308 data.readEntityData(restoredWifiNewConfigData, 0, size);
Roshan Pius5db739c2016-06-17 16:51:36 -0700309 restoreNewWifiConfigData(restoredWifiNewConfigData);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700310 break;
311
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000312 default :
313 data.skipEntityData();
314
Amith Yamasani220f4d62009-07-02 02:34:14 -0700315 }
316 }
Christopher Tated488bc02012-10-09 14:06:30 -0700317
Roshan Pius7a2491f2016-06-02 09:22:55 -0700318 // Do this at the end so that we also pull in the ipconfig data.
319 if (restoredWifiSupplicantData != null) {
320 restoreSupplicantWifiConfigData(
Roshan Pius5db739c2016-06-17 16:51:36 -0700321 restoredWifiSupplicantData, restoredWifiIpConfigData);
Christopher Tated488bc02012-10-09 14:06:30 -0700322 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700323 }
324
Christopher Tate75a99702011-05-18 16:28:19 -0700325 @Override
Christopher Tate79ec80d2011-06-24 14:58:49 -0700326 public void onFullBackup(FullBackupDataOutput data) throws IOException {
Michal Karpinskifbcb24582018-01-09 17:06:19 +0000327 // Full backup of SettingsBackupAgent support was removed in Android P. If you want to adb
328 // backup com.android.providers.settings package use \"-keyvalue\" flag.
329 // Full restore of SettingsBackupAgent is still available for backwards compatibility.
Christopher Tate79ec80d2011-06-24 14:58:49 -0700330 }
331
332 @Override
Christopher Tate75a99702011-05-18 16:28:19 -0700333 public void onRestoreFile(ParcelFileDescriptor data, long size,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000334 int type, String domain, String relpath, long mode, long mtime)
Christopher Tate75a99702011-05-18 16:28:19 -0700335 throws IOException {
336 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
337 // Our data is actually a blob of flattened settings data identical to that
338 // produced during incremental backups. Just unpack and apply it all in
339 // turn.
340 FileInputStream instream = new FileInputStream(data.getFileDescriptor());
341 DataInputStream in = new DataInputStream(instream);
342
343 int version = in.readInt();
344 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
Christopher Tate66488d62012-10-02 11:58:01 -0700345 if (version <= FULL_BACKUP_VERSION) {
346 // Generate the moved-to-global lookup table
347 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800348 Settings.System.getMovedToGlobalSettings(movedToGlobal);
349 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Christopher Tate66488d62012-10-02 11:58:01 -0700350
Christopher Tate75a99702011-05-18 16:28:19 -0700351 // system settings data first
352 int nBytes = in.readInt();
353 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
354 byte[] buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700355 in.readFully(buffer, 0, nBytes);
Christopher Tate66488d62012-10-02 11:58:01 -0700356 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
Christopher Tate75a99702011-05-18 16:28:19 -0700357
358 // secure settings
359 nBytes = in.readInt();
360 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
361 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700362 in.readFully(buffer, 0, nBytes);
Christopher Tate66488d62012-10-02 11:58:01 -0700363 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
364
365 // Global only if sufficiently new
366 if (version >= FULL_BACKUP_ADDED_GLOBAL) {
367 nBytes = in.readInt();
368 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
369 if (nBytes > buffer.length) buffer = new byte[nBytes];
370 in.readFully(buffer, 0, nBytes);
371 movedToGlobal.clear(); // no redirection; this *is* the global namespace
372 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
373 }
Christopher Tate75a99702011-05-18 16:28:19 -0700374
375 // locale
376 nBytes = in.readInt();
377 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
378 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700379 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700380 mSettingsHelper.setLocaleData(buffer, nBytes);
381
Roshan Pius7a2491f2016-06-02 09:22:55 -0700382 // Restore older backups performing the necessary migrations.
383 if (version < FULL_BACKUP_ADDED_WIFI_NEW) {
384 // wifi supplicant
385 int supplicant_size = in.readInt();
386 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data");
387 byte[] supplicant_buffer = new byte[supplicant_size];
388 in.readFully(supplicant_buffer, 0, supplicant_size);
Christopher Tate75a99702011-05-18 16:28:19 -0700389
Roshan Pius7a2491f2016-06-02 09:22:55 -0700390 // ip config
391 int ipconfig_size = in.readInt();
392 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data");
393 byte[] ipconfig_buffer = new byte[ipconfig_size];
394 in.readFully(ipconfig_buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700395 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700396 }
Christopher Tate75a99702011-05-18 16:28:19 -0700397
Amith Yamasani072543f2015-02-13 11:09:45 -0800398 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
399 nBytes = in.readInt();
400 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
401 if (nBytes > buffer.length) buffer = new byte[nBytes];
402 if (nBytes > 0) {
403 in.readFully(buffer, 0, nBytes);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100404 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes);
Amith Yamasani072543f2015-02-13 11:09:45 -0800405 }
406 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000407 // softap config
408 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
409 nBytes = in.readInt();
410 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
411 if (nBytes > buffer.length) buffer = new byte[nBytes];
412 if (nBytes > 0) {
413 in.readFully(buffer, 0, nBytes);
414 restoreSoftApConfiguration(buffer);
415 }
416 }
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000417 // network policies
418 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
419 nBytes = in.readInt();
420 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
421 if (nBytes > buffer.length) buffer = new byte[nBytes];
422 if (nBytes > 0) {
423 in.readFully(buffer, 0, nBytes);
424 restoreNetworkPolicies(buffer);
425 }
426 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700427 // Restore full wifi config data
428 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) {
429 nBytes = in.readInt();
430 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data");
431 if (nBytes > buffer.length) buffer = new byte[nBytes];
432 in.readFully(buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700433 restoreNewWifiConfigData(buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700434 }
435
Christopher Tate75a99702011-05-18 16:28:19 -0700436 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
437 } else {
438 data.close();
439 throw new IOException("Invalid file schema");
440 }
441 }
442
Amith Yamasanid1582142009-07-08 20:04:55 -0700443 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
444 long[] stateChecksums = new long[STATE_SIZE];
445
446 DataInputStream dataInput = new DataInputStream(
447 new FileInputStream(oldState.getFileDescriptor()));
Christopher Tatea286f412009-09-18 15:51:15 -0700448
449 try {
450 int stateVersion = dataInput.readInt();
Ritesh Reddy2400d272016-02-02 11:42:26 +0000451 if (stateVersion > STATE_VERSION) {
452 // Constrain the maximum state version this backup agent
453 // can handle in case a newer or corrupt backup set existed
454 stateVersion = STATE_VERSION;
455 }
Christopher Tate66488d62012-10-02 11:58:01 -0700456 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
457 stateChecksums[i] = dataInput.readLong();
Amith Yamasanid1582142009-07-08 20:04:55 -0700458 }
Christopher Tatea286f412009-09-18 15:51:15 -0700459 } catch (EOFException eof) {
460 // With the default 0 checksum we'll wind up forcing a backup of
461 // any unhandled data sets, which is appropriate.
Amith Yamasanid1582142009-07-08 20:04:55 -0700462 }
463 dataInput.close();
464 return stateChecksums;
465 }
466
467 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
468 throws IOException {
469 DataOutputStream dataOutput = new DataOutputStream(
Marvin Paul68795552014-12-16 14:12:33 -0800470 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
Christopher Tatea286f412009-09-18 15:51:15 -0700471
472 dataOutput.writeInt(STATE_VERSION);
Amith Yamasanid1582142009-07-08 20:04:55 -0700473 for (int i = 0; i < STATE_SIZE; i++) {
474 dataOutput.writeLong(checksums[i]);
475 }
476 dataOutput.close();
477 }
478
479 private long writeIfChanged(long oldChecksum, String key, byte[] data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000480 BackupDataOutput output) {
Amith Yamasanid1582142009-07-08 20:04:55 -0700481 CRC32 checkSummer = new CRC32();
482 checkSummer.update(data);
483 long newChecksum = checkSummer.getValue();
484 if (oldChecksum == newChecksum) {
485 return oldChecksum;
486 }
487 try {
Amith Yamasani072543f2015-02-13 11:09:45 -0800488 if (DEBUG_BACKUP) {
489 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
490 }
Amith Yamasanid1582142009-07-08 20:04:55 -0700491 output.writeEntityHeader(key, data.length);
492 output.writeEntityData(data, data.length);
493 } catch (IOException ioe) {
494 // Bail
495 }
496 return newChecksum;
497 }
498
Amith Yamasani220f4d62009-07-02 02:34:14 -0700499 private byte[] getSystemSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700500 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
501 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700502 try {
503 return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
504 } finally {
505 cursor.close();
506 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700507 }
508
509 private byte[] getSecureSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700510 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
511 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700512 try {
513 return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
514 } finally {
515 cursor.close();
516 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700517 }
518
Christopher Tate66488d62012-10-02 11:58:01 -0700519 private byte[] getGlobalSettings() {
520 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
521 null, null);
522 try {
523 return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
524 } finally {
525 cursor.close();
526 }
527 }
528
Amith Yamasani072543f2015-02-13 11:09:45 -0800529 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100530 * Serialize the owner info and other lock settings
Amith Yamasani072543f2015-02-13 11:09:45 -0800531 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100532 private byte[] getLockSettings(@UserIdInt int userId) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800533 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100534 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId);
535 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId);
536 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId);
537 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId);
538 final boolean powerButtonInstantlyLocks =
539 lockPatternUtils.getPowerButtonInstantlyLocks(userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800540
541 ByteArrayOutputStream baos = new ByteArrayOutputStream();
542 DataOutputStream out = new DataOutputStream(baos);
543 try {
544 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
545 out.writeUTF(ownerInfoEnabled ? "1" : "0");
546 if (ownerInfo != null) {
547 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
548 out.writeUTF(ownerInfo != null ? ownerInfo : "");
549 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100550 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) {
551 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED);
552 out.writeUTF(visiblePatternEnabled ? "1" : "0");
553 }
554 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) {
555 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS);
556 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0");
557 }
Amith Yamasani072543f2015-02-13 11:09:45 -0800558 // End marker
559 out.writeUTF("");
560 out.flush();
561 } catch (IOException ioe) {
562 }
563 return baos.toByteArray();
564 }
565
Christopher Tate66488d62012-10-02 11:58:01 -0700566 private void restoreSettings(BackupDataInput data, Uri contentUri,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000567 HashSet<String> movedToGlobal) {
Christopher Tate75a99702011-05-18 16:28:19 -0700568 byte[] settings = new byte[data.getDataSize()];
569 try {
570 data.readEntityData(settings, 0, settings.length);
571 } catch (IOException ioe) {
572 Log.e(TAG, "Couldn't read entity data");
573 return;
574 }
Christopher Tate66488d62012-10-02 11:58:01 -0700575 restoreSettings(settings, settings.length, contentUri, movedToGlobal);
Christopher Tate75a99702011-05-18 16:28:19 -0700576 }
577
Christopher Tate66488d62012-10-02 11:58:01 -0700578 private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000579 HashSet<String> movedToGlobal) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700580 if (DEBUG) {
581 Log.i(TAG, "restoreSettings: " + contentUri);
582 }
583
Christopher Tate1d0fca32017-06-06 13:30:00 -0700584 // Figure out the white list and redirects to the global table. We restore anything
585 // in either the backup whitelist or the legacy-restore whitelist for this table.
Christopher Tate6597e342015-02-17 12:15:25 -0800586 final String[] whitelist;
Michal Karpinskib52575c2018-01-19 17:38:45 +0000587 Map<String, Validator> validators = null;
Christopher Tate796e0f02009-09-22 11:57:58 -0700588 if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700589 whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP,
590 Settings.Secure.LEGACY_RESTORE_SETTINGS);
Michal Karpinskib52575c2018-01-19 17:38:45 +0000591 validators = Settings.Secure.VALIDATORS;
Christopher Tate796e0f02009-09-22 11:57:58 -0700592 } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700593 whitelist = concat(Settings.System.SETTINGS_TO_BACKUP,
594 Settings.System.LEGACY_RESTORE_SETTINGS);
Michal Karpinskib52575c2018-01-19 17:38:45 +0000595 validators = Settings.System.VALIDATORS;
Christopher Tate66488d62012-10-02 11:58:01 -0700596 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
Christopher Tate1d0fca32017-06-06 13:30:00 -0700597 whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP,
598 Settings.Global.LEGACY_RESTORE_SETTINGS);
Michal Karpinskib52575c2018-01-19 17:38:45 +0000599 validators = Settings.Global.VALIDATORS;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700600 } else {
601 throw new IllegalArgumentException("Unknown URI: " + contentUri);
Christopher Tate796e0f02009-09-22 11:57:58 -0700602 }
603
Svetoslav Ganova571a582011-09-20 18:32:20 -0700604 // Restore only the white list data.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700605 int pos = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700606 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700607 ContentValues contentValues = new ContentValues(2);
608 SettingsHelper settingsHelper = mSettingsHelper;
Christopher Tate6597e342015-02-17 12:15:25 -0800609 ContentResolver cr = getContentResolver();
Christopher Tate0738e882009-09-11 16:35:39 -0700610
Svetoslav Ganova571a582011-09-20 18:32:20 -0700611 final int whiteListSize = whitelist.length;
612 for (int i = 0; i < whiteListSize; i++) {
613 String key = whitelist[i];
Christopher Tate0738e882009-09-11 16:35:39 -0700614
Svet Ganovaabc9632017-07-28 19:37:15 -0700615 String value = null;
616 boolean hasValueToRestore = false;
617 if (cachedEntries.indexOfKey(key) >= 0) {
618 value = cachedEntries.remove(key);
619 hasValueToRestore = true;
620 } else {
621 // If the value not cached, let us look it up.
Svetoslav Ganova571a582011-09-20 18:32:20 -0700622 while (pos < bytes) {
623 int length = readInt(settings, pos);
624 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700625 String dataKey = length >= 0 ? new String(settings, pos, length) : null;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700626 pos += length;
627 length = readInt(settings, pos);
628 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700629 String dataValue = null;
630 if (length >= 0) {
631 dataValue = new String(settings, pos, length);
632 pos += length;
633 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700634 if (key.equals(dataKey)) {
635 value = dataValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700636 hasValueToRestore = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700637 break;
638 }
639 cachedEntries.put(dataKey, dataValue);
Amith Yamasani70c874b2009-07-06 14:53:25 -0700640 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700641 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700642
Svet Ganovaabc9632017-07-28 19:37:15 -0700643 if (!hasValueToRestore) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700644 continue;
645 }
Christopher Tate796e0f02009-09-22 11:57:58 -0700646
Michal Karpinskib52575c2018-01-19 17:38:45 +0000647 // only restore the settings that have valid values
648 if (!isValidSettingValue(key, value, validators)) {
649 Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass"
650 + " validation, value: " + value);
651 continue;
652 }
653
Christopher Tate3543beb2012-10-05 13:35:12 -0700654 final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
Christopher Tate66488d62012-10-02 11:58:01 -0700655 ? Settings.Global.CONTENT_URI
656 : contentUri;
Michal Karpinski6135a262017-08-11 10:45:58 +0100657 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
658 mRestoredFromSdkInt);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700659
Christopher Tated488bc02012-10-09 14:06:30 -0700660 if (DEBUG) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000661 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
Christopher Tate0738e882009-09-11 16:35:39 -0700662 }
663 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700664 }
665
Michal Karpinskib52575c2018-01-19 17:38:45 +0000666 private boolean isValidSettingValue(String key, String value,
667 Map<String, Validator> validators) {
668 if (key == null || validators == null) {
669 return false;
670 }
671 Validator validator = validators.get(key);
672 return (validator != null) && validator.validate(value);
673 }
674
Christopher Tate1d0fca32017-06-06 13:30:00 -0700675 private final String[] concat(String[] first, @Nullable String[] second) {
676 if (second == null || second.length == 0) {
677 return first;
678 }
679 final int firstLen = first.length;
680 final int secondLen = second.length;
681 String[] both = new String[firstLen + secondLen];
682 System.arraycopy(first, 0, both, 0, firstLen);
683 System.arraycopy(second, 0, both, firstLen, secondLen);
684 return both;
685 }
686
Amith Yamasani220f4d62009-07-02 02:34:14 -0700687 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100688 * Restores the owner info enabled and other settings in LockSettings.
Amith Yamasani072543f2015-02-13 11:09:45 -0800689 *
690 * @param buffer
691 * @param nBytes
692 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100693 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800694 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
695
696 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
697 DataInputStream in = new DataInputStream(bais);
698 try {
699 String key;
700 // Read until empty string marker
701 while ((key = in.readUTF()).length() > 0) {
702 final String value = in.readUTF();
703 if (DEBUG_BACKUP) {
704 Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
705 }
706 switch (key) {
707 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100708 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800709 break;
710 case KEY_LOCK_SETTINGS_OWNER_INFO:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100711 lockPatternUtils.setOwnerInfo(value, userId);
712 break;
713 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED:
714 lockPatternUtils.reportPatternWasChosen(userId);
715 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId);
716 break;
717 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
718 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800719 break;
720 }
721 }
722 in.close();
723 } catch (IOException ioe) {
724 }
725 }
726
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100727 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800728 final byte[] settings = new byte[data.getDataSize()];
729 try {
730 data.readEntityData(settings, 0, settings.length);
731 } catch (IOException ioe) {
732 Log.e(TAG, "Couldn't read entity data");
733 return;
734 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100735 restoreLockSettings(userId, settings, settings.length);
Amith Yamasani072543f2015-02-13 11:09:45 -0800736 }
737
738 /**
Svetoslav Ganova571a582011-09-20 18:32:20 -0700739 * Given a cursor and a set of keys, extract the required keys and
740 * values and write them to a byte array.
741 *
742 * @param cursor A cursor with settings data.
743 * @param settings The settings to extract.
744 * @return The byte array of extracted values.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700745 */
Svetoslav Ganova571a582011-09-20 18:32:20 -0700746 private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700747 if (!cursor.moveToFirst()) {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700748 Log.e(TAG, "Couldn't read from the cursor");
749 return new byte[0];
750 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700751
Svet Ganovaabc9632017-07-28 19:37:15 -0700752 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
753 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
754
Svetoslav Ganova571a582011-09-20 18:32:20 -0700755 // Obtain the relevant data in a temporary array.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700756 int totalSize = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700757 int backedUpSettingIndex = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700758 final int settingsCount = settings.length;
759 final byte[][] values = new byte[settingsCount * 2][]; // keys and values
760 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700761 for (int i = 0; i < settingsCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700762 final String key = settings[i];
Svetoslav683914b2015-01-15 14:22:26 -0800763
Svetoslav Ganova571a582011-09-20 18:32:20 -0700764 // If the value not cached, let us look it up.
Svet Ganovaabc9632017-07-28 19:37:15 -0700765 String value = null;
766 boolean hasValueToBackup = false;
767 if (cachedEntries.indexOfKey(key) >= 0) {
768 value = cachedEntries.remove(key);
769 hasValueToBackup = true;
770 } else {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700771 while (!cursor.isAfterLast()) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700772 final String cursorKey = cursor.getString(nameColumnIndex);
773 final String cursorValue = cursor.getString(valueColumnIndex);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700774 cursor.moveToNext();
775 if (key.equals(cursorKey)) {
776 value = cursorValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700777 hasValueToBackup = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700778 break;
779 }
780 cachedEntries.put(cursorKey, cursorValue);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700781 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700782 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700783
Svet Ganovaabc9632017-07-28 19:37:15 -0700784 if (!hasValueToBackup) {
785 continue;
786 }
787
Amith Yamasani622bf2222013-09-06 13:54:28 -0700788 // Intercept the keys and see if they need special handling
789 value = mSettingsHelper.onBackupValue(key, value);
790
Svetoslav Ganova571a582011-09-20 18:32:20 -0700791 // Write the key and value in the intermediary array.
Svet Ganovaabc9632017-07-28 19:37:15 -0700792 final byte[] keyBytes = key.getBytes();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700793 totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
794 values[backedUpSettingIndex * 2] = keyBytes;
795
Svet Ganovaabc9632017-07-28 19:37:15 -0700796 final byte[] valueBytes = (value != null) ? value.getBytes() : NULL_VALUE;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700797 totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
798 values[backedUpSettingIndex * 2 + 1] = valueBytes;
799
800 backedUpSettingIndex++;
801
802 if (DEBUG) {
803 Log.d(TAG, "Backed up setting: " + key + "=" + value);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700804 }
805 }
806
Svetoslav Ganova571a582011-09-20 18:32:20 -0700807 // Aggregate the result.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700808 byte[] result = new byte[totalSize];
809 int pos = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700810 final int keyValuePairCount = backedUpSettingIndex * 2;
811 for (int i = 0; i < keyValuePairCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700812 final byte[] value = values[i];
813 if (value != NULL_VALUE) {
814 pos = writeInt(result, pos, value.length);
815 pos = writeBytes(result, pos, value);
816 } else {
817 pos = writeInt(result, pos, NULL_SIZE);
818 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700819 }
820 return result;
821 }
822
Roshan Pius5db739c2016-06-17 16:51:36 -0700823 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700824 if (DEBUG_BACKUP) {
825 Log.v(TAG, "Applying restored supplicant wifi data");
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800826 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700827 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes);
Amith Yamasani2cfab842009-09-09 18:27:31 -0700828 }
829
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000830 private byte[] getSoftAPConfiguration() {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000831 try {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700832 return mWifiManager.getWifiApConfiguration().getBytesForBackup();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000833 } catch (IOException ioe) {
834 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
835 return new byte[0];
836 }
837 }
838
839 private void restoreSoftApConfiguration(byte[] data) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000840 try {
841 WifiConfiguration config = WifiConfiguration
842 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
843 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700844 int originalApBand = config.apBand;
Roshan Pius7a2491f2016-06-02 09:22:55 -0700845 mWifiManager.setWifiApConfiguration(config);
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700846
847 // Depending on device hardware, we may need to notify the user of a setting change for
848 // the apBand preference
849 boolean dualMode = mWifiManager.isDualModeSupported();
850 int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
851 if (dualMode) {
852 if (storedApBand != originalApBand) {
853 Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
854 mWifiManager.notifyUserOfApBandConversion();
855 }
856 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000857 } catch (IOException | BackupUtils.BadVersionException e) {
858 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
859 }
860 }
861
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000862 private byte[] getNetworkPolicies() {
863 NetworkPolicyManager networkPolicyManager =
864 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
865 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
866 ByteArrayOutputStream baos = new ByteArrayOutputStream();
867 if (policies != null && policies.length != 0) {
868 DataOutputStream out = new DataOutputStream(baos);
869 try {
870 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
871 out.writeInt(policies.length);
872 for (NetworkPolicy policy : policies) {
Jeff Sharkey55a3fe72018-02-24 19:09:20 -0700873 // We purposefully only backup policies that the user has
874 // defined; any inferred policies might include
875 // carrier-protected data that we can't export.
876 if (policy != null && !policy.inferred) {
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000877 byte[] marshaledPolicy = policy.getBytesForBackup();
878 out.writeByte(BackupUtils.NOT_NULL);
879 out.writeInt(marshaledPolicy.length);
880 out.write(marshaledPolicy);
881 } else {
882 out.writeByte(BackupUtils.NULL);
883 }
884 }
885 } catch (IOException ioe) {
886 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
887 baos.reset();
888 }
889 }
890 return baos.toByteArray();
891 }
892
Roshan Pius7a2491f2016-06-02 09:22:55 -0700893 private byte[] getNewWifiConfigData() {
894 return mWifiManager.retrieveBackupData();
895 }
896
Roshan Pius5db739c2016-06-17 16:51:36 -0700897 private void restoreNewWifiConfigData(byte[] bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700898 if (DEBUG_BACKUP) {
899 Log.v(TAG, "Applying restored wifi data");
900 }
901 mWifiManager.restoreBackupData(bytes);
902 }
903
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000904 private void restoreNetworkPolicies(byte[] data) {
905 NetworkPolicyManager networkPolicyManager =
906 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
907 if (data != null && data.length != 0) {
908 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
909 try {
910 int version = in.readInt();
911 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
912 throw new BackupUtils.BadVersionException(
913 "Unknown Backup Serialization Version");
914 }
915 int length = in.readInt();
916 NetworkPolicy[] policies = new NetworkPolicy[length];
917 for (int i = 0; i < length; i++) {
918 byte isNull = in.readByte();
919 if (isNull == BackupUtils.NULL) continue;
920 int byteLength = in.readInt();
921 byte[] policyData = new byte[byteLength];
922 in.read(policyData, 0, byteLength);
923 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
924 new DataInputStream(new ByteArrayInputStream(policyData)));
925 }
926 // Only set the policies if there was no error in the restore operation
927 networkPolicyManager.setNetworkPolicies(policies);
Annie Meng47f5c9c2018-02-27 14:48:21 +0000928 } catch (NullPointerException | IOException | BackupUtils.BadVersionException
929 | DateTimeException e) {
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000930 // NPE can be thrown when trying to instantiate a NetworkPolicy
931 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
932 }
933 }
934 }
935
Amith Yamasani220f4d62009-07-02 02:34:14 -0700936 /**
937 * Write an int in BigEndian into the byte array.
938 * @param out byte array
939 * @param pos current pos in array
940 * @param value integer to write
Svetoslav Ganova571a582011-09-20 18:32:20 -0700941 * @return the index after adding the size of an int (4) in bytes.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700942 */
943 private int writeInt(byte[] out, int pos, int value) {
944 out[pos + 0] = (byte) ((value >> 24) & 0xFF);
945 out[pos + 1] = (byte) ((value >> 16) & 0xFF);
946 out[pos + 2] = (byte) ((value >> 8) & 0xFF);
947 out[pos + 3] = (byte) ((value >> 0) & 0xFF);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700948 return pos + INTEGER_BYTE_COUNT;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700949 }
950
951 private int writeBytes(byte[] out, int pos, byte[] value) {
952 System.arraycopy(value, 0, out, pos, value.length);
953 return pos + value.length;
954 }
955
956 private int readInt(byte[] in, int pos) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000957 int result = ((in[pos] & 0xFF) << 24)
958 | ((in[pos + 1] & 0xFF) << 16)
959 | ((in[pos + 2] & 0xFF) << 8)
960 | ((in[pos + 3] & 0xFF) << 0);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700961 return result;
962 }
Paul Stewart45e6fec2016-05-20 08:14:30 -0700963}