blob: 443288cfe4925b5f9839bc660a973be15327cb4d [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
Bryan Mawhinneye483b562017-05-15 14:46:05 +010019import android.annotation.UserIdInt;
Svetoslav Ganova571a582011-09-20 18:32:20 -070020import android.app.backup.BackupAgentHelper;
21import android.app.backup.BackupDataInput;
22import android.app.backup.BackupDataOutput;
23import android.app.backup.FullBackupDataOutput;
Christopher Tate87bc7e72013-06-10 16:55:02 -070024import android.content.ContentResolver;
Svetoslav Ganova571a582011-09-20 18:32:20 -070025import android.content.ContentValues;
26import android.content.Context;
27import android.database.Cursor;
Ritesh Reddyadca34a2016-02-04 18:33:30 +000028import android.net.NetworkPolicy;
29import android.net.NetworkPolicyManager;
Svetoslav Ganova571a582011-09-20 18:32:20 -070030import android.net.Uri;
Christopher Tatecab915a2015-01-08 12:50:00 -080031import android.net.wifi.WifiConfiguration;
Svetoslav Ganova571a582011-09-20 18:32:20 -070032import android.net.wifi.WifiManager;
Michal Karpinski6517d882018-01-08 15:23:03 +000033import android.os.Build;
Svetoslav Ganova571a582011-09-20 18:32:20 -070034import android.os.ParcelFileDescriptor;
Amith Yamasani072543f2015-02-13 11:09:45 -080035import android.os.UserHandle;
Svetoslav Ganova571a582011-09-20 18:32:20 -070036import android.provider.Settings;
Al Sutton66a3e012019-10-15 15:34:13 +010037import android.provider.settings.backup.DeviceSpecificSettings;
Al Sutton0833b2e2019-08-22 16:21:30 +010038import android.provider.settings.backup.GlobalSettings;
39import android.provider.settings.backup.SecureSettings;
40import android.provider.settings.backup.SystemSettings;
Al Sutton91f89d02019-08-16 12:56:57 +010041import android.provider.settings.validators.GlobalSettingsValidators;
42import android.provider.settings.validators.SecureSettingsValidators;
43import android.provider.settings.validators.SystemSettingsValidators;
Al Suttonb0067fb2019-08-16 10:34:46 +010044import android.provider.settings.validators.Validator;
Svet Ganovaabc9632017-07-28 19:37:15 -070045import android.util.ArrayMap;
Michal Karpinski6517d882018-01-08 15:23:03 +000046import android.util.ArraySet;
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000047import android.util.BackupUtils;
Svetoslav Ganova571a582011-09-20 18:32:20 -070048import android.util.Log;
Al Sutton71dc8ff2019-07-12 11:42:03 +010049import android.util.Slog;
50import android.view.Display;
Svetoslav Ganova571a582011-09-20 18:32:20 -070051
Al Sutton71dc8ff2019-07-12 11:42:03 +010052import com.android.internal.annotations.VisibleForTesting;
Al Sutton81be1552019-07-17 11:19:13 +010053import com.android.internal.util.ArrayUtils;
Amith Yamasani072543f2015-02-13 11:09:45 -080054import com.android.internal.widget.LockPatternUtils;
Al Suttone5e79162019-08-19 13:42:16 +010055import com.android.settingslib.display.DisplayDensityConfiguration;
Amith Yamasani072543f2015-02-13 11:09:45 -080056
Brad Fitzpatrick70787892010-11-17 11:31:12 -080057import java.io.BufferedOutputStream;
Amith Yamasani072543f2015-02-13 11:09:45 -080058import java.io.ByteArrayInputStream;
Christopher Tatecab915a2015-01-08 12:50:00 -080059import java.io.ByteArrayOutputStream;
Amith Yamasanid1582142009-07-08 20:04:55 -070060import java.io.DataInputStream;
61import java.io.DataOutputStream;
Amith Yamasani2cfab842009-09-09 18:27:31 -070062import java.io.EOFException;
Amith Yamasani220f4d62009-07-02 02:34:14 -070063import java.io.FileInputStream;
64import java.io.FileOutputStream;
65import java.io.IOException;
Al Sutton71dc8ff2019-07-12 11:42:03 +010066import java.io.OutputStream;
Annie Meng47f5c9c2018-02-27 14:48:21 +000067import java.time.DateTimeException;
Michal Karpinski6517d882018-01-08 15:23:03 +000068import java.util.Arrays;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070069import java.util.HashSet;
Svetoslav Ganova571a582011-09-20 18:32:20 -070070import java.util.Map;
Al Sutton71dc8ff2019-07-12 11:42:03 +010071import java.util.Objects;
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +010072import java.util.Set;
Al Sutton71dc8ff2019-07-12 11:42:03 +010073import java.util.concurrent.atomic.AtomicInteger;
Amith Yamasanid1582142009-07-08 20:04:55 -070074import java.util.zip.CRC32;
Amith Yamasani220f4d62009-07-02 02:34:14 -070075
Amith Yamasani220f4d62009-07-02 02:34:14 -070076/**
77 * Performs backup and restore of the System and Secure settings.
78 * List of settings that are backed up are stored in the Settings.java file
79 */
Christopher Tatecc84c692010-03-29 14:54:02 -070080public class SettingsBackupAgent extends BackupAgentHelper {
Christopher Tate436344a2009-09-30 16:17:37 -070081 private static final boolean DEBUG = false;
Christopher Tate8dfe2b92012-05-15 15:05:04 -070082 private static final boolean DEBUG_BACKUP = DEBUG || false;
Amith Yamasani220f4d62009-07-02 02:34:14 -070083
Svet Ganovaabc9632017-07-28 19:37:15 -070084 private static final byte[] NULL_VALUE = new byte[0];
85 private static final int NULL_SIZE = -1;
86
Amith Yamasani220f4d62009-07-02 02:34:14 -070087 private static final String KEY_SYSTEM = "system";
88 private static final String KEY_SECURE = "secure";
Christopher Tate66488d62012-10-02 11:58:01 -070089 private static final String KEY_GLOBAL = "global";
Amith Yamasani8823c0a82009-07-07 14:30:17 -070090 private static final String KEY_LOCALE = "locale";
Amith Yamasani072543f2015-02-13 11:09:45 -080091 private static final String KEY_LOCK_SETTINGS = "lock_settings";
Ritesh Reddyaeb4c062016-01-26 19:40:48 +000092 private static final String KEY_SOFTAP_CONFIG = "softap_config";
Ritesh Reddyadca34a2016-02-04 18:33:30 +000093 private static final String KEY_NETWORK_POLICIES = "network_policies";
Roshan Pius7a2491f2016-06-02 09:22:55 -070094 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config";
Al Sutton71dc8ff2019-07-12 11:42:03 +010095 private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config";
Amith Yamasani220f4d62009-07-02 02:34:14 -070096
Christopher Tatea286f412009-09-18 15:51:15 -070097 // Versioning of the state file. Increment this version
98 // number any time the set of state items is altered.
Al Sutton71dc8ff2019-07-12 11:42:03 +010099 private static final int STATE_VERSION = 8;
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000100
101 // Versioning of the Network Policies backup payload.
102 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
103
Christopher Tatea286f412009-09-18 15:51:15 -0700104
Christopher Tate66488d62012-10-02 11:58:01 -0700105 // Slots in the checksum array. Never insert new items in the middle
106 // of this array; new slots must be appended.
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000107 private static final int STATE_SYSTEM = 0;
108 private static final int STATE_SECURE = 1;
109 private static final int STATE_LOCALE = 2;
110 private static final int STATE_WIFI_SUPPLICANT = 3;
111 private static final int STATE_WIFI_CONFIG = 4;
112 private static final int STATE_GLOBAL = 5;
113 private static final int STATE_LOCK_SETTINGS = 6;
114 private static final int STATE_SOFTAP_CONFIG = 7;
115 private static final int STATE_NETWORK_POLICIES = 8;
Roshan Pius7a2491f2016-06-02 09:22:55 -0700116 private static final int STATE_WIFI_NEW_CONFIG = 9;
Al Sutton71dc8ff2019-07-12 11:42:03 +0100117 private static final int STATE_DEVICE_CONFIG = 10;
Christopher Tate66488d62012-10-02 11:58:01 -0700118
Al Sutton71dc8ff2019-07-12 11:42:03 +0100119 private static final int STATE_SIZE = 11; // The current number of state items
Christopher Tate66488d62012-10-02 11:58:01 -0700120
121 // Number of entries in the checksum array at various version numbers
122 private static final int STATE_SIZES[] = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000123 0,
124 4, // version 1
125 5, // version 2 added STATE_WIFI_CONFIG
126 6, // version 3 added STATE_GLOBAL
127 7, // version 4 added STATE_LOCK_SETTINGS
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000128 8, // version 5 added STATE_SOFTAP_CONFIG
Roshan Pius7a2491f2016-06-02 09:22:55 -0700129 9, // version 6 added STATE_NETWORK_POLICIES
Al Sutton71dc8ff2019-07-12 11:42:03 +0100130 10, // version 7 added STATE_WIFI_NEW_CONFIG
131 STATE_SIZE // version 8 added STATE_DEVICE_CONFIG
Christopher Tate66488d62012-10-02 11:58:01 -0700132 };
Amith Yamasanid1582142009-07-08 20:04:55 -0700133
Christopher Tate66488d62012-10-02 11:58:01 -0700134 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry
Amith Yamasani072543f2015-02-13 11:09:45 -0800135 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000136 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000137 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
Roshan Pius7a2491f2016-06-02 09:22:55 -0700138 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry
Al Sutton71dc8ff2019-07-12 11:42:03 +0100139 private static final int FULL_BACKUP_ADDED_DEVICE_SPECIFIC = 7; // added "device specific" entry
140 // Versioning of the 'full backup' format
141 // Increment this version any time a new item is added
142 private static final int FULL_BACKUP_VERSION = FULL_BACKUP_ADDED_DEVICE_SPECIFIC;
Christopher Tate75a99702011-05-18 16:28:19 -0700143
Svetoslav Ganova571a582011-09-20 18:32:20 -0700144 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700145
146 private static final byte[] EMPTY_DATA = new byte[0];
147
148 private static final String TAG = "SettingsBackupAgent";
149
Al Sutton71dc8ff2019-07-12 11:42:03 +0100150 @VisibleForTesting
151 static final String[] PROJECTION = {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000152 Settings.NameValueTable.NAME,
153 Settings.NameValueTable.VALUE
Amith Yamasani220f4d62009-07-02 02:34:14 -0700154 };
155
Al Sutton71dc8ff2019-07-12 11:42:03 +0100156 // Versioning of the 'device specific' section of a backup
157 // Increment this any time the format is changed or data added.
158 @VisibleForTesting
159 static final int DEVICE_SPECIFIC_VERSION = 1;
160
Christian Sonntag92c17522009-08-07 15:16:17 -0700161 // the key to store the WIFI data under, should be sorted as last, so restore happens last.
162 // use very late unicode character to quasi-guarantee last sort position.
Amith Yamasani2cfab842009-09-09 18:27:31 -0700163 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800164 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
Amith Yamasani220f4d62009-07-02 02:34:14 -0700165
Amith Yamasani072543f2015-02-13 11:09:45 -0800166 // Keys within the lock settings section
167 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
168 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100169 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED =
170 "visible_pattern_enabled";
171 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS =
172 "power_button_instantly_locks";
Amith Yamasani072543f2015-02-13 11:09:45 -0800173
Christopher Tate4a627c72011-04-01 14:43:32 -0700174 // Name of the temporary file we use during full backup/restore. This is
175 // stored in the full-backup tarfile as well, so should not be changed.
176 private static final String STAGE_FILE = "flattened-data";
177
Michal Karpinski6517d882018-01-08 15:23:03 +0000178 // List of keys that support restore to lower version of the SDK, introduced in Android P
179 private static final ArraySet<String> RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS =
180 new ArraySet<String>(Arrays.asList(new String[] {
181 KEY_NETWORK_POLICIES,
182 KEY_WIFI_NEW_CONFIG,
Michal Karpinskib52575c2018-01-19 17:38:45 +0000183 KEY_SYSTEM,
184 KEY_SECURE,
185 KEY_GLOBAL,
Michal Karpinski6517d882018-01-08 15:23:03 +0000186 }));
187
Al Sutton71dc8ff2019-07-12 11:42:03 +0100188 @VisibleForTesting
189 SettingsHelper mSettingsHelper;
Amith Yamasani220f4d62009-07-02 02:34:14 -0700190
Roshan Pius7a2491f2016-06-02 09:22:55 -0700191 private WifiManager mWifiManager;
Christopher Tate8dfe2b92012-05-15 15:05:04 -0700192
Michal Karpinski6135a262017-08-11 10:45:58 +0100193 // Version of the SDK that com.android.providers.settings package has been restored from.
194 // Populated in onRestore().
195 private int mRestoredFromSdkInt;
196
Svetoslav Ganova571a582011-09-20 18:32:20 -0700197 @Override
Amith Yamasani220f4d62009-07-02 02:34:14 -0700198 public void onCreate() {
Christopher Tate75a99702011-05-18 16:28:19 -0700199 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
200
Amith Yamasani220f4d62009-07-02 02:34:14 -0700201 mSettingsHelper = new SettingsHelper(this);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700202 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700203 super.onCreate();
204 }
205
206 @Override
207 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000208 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700209
210 byte[] systemSettingsData = getSystemSettings();
211 byte[] secureSettingsData = getSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700212 byte[] globalSettingsData = getGlobalSettings();
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100213 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId());
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700214 byte[] locale = mSettingsHelper.getLocaleData();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000215 byte[] softApConfigData = getSoftAPConfiguration();
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000216 byte[] netPoliciesData = getNetworkPolicies();
Roshan Pius7a2491f2016-06-02 09:22:55 -0700217 byte[] wifiFullConfigData = getNewWifiConfigData();
Al Sutton71dc8ff2019-07-12 11:42:03 +0100218 byte[] deviceSpecificInformation = getDeviceSpecificConfiguration();
Amith Yamasani220f4d62009-07-02 02:34:14 -0700219
Christopher Tate79ec80d2011-06-24 14:58:49 -0700220 long[] stateChecksums = readOldChecksums(oldState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700221
Christopher Tate79ec80d2011-06-24 14:58:49 -0700222 stateChecksums[STATE_SYSTEM] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000223 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700224 stateChecksums[STATE_SECURE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000225 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
Christopher Tate66488d62012-10-02 11:58:01 -0700226 stateChecksums[STATE_GLOBAL] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000227 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
Christopher Tate79ec80d2011-06-24 14:58:49 -0700228 stateChecksums[STATE_LOCALE] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000229 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700230 stateChecksums[STATE_WIFI_SUPPLICANT] = 0;
231 stateChecksums[STATE_WIFI_CONFIG] = 0;
Amith Yamasani072543f2015-02-13 11:09:45 -0800232 stateChecksums[STATE_LOCK_SETTINGS] =
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000233 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
234 lockSettingsData, data);
235 stateChecksums[STATE_SOFTAP_CONFIG] =
236 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
237 softApConfigData, data);
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000238 stateChecksums[STATE_NETWORK_POLICIES] =
239 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
240 netPoliciesData, data);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700241 stateChecksums[STATE_WIFI_NEW_CONFIG] =
242 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG,
243 wifiFullConfigData, data);
Al Sutton71dc8ff2019-07-12 11:42:03 +0100244 stateChecksums[STATE_DEVICE_CONFIG] =
245 writeIfChanged(stateChecksums[STATE_DEVICE_CONFIG], KEY_DEVICE_SPECIFIC_CONFIG,
246 deviceSpecificInformation, data);
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700247
Christopher Tate79ec80d2011-06-24 14:58:49 -0700248 writeNewChecksums(stateChecksums, newState);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700249 }
250
251 @Override
252 public void onRestore(BackupDataInput data, int appVersionCode,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000253 ParcelFileDescriptor newState) throws IOException {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700254
Michal Karpinski6517d882018-01-08 15:23:03 +0000255 if (DEBUG) {
256 Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode
257 + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT);
258 }
Michal Karpinskib52575c2018-01-19 17:38:45 +0000259
260 boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(),
261 Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1;
262 if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) {
263 Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API"
264 + Build.VERSION.SDK_INT + " due to settings flag override.");
265 return;
266 }
267
Michal Karpinski6135a262017-08-11 10:45:58 +0100268 // versionCode of com.android.providers.settings corresponds to SDK_INT
269 mRestoredFromSdkInt = appVersionCode;
270
Christopher Tate66488d62012-10-02 11:58:01 -0700271 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800272 Settings.System.getMovedToGlobalSettings(movedToGlobal);
273 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100274 Set<String> movedToSecure = getMovedToSecureSettings();
275
Roshan Pius7a2491f2016-06-02 09:22:55 -0700276 byte[] restoredWifiSupplicantData = null;
277 byte[] restoredWifiIpConfigData = null;
Christopher Tate66488d62012-10-02 11:58:01 -0700278
Amith Yamasani220f4d62009-07-02 02:34:14 -0700279 while (data.readNextHeader()) {
280 final String key = data.getKey();
Amith Yamasani8823c0a82009-07-07 14:30:17 -0700281 final int size = data.getDataSize();
Michal Karpinski6517d882018-01-08 15:23:03 +0000282
283 // bail out of restoring from higher SDK_INT version for unsupported keys
284 if (appVersionCode > Build.VERSION.SDK_INT
285 && !RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS.contains(key)) {
286 Log.w(TAG, "Not restoring unrecognized key '"
287 + key + "' from future version " + appVersionCode);
Anton Philippov54c6d6c2018-04-10 22:52:28 +0100288 data.skipEntityData();
Michal Karpinski6517d882018-01-08 15:23:03 +0000289 continue;
290 }
291
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000292 switch (key) {
293 case KEY_SYSTEM :
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100294 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
295 movedToSecure);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000296 mSettingsHelper.applyAudioSettings();
297 break;
298
299 case KEY_SECURE :
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100300 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, null);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000301 break;
302
303 case KEY_GLOBAL :
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100304 restoreSettings(data, Settings.Global.CONTENT_URI, null, movedToSecure);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000305 break;
306
307 case KEY_WIFI_SUPPLICANT :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700308 restoredWifiSupplicantData = new byte[size];
309 data.readEntityData(restoredWifiSupplicantData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000310 break;
311
312 case KEY_LOCALE :
313 byte[] localeData = new byte[size];
314 data.readEntityData(localeData, 0, size);
315 mSettingsHelper.setLocaleData(localeData, size);
316 break;
317
318 case KEY_WIFI_CONFIG :
Roshan Pius7a2491f2016-06-02 09:22:55 -0700319 restoredWifiIpConfigData = new byte[size];
320 data.readEntityData(restoredWifiIpConfigData, 0, size);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000321 break;
322
323 case KEY_LOCK_SETTINGS :
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100324 restoreLockSettings(UserHandle.myUserId(), data);
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000325 break;
326
327 case KEY_SOFTAP_CONFIG :
328 byte[] softapData = new byte[size];
329 data.readEntityData(softapData, 0, size);
330 restoreSoftApConfiguration(softapData);
331 break;
332
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000333 case KEY_NETWORK_POLICIES:
334 byte[] netPoliciesData = new byte[size];
335 data.readEntityData(netPoliciesData, 0, size);
336 restoreNetworkPolicies(netPoliciesData);
337 break;
338
Roshan Pius7a2491f2016-06-02 09:22:55 -0700339 case KEY_WIFI_NEW_CONFIG:
340 byte[] restoredWifiNewConfigData = new byte[size];
341 data.readEntityData(restoredWifiNewConfigData, 0, size);
Roshan Pius5db739c2016-06-17 16:51:36 -0700342 restoreNewWifiConfigData(restoredWifiNewConfigData);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700343 break;
344
Al Sutton71dc8ff2019-07-12 11:42:03 +0100345 case KEY_DEVICE_SPECIFIC_CONFIG:
346 byte[] restoredDeviceSpecificConfig = new byte[size];
347 data.readEntityData(restoredDeviceSpecificConfig, 0, size);
348 restoreDeviceSpecificConfig(restoredDeviceSpecificConfig);
349 break;
350
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000351 default :
352 data.skipEntityData();
353
Amith Yamasani220f4d62009-07-02 02:34:14 -0700354 }
355 }
Christopher Tated488bc02012-10-09 14:06:30 -0700356
Roshan Pius7a2491f2016-06-02 09:22:55 -0700357 // Do this at the end so that we also pull in the ipconfig data.
358 if (restoredWifiSupplicantData != null) {
359 restoreSupplicantWifiConfigData(
Roshan Pius5db739c2016-06-17 16:51:36 -0700360 restoredWifiSupplicantData, restoredWifiIpConfigData);
Christopher Tated488bc02012-10-09 14:06:30 -0700361 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700362 }
363
Christopher Tate75a99702011-05-18 16:28:19 -0700364 @Override
Christopher Tate79ec80d2011-06-24 14:58:49 -0700365 public void onFullBackup(FullBackupDataOutput data) throws IOException {
Michal Karpinskifbcb24582018-01-09 17:06:19 +0000366 // Full backup of SettingsBackupAgent support was removed in Android P. If you want to adb
367 // backup com.android.providers.settings package use \"-keyvalue\" flag.
368 // Full restore of SettingsBackupAgent is still available for backwards compatibility.
Christopher Tate79ec80d2011-06-24 14:58:49 -0700369 }
370
371 @Override
Christopher Tate75a99702011-05-18 16:28:19 -0700372 public void onRestoreFile(ParcelFileDescriptor data, long size,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000373 int type, String domain, String relpath, long mode, long mtime)
Christopher Tate75a99702011-05-18 16:28:19 -0700374 throws IOException {
375 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
376 // Our data is actually a blob of flattened settings data identical to that
377 // produced during incremental backups. Just unpack and apply it all in
378 // turn.
379 FileInputStream instream = new FileInputStream(data.getFileDescriptor());
380 DataInputStream in = new DataInputStream(instream);
381
382 int version = in.readInt();
383 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
Christopher Tate66488d62012-10-02 11:58:01 -0700384 if (version <= FULL_BACKUP_VERSION) {
385 // Generate the moved-to-global lookup table
386 HashSet<String> movedToGlobal = new HashSet<String>();
Svetoslav683914b2015-01-15 14:22:26 -0800387 Settings.System.getMovedToGlobalSettings(movedToGlobal);
388 Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100389 Set<String> movedToSecure = getMovedToSecureSettings();
Christopher Tate66488d62012-10-02 11:58:01 -0700390
Christopher Tate75a99702011-05-18 16:28:19 -0700391 // system settings data first
392 int nBytes = in.readInt();
393 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
394 byte[] buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700395 in.readFully(buffer, 0, nBytes);
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100396 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
397 movedToSecure);
Christopher Tate75a99702011-05-18 16:28:19 -0700398
399 // secure settings
400 nBytes = in.readInt();
401 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
402 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700403 in.readFully(buffer, 0, nBytes);
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100404 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, null);
Christopher Tate66488d62012-10-02 11:58:01 -0700405
406 // Global only if sufficiently new
407 if (version >= FULL_BACKUP_ADDED_GLOBAL) {
408 nBytes = in.readInt();
409 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
410 if (nBytes > buffer.length) buffer = new byte[nBytes];
411 in.readFully(buffer, 0, nBytes);
412 movedToGlobal.clear(); // no redirection; this *is* the global namespace
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100413 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
414 movedToSecure);
Christopher Tate66488d62012-10-02 11:58:01 -0700415 }
Christopher Tate75a99702011-05-18 16:28:19 -0700416
417 // locale
418 nBytes = in.readInt();
419 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
420 if (nBytes > buffer.length) buffer = new byte[nBytes];
Christopher Tate2efd2db2011-07-19 16:32:49 -0700421 in.readFully(buffer, 0, nBytes);
Christopher Tate75a99702011-05-18 16:28:19 -0700422 mSettingsHelper.setLocaleData(buffer, nBytes);
423
Roshan Pius7a2491f2016-06-02 09:22:55 -0700424 // Restore older backups performing the necessary migrations.
425 if (version < FULL_BACKUP_ADDED_WIFI_NEW) {
426 // wifi supplicant
427 int supplicant_size = in.readInt();
428 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data");
429 byte[] supplicant_buffer = new byte[supplicant_size];
430 in.readFully(supplicant_buffer, 0, supplicant_size);
Christopher Tate75a99702011-05-18 16:28:19 -0700431
Roshan Pius7a2491f2016-06-02 09:22:55 -0700432 // ip config
433 int ipconfig_size = in.readInt();
434 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data");
435 byte[] ipconfig_buffer = new byte[ipconfig_size];
436 in.readFully(ipconfig_buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700437 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700438 }
Christopher Tate75a99702011-05-18 16:28:19 -0700439
Amith Yamasani072543f2015-02-13 11:09:45 -0800440 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
441 nBytes = in.readInt();
442 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
443 if (nBytes > buffer.length) buffer = new byte[nBytes];
444 if (nBytes > 0) {
445 in.readFully(buffer, 0, nBytes);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100446 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes);
Amith Yamasani072543f2015-02-13 11:09:45 -0800447 }
448 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000449 // softap config
450 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
451 nBytes = in.readInt();
452 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
453 if (nBytes > buffer.length) buffer = new byte[nBytes];
454 if (nBytes > 0) {
455 in.readFully(buffer, 0, nBytes);
456 restoreSoftApConfiguration(buffer);
457 }
458 }
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000459 // network policies
460 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
461 nBytes = in.readInt();
462 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
463 if (nBytes > buffer.length) buffer = new byte[nBytes];
464 if (nBytes > 0) {
465 in.readFully(buffer, 0, nBytes);
466 restoreNetworkPolicies(buffer);
467 }
468 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700469 // Restore full wifi config data
470 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) {
471 nBytes = in.readInt();
472 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data");
473 if (nBytes > buffer.length) buffer = new byte[nBytes];
474 in.readFully(buffer, 0, nBytes);
Roshan Pius5db739c2016-06-17 16:51:36 -0700475 restoreNewWifiConfigData(buffer);
Roshan Pius7a2491f2016-06-02 09:22:55 -0700476 }
477
Christopher Tate75a99702011-05-18 16:28:19 -0700478 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
479 } else {
480 data.close();
481 throw new IOException("Invalid file schema");
482 }
483 }
484
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100485 private Set<String> getMovedToSecureSettings() {
486 Set<String> movedToSecureSettings = new HashSet<>();
487 Settings.Global.getMovedToSecureSettings(movedToSecureSettings);
488 Settings.System.getMovedToSecureSettings(movedToSecureSettings);
489 return movedToSecureSettings;
490 }
491
Amith Yamasanid1582142009-07-08 20:04:55 -0700492 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
493 long[] stateChecksums = new long[STATE_SIZE];
494
495 DataInputStream dataInput = new DataInputStream(
496 new FileInputStream(oldState.getFileDescriptor()));
Christopher Tatea286f412009-09-18 15:51:15 -0700497
498 try {
499 int stateVersion = dataInput.readInt();
Ritesh Reddy2400d272016-02-02 11:42:26 +0000500 if (stateVersion > STATE_VERSION) {
501 // Constrain the maximum state version this backup agent
502 // can handle in case a newer or corrupt backup set existed
503 stateVersion = STATE_VERSION;
504 }
Christopher Tate66488d62012-10-02 11:58:01 -0700505 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
506 stateChecksums[i] = dataInput.readLong();
Amith Yamasanid1582142009-07-08 20:04:55 -0700507 }
Christopher Tatea286f412009-09-18 15:51:15 -0700508 } catch (EOFException eof) {
509 // With the default 0 checksum we'll wind up forcing a backup of
510 // any unhandled data sets, which is appropriate.
Amith Yamasanid1582142009-07-08 20:04:55 -0700511 }
512 dataInput.close();
513 return stateChecksums;
514 }
515
516 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
517 throws IOException {
518 DataOutputStream dataOutput = new DataOutputStream(
Marvin Paul68795552014-12-16 14:12:33 -0800519 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
Christopher Tatea286f412009-09-18 15:51:15 -0700520
521 dataOutput.writeInt(STATE_VERSION);
Amith Yamasanid1582142009-07-08 20:04:55 -0700522 for (int i = 0; i < STATE_SIZE; i++) {
523 dataOutput.writeLong(checksums[i]);
524 }
525 dataOutput.close();
526 }
527
528 private long writeIfChanged(long oldChecksum, String key, byte[] data,
Ritesh Reddy33117fe2016-02-01 13:45:33 +0000529 BackupDataOutput output) {
Amith Yamasanid1582142009-07-08 20:04:55 -0700530 CRC32 checkSummer = new CRC32();
531 checkSummer.update(data);
532 long newChecksum = checkSummer.getValue();
533 if (oldChecksum == newChecksum) {
534 return oldChecksum;
535 }
536 try {
Amith Yamasani072543f2015-02-13 11:09:45 -0800537 if (DEBUG_BACKUP) {
538 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
539 }
Amith Yamasanid1582142009-07-08 20:04:55 -0700540 output.writeEntityHeader(key, data.length);
541 output.writeEntityData(data, data.length);
542 } catch (IOException ioe) {
543 // Bail
544 }
545 return newChecksum;
546 }
547
Amith Yamasani220f4d62009-07-02 02:34:14 -0700548 private byte[] getSystemSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700549 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
550 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700551 try {
Al Sutton0833b2e2019-08-22 16:21:30 +0100552 return extractRelevantValues(cursor, SystemSettings.SETTINGS_TO_BACKUP);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700553 } finally {
554 cursor.close();
555 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700556 }
557
558 private byte[] getSecureSettings() {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700559 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
560 null, null);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700561 try {
Al Sutton0833b2e2019-08-22 16:21:30 +0100562 return extractRelevantValues(cursor, SecureSettings.SETTINGS_TO_BACKUP);
Jeff Brown1d8e7d62011-10-09 15:24:53 -0700563 } finally {
564 cursor.close();
565 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700566 }
567
Christopher Tate66488d62012-10-02 11:58:01 -0700568 private byte[] getGlobalSettings() {
569 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
570 null, null);
571 try {
Al Sutton0833b2e2019-08-22 16:21:30 +0100572 return extractRelevantValues(cursor, GlobalSettings.SETTINGS_TO_BACKUP);
Christopher Tate66488d62012-10-02 11:58:01 -0700573 } finally {
574 cursor.close();
575 }
576 }
577
Amith Yamasani072543f2015-02-13 11:09:45 -0800578 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100579 * Serialize the owner info and other lock settings
Amith Yamasani072543f2015-02-13 11:09:45 -0800580 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100581 private byte[] getLockSettings(@UserIdInt int userId) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800582 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100583 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId);
584 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId);
585 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId);
586 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId);
587 final boolean powerButtonInstantlyLocks =
588 lockPatternUtils.getPowerButtonInstantlyLocks(userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800589
590 ByteArrayOutputStream baos = new ByteArrayOutputStream();
591 DataOutputStream out = new DataOutputStream(baos);
592 try {
593 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
594 out.writeUTF(ownerInfoEnabled ? "1" : "0");
595 if (ownerInfo != null) {
596 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
597 out.writeUTF(ownerInfo != null ? ownerInfo : "");
598 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100599 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) {
600 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED);
601 out.writeUTF(visiblePatternEnabled ? "1" : "0");
602 }
603 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) {
604 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS);
605 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0");
606 }
Amith Yamasani072543f2015-02-13 11:09:45 -0800607 // End marker
608 out.writeUTF("");
609 out.flush();
610 } catch (IOException ioe) {
611 }
612 return baos.toByteArray();
613 }
614
Christopher Tate66488d62012-10-02 11:58:01 -0700615 private void restoreSettings(BackupDataInput data, Uri contentUri,
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100616 HashSet<String> movedToGlobal, Set<String> movedToSecure) {
Christopher Tate75a99702011-05-18 16:28:19 -0700617 byte[] settings = new byte[data.getDataSize()];
618 try {
619 data.readEntityData(settings, 0, settings.length);
620 } catch (IOException ioe) {
621 Log.e(TAG, "Couldn't read entity data");
622 return;
623 }
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100624 restoreSettings(settings, settings.length, contentUri, movedToGlobal, movedToSecure);
Christopher Tate75a99702011-05-18 16:28:19 -0700625 }
626
Christopher Tate66488d62012-10-02 11:58:01 -0700627 private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100628 HashSet<String> movedToGlobal, Set<String> movedToSecure) {
Al Sutton71dc8ff2019-07-12 11:42:03 +0100629 restoreSettings(settings, 0, bytes, contentUri, movedToGlobal, movedToSecure);
630 }
631
632 private void restoreSettings(byte[] settings, int pos, int bytes, Uri contentUri,
633 HashSet<String> movedToGlobal, Set<String> movedToSecure) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700634 if (DEBUG) {
635 Log.i(TAG, "restoreSettings: " + contentUri);
636 }
637
Christopher Tate1d0fca32017-06-06 13:30:00 -0700638 // Figure out the white list and redirects to the global table. We restore anything
639 // in either the backup whitelist or the legacy-restore whitelist for this table.
Christopher Tate6597e342015-02-17 12:15:25 -0800640 final String[] whitelist;
Michal Karpinskib52575c2018-01-19 17:38:45 +0000641 Map<String, Validator> validators = null;
Christopher Tate796e0f02009-09-22 11:57:58 -0700642 if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
Al Sutton0833b2e2019-08-22 16:21:30 +0100643 whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
Al Sutton71dc8ff2019-07-12 11:42:03 +0100644 Settings.Secure.LEGACY_RESTORE_SETTINGS,
Al Sutton66a3e012019-10-15 15:34:13 +0100645 DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
Al Sutton91f89d02019-08-16 12:56:57 +0100646 validators = SecureSettingsValidators.VALIDATORS;
Christopher Tate796e0f02009-09-22 11:57:58 -0700647 } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
Al Sutton0833b2e2019-08-22 16:21:30 +0100648 whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
Christopher Tate1d0fca32017-06-06 13:30:00 -0700649 Settings.System.LEGACY_RESTORE_SETTINGS);
Al Sutton91f89d02019-08-16 12:56:57 +0100650 validators = SystemSettingsValidators.VALIDATORS;
Christopher Tate66488d62012-10-02 11:58:01 -0700651 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
Al Sutton0833b2e2019-08-22 16:21:30 +0100652 whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
Christopher Tate1d0fca32017-06-06 13:30:00 -0700653 Settings.Global.LEGACY_RESTORE_SETTINGS);
Al Sutton91f89d02019-08-16 12:56:57 +0100654 validators = GlobalSettingsValidators.VALIDATORS;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700655 } else {
656 throw new IllegalArgumentException("Unknown URI: " + contentUri);
Christopher Tate796e0f02009-09-22 11:57:58 -0700657 }
658
Svetoslav Ganova571a582011-09-20 18:32:20 -0700659 // Restore only the white list data.
Svet Ganovaabc9632017-07-28 19:37:15 -0700660 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700661 ContentValues contentValues = new ContentValues(2);
662 SettingsHelper settingsHelper = mSettingsHelper;
Christopher Tate6597e342015-02-17 12:15:25 -0800663 ContentResolver cr = getContentResolver();
Christopher Tate0738e882009-09-11 16:35:39 -0700664
Svetoslav Ganova571a582011-09-20 18:32:20 -0700665 final int whiteListSize = whitelist.length;
666 for (int i = 0; i < whiteListSize; i++) {
667 String key = whitelist[i];
Christopher Tate0738e882009-09-11 16:35:39 -0700668
Svet Ganovaabc9632017-07-28 19:37:15 -0700669 String value = null;
670 boolean hasValueToRestore = false;
671 if (cachedEntries.indexOfKey(key) >= 0) {
672 value = cachedEntries.remove(key);
673 hasValueToRestore = true;
674 } else {
675 // If the value not cached, let us look it up.
Svetoslav Ganova571a582011-09-20 18:32:20 -0700676 while (pos < bytes) {
677 int length = readInt(settings, pos);
678 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700679 String dataKey = length >= 0 ? new String(settings, pos, length) : null;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700680 pos += length;
681 length = readInt(settings, pos);
682 pos += INTEGER_BYTE_COUNT;
Svet Ganovaabc9632017-07-28 19:37:15 -0700683 String dataValue = null;
684 if (length >= 0) {
685 dataValue = new String(settings, pos, length);
686 pos += length;
687 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700688 if (key.equals(dataKey)) {
689 value = dataValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700690 hasValueToRestore = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700691 break;
692 }
693 cachedEntries.put(dataKey, dataValue);
Amith Yamasani70c874b2009-07-06 14:53:25 -0700694 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700695 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700696
Svet Ganovaabc9632017-07-28 19:37:15 -0700697 if (!hasValueToRestore) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700698 continue;
699 }
Christopher Tate796e0f02009-09-22 11:57:58 -0700700
Michal Karpinskib52575c2018-01-19 17:38:45 +0000701 // only restore the settings that have valid values
702 if (!isValidSettingValue(key, value, validators)) {
703 Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass"
704 + " validation, value: " + value);
705 continue;
706 }
707
Ruslan Tkhakokhovb8bf45f2019-07-24 21:13:35 +0100708 final Uri destination;
709 if (movedToGlobal != null && movedToGlobal.contains(key)) {
710 destination = Settings.Global.CONTENT_URI;
711 } else if (movedToSecure != null && movedToSecure.contains(key)) {
712 destination = Settings.Secure.CONTENT_URI;
713 } else {
714 destination = contentUri;
715 }
Michal Karpinski6135a262017-08-11 10:45:58 +0100716 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value,
717 mRestoredFromSdkInt);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700718
Christopher Tated488bc02012-10-09 14:06:30 -0700719 if (DEBUG) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000720 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
Christopher Tate0738e882009-09-11 16:35:39 -0700721 }
722 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700723 }
724
Michal Karpinskib52575c2018-01-19 17:38:45 +0000725 private boolean isValidSettingValue(String key, String value,
726 Map<String, Validator> validators) {
727 if (key == null || validators == null) {
728 return false;
729 }
730 Validator validator = validators.get(key);
731 return (validator != null) && validator.validate(value);
732 }
733
Amith Yamasani220f4d62009-07-02 02:34:14 -0700734 /**
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100735 * Restores the owner info enabled and other settings in LockSettings.
Amith Yamasani072543f2015-02-13 11:09:45 -0800736 *
737 * @param buffer
738 * @param nBytes
739 */
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100740 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800741 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
742
743 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
744 DataInputStream in = new DataInputStream(bais);
745 try {
746 String key;
747 // Read until empty string marker
748 while ((key = in.readUTF()).length() > 0) {
749 final String value = in.readUTF();
750 if (DEBUG_BACKUP) {
751 Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
752 }
753 switch (key) {
754 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100755 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800756 break;
757 case KEY_LOCK_SETTINGS_OWNER_INFO:
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100758 lockPatternUtils.setOwnerInfo(value, userId);
759 break;
760 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED:
761 lockPatternUtils.reportPatternWasChosen(userId);
762 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId);
763 break;
764 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS:
765 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId);
Amith Yamasani072543f2015-02-13 11:09:45 -0800766 break;
767 }
768 }
769 in.close();
770 } catch (IOException ioe) {
771 }
772 }
773
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100774 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) {
Amith Yamasani072543f2015-02-13 11:09:45 -0800775 final byte[] settings = new byte[data.getDataSize()];
776 try {
777 data.readEntityData(settings, 0, settings.length);
778 } catch (IOException ioe) {
779 Log.e(TAG, "Couldn't read entity data");
780 return;
781 }
Bryan Mawhinneye483b562017-05-15 14:46:05 +0100782 restoreLockSettings(userId, settings, settings.length);
Amith Yamasani072543f2015-02-13 11:09:45 -0800783 }
784
785 /**
Svetoslav Ganova571a582011-09-20 18:32:20 -0700786 * Given a cursor and a set of keys, extract the required keys and
787 * values and write them to a byte array.
788 *
789 * @param cursor A cursor with settings data.
790 * @param settings The settings to extract.
791 * @return The byte array of extracted values.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700792 */
Svetoslav Ganova571a582011-09-20 18:32:20 -0700793 private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700794 if (!cursor.moveToFirst()) {
Amith Yamasani220f4d62009-07-02 02:34:14 -0700795 Log.e(TAG, "Couldn't read from the cursor");
796 return new byte[0];
797 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700798
Svet Ganovaabc9632017-07-28 19:37:15 -0700799 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
800 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
801
Svetoslav Ganova571a582011-09-20 18:32:20 -0700802 // Obtain the relevant data in a temporary array.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700803 int totalSize = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700804 int backedUpSettingIndex = 0;
Svet Ganovaabc9632017-07-28 19:37:15 -0700805 final int settingsCount = settings.length;
806 final byte[][] values = new byte[settingsCount * 2][]; // keys and values
807 final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700808 for (int i = 0; i < settingsCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700809 final String key = settings[i];
Svetoslav683914b2015-01-15 14:22:26 -0800810
Svetoslav Ganova571a582011-09-20 18:32:20 -0700811 // If the value not cached, let us look it up.
Svet Ganovaabc9632017-07-28 19:37:15 -0700812 String value = null;
813 boolean hasValueToBackup = false;
814 if (cachedEntries.indexOfKey(key) >= 0) {
815 value = cachedEntries.remove(key);
816 hasValueToBackup = true;
817 } else {
Svetoslav Ganova571a582011-09-20 18:32:20 -0700818 while (!cursor.isAfterLast()) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700819 final String cursorKey = cursor.getString(nameColumnIndex);
820 final String cursorValue = cursor.getString(valueColumnIndex);
Svetoslav Ganova571a582011-09-20 18:32:20 -0700821 cursor.moveToNext();
822 if (key.equals(cursorKey)) {
823 value = cursorValue;
Svet Ganovaabc9632017-07-28 19:37:15 -0700824 hasValueToBackup = true;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700825 break;
826 }
827 cachedEntries.put(cursorKey, cursorValue);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700828 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700829 }
Svetoslav Ganova571a582011-09-20 18:32:20 -0700830
Svet Ganovaabc9632017-07-28 19:37:15 -0700831 if (!hasValueToBackup) {
832 continue;
833 }
834
Amith Yamasani622bf2222013-09-06 13:54:28 -0700835 // Intercept the keys and see if they need special handling
836 value = mSettingsHelper.onBackupValue(key, value);
837
Svetoslav Ganova571a582011-09-20 18:32:20 -0700838 // Write the key and value in the intermediary array.
Svet Ganovaabc9632017-07-28 19:37:15 -0700839 final byte[] keyBytes = key.getBytes();
Svetoslav Ganova571a582011-09-20 18:32:20 -0700840 totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
841 values[backedUpSettingIndex * 2] = keyBytes;
842
Svet Ganovaabc9632017-07-28 19:37:15 -0700843 final byte[] valueBytes = (value != null) ? value.getBytes() : NULL_VALUE;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700844 totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
845 values[backedUpSettingIndex * 2 + 1] = valueBytes;
846
847 backedUpSettingIndex++;
848
849 if (DEBUG) {
850 Log.d(TAG, "Backed up setting: " + key + "=" + value);
Amith Yamasani220f4d62009-07-02 02:34:14 -0700851 }
852 }
853
Svetoslav Ganova571a582011-09-20 18:32:20 -0700854 // Aggregate the result.
Amith Yamasani220f4d62009-07-02 02:34:14 -0700855 byte[] result = new byte[totalSize];
856 int pos = 0;
Svetoslav Ganova571a582011-09-20 18:32:20 -0700857 final int keyValuePairCount = backedUpSettingIndex * 2;
858 for (int i = 0; i < keyValuePairCount; i++) {
Svet Ganovaabc9632017-07-28 19:37:15 -0700859 final byte[] value = values[i];
860 if (value != NULL_VALUE) {
861 pos = writeInt(result, pos, value.length);
862 pos = writeBytes(result, pos, value);
863 } else {
864 pos = writeInt(result, pos, NULL_SIZE);
865 }
Amith Yamasani220f4d62009-07-02 02:34:14 -0700866 }
867 return result;
868 }
869
Roshan Pius5db739c2016-06-17 16:51:36 -0700870 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700871 if (DEBUG_BACKUP) {
872 Log.v(TAG, "Applying restored supplicant wifi data");
Irfan Sheriff4aeca7c52011-03-10 16:53:33 -0800873 }
Roshan Pius7a2491f2016-06-02 09:22:55 -0700874 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes);
Amith Yamasani2cfab842009-09-09 18:27:31 -0700875 }
876
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000877 private byte[] getSoftAPConfiguration() {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000878 try {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700879 return mWifiManager.getWifiApConfiguration().getBytesForBackup();
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000880 } catch (IOException ioe) {
881 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
882 return new byte[0];
883 }
884 }
885
886 private void restoreSoftApConfiguration(byte[] data) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000887 try {
888 WifiConfiguration config = WifiConfiguration
889 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
890 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700891 int originalApBand = config.apBand;
Roshan Pius7a2491f2016-06-02 09:22:55 -0700892 mWifiManager.setWifiApConfiguration(config);
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700893
894 // Depending on device hardware, we may need to notify the user of a setting change for
895 // the apBand preference
896 boolean dualMode = mWifiManager.isDualModeSupported();
897 int storedApBand = mWifiManager.getWifiApConfiguration().apBand;
David Su6c07c9f2019-11-20 18:16:56 -0800898 if (dualMode && storedApBand != originalApBand) {
899 Log.d(TAG, "restored ap configuration requires a conversion, notify the user");
900 WifiSoftApBandChangedNotifier.notifyUserOfApBandConversion(this);
Rebecca Silbersteind41106c2018-06-01 17:31:40 -0700901 }
Ritesh Reddyaeb4c062016-01-26 19:40:48 +0000902 } catch (IOException | BackupUtils.BadVersionException e) {
903 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
904 }
905 }
906
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000907 private byte[] getNetworkPolicies() {
908 NetworkPolicyManager networkPolicyManager =
909 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
910 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
911 ByteArrayOutputStream baos = new ByteArrayOutputStream();
912 if (policies != null && policies.length != 0) {
913 DataOutputStream out = new DataOutputStream(baos);
914 try {
915 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
916 out.writeInt(policies.length);
917 for (NetworkPolicy policy : policies) {
Jeff Sharkey55a3fe72018-02-24 19:09:20 -0700918 // We purposefully only backup policies that the user has
919 // defined; any inferred policies might include
920 // carrier-protected data that we can't export.
921 if (policy != null && !policy.inferred) {
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000922 byte[] marshaledPolicy = policy.getBytesForBackup();
923 out.writeByte(BackupUtils.NOT_NULL);
924 out.writeInt(marshaledPolicy.length);
925 out.write(marshaledPolicy);
926 } else {
927 out.writeByte(BackupUtils.NULL);
928 }
929 }
930 } catch (IOException ioe) {
931 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
932 baos.reset();
933 }
934 }
935 return baos.toByteArray();
936 }
937
Roshan Pius7a2491f2016-06-02 09:22:55 -0700938 private byte[] getNewWifiConfigData() {
939 return mWifiManager.retrieveBackupData();
940 }
941
Roshan Pius5db739c2016-06-17 16:51:36 -0700942 private void restoreNewWifiConfigData(byte[] bytes) {
Roshan Pius7a2491f2016-06-02 09:22:55 -0700943 if (DEBUG_BACKUP) {
944 Log.v(TAG, "Applying restored wifi data");
945 }
946 mWifiManager.restoreBackupData(bytes);
947 }
948
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000949 private void restoreNetworkPolicies(byte[] data) {
950 NetworkPolicyManager networkPolicyManager =
951 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
952 if (data != null && data.length != 0) {
953 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
954 try {
955 int version = in.readInt();
956 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
957 throw new BackupUtils.BadVersionException(
958 "Unknown Backup Serialization Version");
959 }
960 int length = in.readInt();
961 NetworkPolicy[] policies = new NetworkPolicy[length];
962 for (int i = 0; i < length; i++) {
963 byte isNull = in.readByte();
964 if (isNull == BackupUtils.NULL) continue;
965 int byteLength = in.readInt();
966 byte[] policyData = new byte[byteLength];
967 in.read(policyData, 0, byteLength);
968 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
969 new DataInputStream(new ByteArrayInputStream(policyData)));
970 }
971 // Only set the policies if there was no error in the restore operation
972 networkPolicyManager.setNetworkPolicies(policies);
Annie Meng47f5c9c2018-02-27 14:48:21 +0000973 } catch (NullPointerException | IOException | BackupUtils.BadVersionException
974 | DateTimeException e) {
Ritesh Reddyadca34a2016-02-04 18:33:30 +0000975 // NPE can be thrown when trying to instantiate a NetworkPolicy
976 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
977 }
978 }
979 }
980
Al Sutton71dc8ff2019-07-12 11:42:03 +0100981 @VisibleForTesting
982 byte[] getDeviceSpecificConfiguration() throws IOException {
983 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
984 writeHeader(os);
985 os.write(getDeviceSpecificSettings());
986 return os.toByteArray();
987 }
988 }
989
990 @VisibleForTesting
991 void writeHeader(OutputStream os) throws IOException {
992 os.write(toByteArray(DEVICE_SPECIFIC_VERSION));
993 os.write(toByteArray(Build.MANUFACTURER));
994 os.write(toByteArray(Build.PRODUCT));
995 }
996
997 private byte[] getDeviceSpecificSettings() {
998 try (Cursor cursor =
999 getContentResolver()
1000 .query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null)) {
1001 return extractRelevantValues(
Al Sutton66a3e012019-10-15 15:34:13 +01001002 cursor, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
Al Sutton71dc8ff2019-07-12 11:42:03 +01001003 }
1004 }
1005
1006 /**
1007 * Restore the device specific settings.
1008 *
1009 * @param data The byte array holding a backed up version of another devices settings.
1010 * @return true if the restore succeeded, false if it was stopped.
1011 */
1012 @VisibleForTesting
1013 boolean restoreDeviceSpecificConfig(byte[] data) {
1014 // We're using an AtomicInteger to wrap the position int and allow called methods to
1015 // modify it.
1016 AtomicInteger pos = new AtomicInteger(0);
1017 if (!isSourceAcceptable(data, pos)) {
1018 return false;
1019 }
1020
1021 Integer originalDensity = getPreviousDensity();
1022
1023 int dataStart = pos.get();
1024 restoreSettings(
1025 data, dataStart, data.length, Settings.Secure.CONTENT_URI, null, null);
1026
1027 updateWindowManagerIfNeeded(originalDensity);
1028
1029 return true;
1030 }
1031
1032 private void updateWindowManagerIfNeeded(Integer previousDensity) {
1033 int newDensity;
1034 try {
1035 newDensity = getForcedDensity();
1036 } catch (Settings.SettingNotFoundException e) {
1037 // If there's not density setting we can't perform a change.
1038 return;
1039 }
1040
1041 if (previousDensity == null || previousDensity != newDensity) {
1042 // From nothing to something is a change.
Al Suttone5e79162019-08-19 13:42:16 +01001043 DisplayDensityConfiguration.setForcedDisplayDensity(
1044 Display.DEFAULT_DISPLAY, newDensity);
Al Sutton71dc8ff2019-07-12 11:42:03 +01001045 }
1046 }
1047
1048 private Integer getPreviousDensity() {
1049 try {
1050 return getForcedDensity();
1051 } catch (Settings.SettingNotFoundException e) {
1052 return null;
1053 }
1054 }
1055
1056 private int getForcedDensity() throws Settings.SettingNotFoundException {
1057 return Settings.Secure.getInt(getContentResolver(), Settings.Secure.DISPLAY_DENSITY_FORCED);
1058 }
1059
1060 @VisibleForTesting
1061 boolean isSourceAcceptable(byte[] data, AtomicInteger pos) {
1062 int version = readInt(data, pos);
1063 if (version > DEVICE_SPECIFIC_VERSION) {
1064 Slog.w(TAG, "Unable to restore device specific information; Backup is too new");
1065 return false;
1066 }
1067
1068 String sourceManufacturer = readString(data, pos);
1069 if (!Objects.equals(Build.MANUFACTURER, sourceManufacturer)) {
1070 Log.w(
1071 TAG,
1072 "Unable to restore device specific information; Manufacturer mismatch "
1073 + "(\'"
1074 + Build.MANUFACTURER
1075 + "\' and \'"
1076 + sourceManufacturer
1077 + "\')");
1078 return false;
1079 }
1080
1081 String sourceProduct = readString(data, pos);
1082 if (!Objects.equals(Build.PRODUCT, sourceProduct)) {
1083 Log.w(
1084 TAG,
1085 "Unable to restore device specific information; Product mismatch (\'"
1086 + Build.PRODUCT
1087 + "\' and \'"
1088 + sourceProduct
1089 + "\')");
1090 return false;
1091 }
1092
1093 return true;
1094 }
1095
1096 @VisibleForTesting
1097 static byte[] toByteArray(String value) {
1098 if (value == null) {
1099 return toByteArray(NULL_SIZE);
1100 }
1101
1102 byte[] stringBytes = value.getBytes();
1103 byte[] sizeAndString = new byte[stringBytes.length + INTEGER_BYTE_COUNT];
1104 writeInt(sizeAndString, 0, stringBytes.length);
1105 writeBytes(sizeAndString, INTEGER_BYTE_COUNT, stringBytes);
1106 return sizeAndString;
1107 }
1108
1109 @VisibleForTesting
1110 static byte[] toByteArray(int value) {
1111 byte[] result = new byte[INTEGER_BYTE_COUNT];
1112 writeInt(result, 0, value);
1113 return result;
1114 }
1115
1116 private String readString(byte[] data, AtomicInteger pos) {
1117 int byteCount = readInt(data, pos);
1118 if (byteCount == NULL_SIZE) {
1119 return null;
1120 }
1121
1122 int stringStart = pos.getAndAdd(byteCount);
1123 return new String(data, stringStart, byteCount);
1124 }
1125
Amith Yamasani220f4d62009-07-02 02:34:14 -07001126 /**
1127 * Write an int in BigEndian into the byte array.
1128 * @param out byte array
1129 * @param pos current pos in array
1130 * @param value integer to write
Svetoslav Ganova571a582011-09-20 18:32:20 -07001131 * @return the index after adding the size of an int (4) in bytes.
Amith Yamasani220f4d62009-07-02 02:34:14 -07001132 */
Al Sutton71dc8ff2019-07-12 11:42:03 +01001133 private static int writeInt(byte[] out, int pos, int value) {
Amith Yamasani220f4d62009-07-02 02:34:14 -07001134 out[pos + 0] = (byte) ((value >> 24) & 0xFF);
1135 out[pos + 1] = (byte) ((value >> 16) & 0xFF);
1136 out[pos + 2] = (byte) ((value >> 8) & 0xFF);
1137 out[pos + 3] = (byte) ((value >> 0) & 0xFF);
Svetoslav Ganova571a582011-09-20 18:32:20 -07001138 return pos + INTEGER_BYTE_COUNT;
Amith Yamasani220f4d62009-07-02 02:34:14 -07001139 }
1140
Al Sutton71dc8ff2019-07-12 11:42:03 +01001141 private static int writeBytes(byte[] out, int pos, byte[] value) {
Amith Yamasani220f4d62009-07-02 02:34:14 -07001142 System.arraycopy(value, 0, out, pos, value.length);
1143 return pos + value.length;
1144 }
1145
Al Sutton71dc8ff2019-07-12 11:42:03 +01001146 private int readInt(byte[] in, AtomicInteger pos) {
1147 return readInt(in, pos.getAndAdd(INTEGER_BYTE_COUNT));
1148 }
1149
Amith Yamasani220f4d62009-07-02 02:34:14 -07001150 private int readInt(byte[] in, int pos) {
Ritesh Reddyaeb4c062016-01-26 19:40:48 +00001151 int result = ((in[pos] & 0xFF) << 24)
1152 | ((in[pos + 1] & 0xFF) << 16)
1153 | ((in[pos + 2] & 0xFF) << 8)
1154 | ((in[pos + 3] & 0xFF) << 0);
Amith Yamasani220f4d62009-07-02 02:34:14 -07001155 return result;
1156 }
Paul Stewart45e6fec2016-05-20 08:14:30 -07001157}