1 /* 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 17 package com.android.providers.settings; 18 19 import android.annotation.UserIdInt; 20 import android.app.backup.BackupAgentHelper; 21 import android.app.backup.BackupDataInput; 22 import android.app.backup.BackupDataOutput; 23 import android.app.backup.FullBackupDataOutput; 24 import android.content.ContentResolver; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.pm.PackageManager; 28 import android.database.Cursor; 29 import android.net.NetworkPolicy; 30 import android.net.NetworkPolicyManager; 31 import android.net.Uri; 32 import android.net.wifi.SoftApConfiguration; 33 import android.net.wifi.WifiManager; 34 import android.os.Build; 35 import android.os.ParcelFileDescriptor; 36 import android.os.UserHandle; 37 import android.provider.Settings; 38 import android.provider.settings.backup.DeviceSpecificSettings; 39 import android.provider.settings.backup.GlobalSettings; 40 import android.provider.settings.backup.LargeScreenSettings; 41 import android.provider.settings.backup.SecureSettings; 42 import android.provider.settings.backup.SystemSettings; 43 import android.provider.settings.validators.GlobalSettingsValidators; 44 import android.provider.settings.validators.SecureSettingsValidators; 45 import android.provider.settings.validators.SystemSettingsValidators; 46 import android.provider.settings.validators.Validator; 47 import android.telephony.SubscriptionManager; 48 import android.util.ArrayMap; 49 import android.util.ArraySet; 50 import android.util.BackupUtils; 51 import android.util.FeatureFlagUtils; 52 import android.util.Log; 53 import android.util.Slog; 54 import android.view.Display; 55 56 import com.android.internal.annotations.VisibleForTesting; 57 import com.android.internal.util.ArrayUtils; 58 import com.android.internal.widget.LockPatternUtils; 59 import com.android.settingslib.display.DisplayDensityConfiguration; 60 61 import java.io.BufferedOutputStream; 62 import java.io.ByteArrayInputStream; 63 import java.io.ByteArrayOutputStream; 64 import java.io.DataInputStream; 65 import java.io.DataOutputStream; 66 import java.io.EOFException; 67 import java.io.FileInputStream; 68 import java.io.FileOutputStream; 69 import java.io.IOException; 70 import java.io.OutputStream; 71 import java.time.DateTimeException; 72 import java.util.Arrays; 73 import java.util.Collections; 74 import java.util.HashSet; 75 import java.util.Map; 76 import java.util.Objects; 77 import java.util.Set; 78 import java.util.concurrent.atomic.AtomicInteger; 79 import java.util.zip.CRC32; 80 81 /** 82 * Performs backup and restore of the System and Secure settings. 83 * List of settings that are backed up are stored in the Settings.java file 84 */ 85 public class SettingsBackupAgent extends BackupAgentHelper { 86 private static final boolean DEBUG = false; 87 private static final boolean DEBUG_BACKUP = DEBUG || false; 88 89 private static final byte[] NULL_VALUE = new byte[0]; 90 private static final int NULL_SIZE = -1; 91 92 private static final String KEY_SYSTEM = "system"; 93 private static final String KEY_SECURE = "secure"; 94 private static final String KEY_GLOBAL = "global"; 95 private static final String KEY_LOCALE = "locale"; 96 private static final String KEY_LOCK_SETTINGS = "lock_settings"; 97 private static final String KEY_SOFTAP_CONFIG = "softap_config"; 98 private static final String KEY_NETWORK_POLICIES = "network_policies"; 99 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config"; 100 private static final String KEY_DEVICE_SPECIFIC_CONFIG = "device_specific_config"; 101 private static final String KEY_SIM_SPECIFIC_SETTINGS = "sim_specific_settings"; 102 // Restoring sim-specific data backed up from newer Android version to Android 12 was causing a 103 // fatal crash. Creating a backup with a different key will prevent Android 12 versions from 104 // restoring this data. 105 private static final String KEY_SIM_SPECIFIC_SETTINGS_2 = "sim_specific_settings_2"; 106 107 // Versioning of the state file. Increment this version 108 // number any time the set of state items is altered. 109 private static final int STATE_VERSION = 9; 110 111 // Versioning of the Network Policies backup payload. 112 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1; 113 114 115 // Slots in the checksum array. Never insert new items in the middle 116 // of this array; new slots must be appended. 117 private static final int STATE_SYSTEM = 0; 118 private static final int STATE_SECURE = 1; 119 private static final int STATE_LOCALE = 2; 120 private static final int STATE_WIFI_SUPPLICANT = 3; 121 private static final int STATE_WIFI_CONFIG = 4; 122 private static final int STATE_GLOBAL = 5; 123 private static final int STATE_LOCK_SETTINGS = 6; 124 private static final int STATE_SOFTAP_CONFIG = 7; 125 private static final int STATE_NETWORK_POLICIES = 8; 126 private static final int STATE_WIFI_NEW_CONFIG = 9; 127 private static final int STATE_DEVICE_CONFIG = 10; 128 private static final int STATE_SIM_SPECIFIC_SETTINGS = 11; 129 130 private static final int STATE_SIZE = 12; // The current number of state items 131 132 // Number of entries in the checksum array at various version numbers 133 private static final int STATE_SIZES[] = { 134 0, 135 4, // version 1 136 5, // version 2 added STATE_WIFI_CONFIG 137 6, // version 3 added STATE_GLOBAL 138 7, // version 4 added STATE_LOCK_SETTINGS 139 8, // version 5 added STATE_SOFTAP_CONFIG 140 9, // version 6 added STATE_NETWORK_POLICIES 141 10, // version 7 added STATE_WIFI_NEW_CONFIG 142 11, // version 8 added STATE_DEVICE_CONFIG 143 STATE_SIZE // version 9 added STATE_SIM_SPECIFIC_SETTINGS 144 }; 145 146 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry 147 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry 148 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry 149 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies" 150 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry 151 private static final int FULL_BACKUP_ADDED_DEVICE_SPECIFIC = 7; // added "device specific" entry 152 // Versioning of the 'full backup' format 153 // Increment this version any time a new item is added 154 private static final int FULL_BACKUP_VERSION = FULL_BACKUP_ADDED_DEVICE_SPECIFIC; 155 156 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE; 157 158 private static final byte[] EMPTY_DATA = new byte[0]; 159 160 private static final String TAG = "SettingsBackupAgent"; 161 162 @VisibleForTesting 163 static final String[] PROJECTION = { 164 Settings.NameValueTable.NAME, 165 Settings.NameValueTable.VALUE 166 }; 167 168 // Versioning of the 'device specific' section of a backup 169 // Increment this any time the format is changed or data added. 170 @VisibleForTesting 171 static final int DEVICE_SPECIFIC_VERSION = 1; 172 173 // the key to store the WIFI data under, should be sorted as last, so restore happens last. 174 // use very late unicode character to quasi-guarantee last sort position. 175 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI"; 176 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI"; 177 178 // Keys within the lock settings section 179 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled"; 180 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info"; 181 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED = 182 "visible_pattern_enabled"; 183 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS = 184 "power_button_instantly_locks"; 185 private static final String KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY = 186 "pin_enhanced_privacy"; 187 188 // Name of the temporary file we use during full backup/restore. This is 189 // stored in the full-backup tarfile as well, so should not be changed. 190 private static final String STAGE_FILE = "flattened-data"; 191 192 // List of keys that support restore to lower version of the SDK, introduced in Android P 193 private static final ArraySet<String> RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS = 194 new ArraySet<String>(Arrays.asList(new String[] { 195 KEY_NETWORK_POLICIES, 196 KEY_WIFI_NEW_CONFIG, 197 KEY_SYSTEM, 198 KEY_SECURE, 199 KEY_GLOBAL, 200 })); 201 202 @VisibleForTesting 203 SettingsHelper mSettingsHelper; 204 205 private WifiManager mWifiManager; 206 207 // Version of the SDK that com.android.providers.settings package has been restored from. 208 // Populated in onRestore(). 209 private int mRestoredFromSdkInt; 210 211 @Override onCreate()212 public void onCreate() { 213 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); 214 215 mSettingsHelper = new SettingsHelper(this); 216 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); 217 super.onCreate(); 218 } 219 220 @Override onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)221 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 222 ParcelFileDescriptor newState) throws IOException { 223 byte[] systemSettingsData = getSystemSettings(); 224 byte[] secureSettingsData = getSecureSettings(); 225 byte[] globalSettingsData = getGlobalSettings(); 226 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId()); 227 byte[] locale = mSettingsHelper.getLocaleData(); 228 byte[] softApConfigData = getSoftAPConfiguration(); 229 byte[] netPoliciesData = getNetworkPolicies(); 230 byte[] wifiFullConfigData = getNewWifiConfigData(); 231 byte[] deviceSpecificInformation = getDeviceSpecificConfiguration(); 232 byte[] simSpecificSettingsData = getSimSpecificSettingsData(); 233 234 long[] stateChecksums = readOldChecksums(oldState); 235 236 stateChecksums[STATE_SYSTEM] = 237 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data); 238 stateChecksums[STATE_SECURE] = 239 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data); 240 stateChecksums[STATE_GLOBAL] = 241 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data); 242 stateChecksums[STATE_LOCALE] = 243 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data); 244 stateChecksums[STATE_WIFI_SUPPLICANT] = 0; 245 stateChecksums[STATE_WIFI_CONFIG] = 0; 246 stateChecksums[STATE_LOCK_SETTINGS] = 247 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS, 248 lockSettingsData, data); 249 stateChecksums[STATE_SOFTAP_CONFIG] = 250 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG, 251 softApConfigData, data); 252 stateChecksums[STATE_NETWORK_POLICIES] = 253 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES, 254 netPoliciesData, data); 255 stateChecksums[STATE_WIFI_NEW_CONFIG] = 256 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG, 257 wifiFullConfigData, data); 258 stateChecksums[STATE_DEVICE_CONFIG] = 259 writeIfChanged(stateChecksums[STATE_DEVICE_CONFIG], KEY_DEVICE_SPECIFIC_CONFIG, 260 deviceSpecificInformation, data); 261 stateChecksums[STATE_SIM_SPECIFIC_SETTINGS] = 262 writeIfChanged(stateChecksums[STATE_SIM_SPECIFIC_SETTINGS], 263 KEY_SIM_SPECIFIC_SETTINGS_2, simSpecificSettingsData, data); 264 265 writeNewChecksums(stateChecksums, newState); 266 } 267 268 @Override onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)269 public void onRestore(BackupDataInput data, int appVersionCode, 270 ParcelFileDescriptor newState) { 271 throw new RuntimeException("SettingsBackupAgent has been migrated to use key exclusion"); 272 } 273 274 @Override onRestore(BackupDataInput data, long appVersionCode, ParcelFileDescriptor newState, Set<String> dynamicBlockList)275 public void onRestore(BackupDataInput data, long appVersionCode, 276 ParcelFileDescriptor newState, Set<String> dynamicBlockList) throws IOException { 277 278 if (DEBUG) { 279 Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode 280 + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT); 281 } 282 283 boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(), 284 Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1; 285 if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) { 286 Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API" 287 + Build.VERSION.SDK_INT + " due to settings flag override."); 288 return; 289 } 290 291 // versionCode of com.android.providers.settings corresponds to SDK_INT 292 mRestoredFromSdkInt = (int) appVersionCode; 293 294 Set<String> movedToGlobal = getMovedToGlobalSettings(); 295 Set<String> movedToSecure = getMovedToSecureSettings(); 296 Set<String> movedToSystem = getMovedToSystemSettings(); 297 298 Set<String> preservedGlobalSettings = getSettingsToPreserveInRestore( 299 Settings.Global.CONTENT_URI); 300 Set<String> preservedSecureSettings = getSettingsToPreserveInRestore( 301 Settings.Secure.CONTENT_URI); 302 Set<String> preservedSystemSettings = getSettingsToPreserveInRestore( 303 Settings.System.CONTENT_URI); 304 Set<String> preservedSettings = new HashSet<>(preservedGlobalSettings); 305 preservedSettings.addAll(preservedSecureSettings); 306 preservedSettings.addAll(preservedSystemSettings); 307 308 byte[] restoredWifiSupplicantData = null; 309 byte[] restoredWifiIpConfigData = null; 310 311 while (data.readNextHeader()) { 312 final String key = data.getKey(); 313 final int size = data.getDataSize(); 314 315 // bail out of restoring from higher SDK_INT version for unsupported keys 316 if (appVersionCode > Build.VERSION.SDK_INT 317 && !RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS.contains(key)) { 318 Log.w(TAG, "Not restoring unrecognized key '" 319 + key + "' from future version " + appVersionCode); 320 data.skipEntityData(); 321 continue; 322 } 323 324 switch (key) { 325 case KEY_SYSTEM : 326 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal, 327 movedToSecure, /* movedToSystem= */ null, 328 R.array.restore_blocked_system_settings, dynamicBlockList, 329 preservedSystemSettings); 330 mSettingsHelper.applyAudioSettings(); 331 break; 332 333 case KEY_SECURE : 334 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal, 335 /* movedToSecure= */ null, movedToSystem, 336 R.array.restore_blocked_secure_settings, dynamicBlockList, 337 preservedSecureSettings); 338 break; 339 340 case KEY_GLOBAL : 341 restoreSettings(data, Settings.Global.CONTENT_URI, /* movedToGlobal= */ null, 342 movedToSecure, movedToSystem, R.array.restore_blocked_global_settings, 343 dynamicBlockList, preservedGlobalSettings); 344 break; 345 346 case KEY_WIFI_SUPPLICANT : 347 restoredWifiSupplicantData = new byte[size]; 348 data.readEntityData(restoredWifiSupplicantData, 0, size); 349 break; 350 351 case KEY_LOCALE : 352 byte[] localeData = new byte[size]; 353 data.readEntityData(localeData, 0, size); 354 mSettingsHelper.setLocaleData(localeData, size); 355 break; 356 357 case KEY_WIFI_CONFIG : 358 restoredWifiIpConfigData = new byte[size]; 359 data.readEntityData(restoredWifiIpConfigData, 0, size); 360 break; 361 362 case KEY_LOCK_SETTINGS : 363 restoreLockSettings(UserHandle.myUserId(), data); 364 break; 365 366 case KEY_SOFTAP_CONFIG : 367 byte[] softapData = new byte[size]; 368 data.readEntityData(softapData, 0, size); 369 restoreSoftApConfiguration(softapData); 370 break; 371 372 case KEY_NETWORK_POLICIES: 373 byte[] netPoliciesData = new byte[size]; 374 data.readEntityData(netPoliciesData, 0, size); 375 restoreNetworkPolicies(netPoliciesData); 376 break; 377 378 case KEY_WIFI_NEW_CONFIG: 379 byte[] restoredWifiNewConfigData = new byte[size]; 380 data.readEntityData(restoredWifiNewConfigData, 0, size); 381 restoreNewWifiConfigData(restoredWifiNewConfigData); 382 break; 383 384 case KEY_DEVICE_SPECIFIC_CONFIG: 385 byte[] restoredDeviceSpecificConfig = new byte[size]; 386 data.readEntityData(restoredDeviceSpecificConfig, 0, size); 387 restoreDeviceSpecificConfig( 388 restoredDeviceSpecificConfig, 389 R.array.restore_blocked_device_specific_settings, 390 dynamicBlockList, 391 preservedSettings); 392 break; 393 394 case KEY_SIM_SPECIFIC_SETTINGS: 395 // Intentional fall through so that sim-specific backups from Android 12 will 396 // also be restored on newer Android versions. 397 case KEY_SIM_SPECIFIC_SETTINGS_2: 398 byte[] restoredSimSpecificSettings = new byte[size]; 399 data.readEntityData(restoredSimSpecificSettings, 0, size); 400 restoreSimSpecificSettings(restoredSimSpecificSettings); 401 break; 402 403 default : 404 data.skipEntityData(); 405 406 } 407 } 408 409 // Do this at the end so that we also pull in the ipconfig data. 410 if (restoredWifiSupplicantData != null) { 411 restoreSupplicantWifiConfigData( 412 restoredWifiSupplicantData, restoredWifiIpConfigData); 413 } 414 } 415 416 @Override onFullBackup(FullBackupDataOutput data)417 public void onFullBackup(FullBackupDataOutput data) throws IOException { 418 // Full backup of SettingsBackupAgent support was removed in Android P. If you want to adb 419 // backup com.android.providers.settings package use \"-keyvalue\" flag. 420 // Full restore of SettingsBackupAgent is still available for backwards compatibility. 421 } 422 423 @Override onRestoreFile(ParcelFileDescriptor data, long size, int type, String domain, String relpath, long mode, long mtime)424 public void onRestoreFile(ParcelFileDescriptor data, long size, 425 int type, String domain, String relpath, long mode, long mtime) 426 throws IOException { 427 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked"); 428 // Our data is actually a blob of flattened settings data identical to that 429 // produced during incremental backups. Just unpack and apply it all in 430 // turn. 431 FileInputStream instream = new FileInputStream(data.getFileDescriptor()); 432 DataInputStream in = new DataInputStream(instream); 433 434 int version = in.readInt(); 435 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version); 436 if (version <= FULL_BACKUP_VERSION) { 437 // Generate the moved-to-global lookup table 438 Set<String> movedToGlobal = getMovedToGlobalSettings(); 439 Set<String> movedToSecure = getMovedToSecureSettings(); 440 Set<String> movedToSystem = getMovedToSystemSettings(); 441 442 // system settings data first 443 int nBytes = in.readInt(); 444 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data"); 445 byte[] buffer = new byte[nBytes]; 446 in.readFully(buffer, 0, nBytes); 447 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal, 448 movedToSecure, /* movedToSystem= */ null, 449 R.array.restore_blocked_system_settings, Collections.emptySet(), 450 Collections.emptySet()); 451 452 // secure settings 453 nBytes = in.readInt(); 454 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data"); 455 if (nBytes > buffer.length) buffer = new byte[nBytes]; 456 in.readFully(buffer, 0, nBytes); 457 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal, 458 /* movedToSecure= */ null, movedToSystem, 459 R.array.restore_blocked_secure_settings, Collections.emptySet(), 460 Collections.emptySet()); 461 462 // Global only if sufficiently new 463 if (version >= FULL_BACKUP_ADDED_GLOBAL) { 464 nBytes = in.readInt(); 465 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data"); 466 if (nBytes > buffer.length) buffer = new byte[nBytes]; 467 in.readFully(buffer, 0, nBytes); 468 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, 469 /* movedToGlobal= */ null, movedToSecure, movedToSystem, 470 R.array.restore_blocked_global_settings, Collections.emptySet(), 471 Collections.emptySet()); 472 } 473 474 // locale 475 nBytes = in.readInt(); 476 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data"); 477 if (nBytes > buffer.length) buffer = new byte[nBytes]; 478 in.readFully(buffer, 0, nBytes); 479 mSettingsHelper.setLocaleData(buffer, nBytes); 480 481 // Restore older backups performing the necessary migrations. 482 if (version < FULL_BACKUP_ADDED_WIFI_NEW) { 483 // wifi supplicant 484 int supplicant_size = in.readInt(); 485 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data"); 486 byte[] supplicant_buffer = new byte[supplicant_size]; 487 in.readFully(supplicant_buffer, 0, supplicant_size); 488 489 // ip config 490 int ipconfig_size = in.readInt(); 491 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data"); 492 byte[] ipconfig_buffer = new byte[ipconfig_size]; 493 in.readFully(ipconfig_buffer, 0, nBytes); 494 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer); 495 } 496 497 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) { 498 nBytes = in.readInt(); 499 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data"); 500 if (nBytes > buffer.length) buffer = new byte[nBytes]; 501 if (nBytes > 0) { 502 in.readFully(buffer, 0, nBytes); 503 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes); 504 } 505 } 506 // softap config 507 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) { 508 nBytes = in.readInt(); 509 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data"); 510 if (nBytes > buffer.length) buffer = new byte[nBytes]; 511 if (nBytes > 0) { 512 in.readFully(buffer, 0, nBytes); 513 restoreSoftApConfiguration(buffer); 514 } 515 } 516 // network policies 517 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) { 518 nBytes = in.readInt(); 519 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data"); 520 if (nBytes > buffer.length) buffer = new byte[nBytes]; 521 if (nBytes > 0) { 522 in.readFully(buffer, 0, nBytes); 523 restoreNetworkPolicies(buffer); 524 } 525 } 526 // Restore full wifi config data 527 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) { 528 nBytes = in.readInt(); 529 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data"); 530 if (nBytes > buffer.length) buffer = new byte[nBytes]; 531 in.readFully(buffer, 0, nBytes); 532 restoreNewWifiConfigData(buffer); 533 } 534 535 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete."); 536 } else { 537 data.close(); 538 throw new IOException("Invalid file schema"); 539 } 540 } 541 getMovedToGlobalSettings()542 private Set<String> getMovedToGlobalSettings() { 543 HashSet<String> movedToGlobalSettings = new HashSet<String>(); 544 Settings.System.getMovedToGlobalSettings(movedToGlobalSettings); 545 Settings.Secure.getMovedToGlobalSettings(movedToGlobalSettings); 546 return movedToGlobalSettings; 547 } 548 getMovedToSecureSettings()549 private Set<String> getMovedToSecureSettings() { 550 Set<String> movedToSecureSettings = new HashSet<>(); 551 Settings.Global.getMovedToSecureSettings(movedToSecureSettings); 552 Settings.System.getMovedToSecureSettings(movedToSecureSettings); 553 return movedToSecureSettings; 554 } 555 getMovedToSystemSettings()556 private Set<String> getMovedToSystemSettings() { 557 Set<String> movedToSystemSettings = new HashSet<>(); 558 Settings.Global.getMovedToSystemSettings(movedToSystemSettings); 559 Settings.Secure.getMovedToSystemSettings(movedToSystemSettings); 560 return movedToSystemSettings; 561 } 562 readOldChecksums(ParcelFileDescriptor oldState)563 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException { 564 long[] stateChecksums = new long[STATE_SIZE]; 565 566 DataInputStream dataInput = new DataInputStream( 567 new FileInputStream(oldState.getFileDescriptor())); 568 569 try { 570 int stateVersion = dataInput.readInt(); 571 if (stateVersion > STATE_VERSION) { 572 // Constrain the maximum state version this backup agent 573 // can handle in case a newer or corrupt backup set existed 574 stateVersion = STATE_VERSION; 575 } 576 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) { 577 stateChecksums[i] = dataInput.readLong(); 578 } 579 } catch (EOFException eof) { 580 // With the default 0 checksum we'll wind up forcing a backup of 581 // any unhandled data sets, which is appropriate. 582 } 583 dataInput.close(); 584 return stateChecksums; 585 } 586 writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)587 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState) 588 throws IOException { 589 DataOutputStream dataOutput = new DataOutputStream( 590 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor()))); 591 592 dataOutput.writeInt(STATE_VERSION); 593 for (int i = 0; i < STATE_SIZE; i++) { 594 dataOutput.writeLong(checksums[i]); 595 } 596 dataOutput.close(); 597 } 598 writeIfChanged(long oldChecksum, String key, byte[] data, BackupDataOutput output)599 private long writeIfChanged(long oldChecksum, String key, byte[] data, 600 BackupDataOutput output) { 601 CRC32 checkSummer = new CRC32(); 602 checkSummer.update(data); 603 long newChecksum = checkSummer.getValue(); 604 if (oldChecksum == newChecksum) { 605 return oldChecksum; 606 } 607 try { 608 if (DEBUG_BACKUP) { 609 Log.v(TAG, "Writing entity " + key + " of size " + data.length); 610 } 611 output.writeEntityHeader(key, data.length); 612 output.writeEntityData(data, data.length); 613 } catch (IOException ioe) { 614 // Bail 615 } 616 return newChecksum; 617 } 618 getSystemSettings()619 private byte[] getSystemSettings() { 620 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null, 621 null, null); 622 try { 623 return extractRelevantValues(cursor, SystemSettings.SETTINGS_TO_BACKUP); 624 } finally { 625 cursor.close(); 626 } 627 } 628 getSecureSettings()629 private byte[] getSecureSettings() { 630 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null, 631 null, null); 632 try { 633 return extractRelevantValues(cursor, SecureSettings.SETTINGS_TO_BACKUP); 634 } finally { 635 cursor.close(); 636 } 637 } 638 getGlobalSettings()639 private byte[] getGlobalSettings() { 640 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null, 641 null, null); 642 try { 643 return extractRelevantValues(cursor, GlobalSettings.SETTINGS_TO_BACKUP); 644 } finally { 645 cursor.close(); 646 } 647 } 648 649 /** 650 * Get names of the settings for which the current value should be preserved during restore. 651 */ getSettingsToPreserveInRestore(Uri settingsUri)652 private Set<String> getSettingsToPreserveInRestore(Uri settingsUri) { 653 if (!FeatureFlagUtils.isEnabled(getBaseContext(), 654 FeatureFlagUtils.SETTINGS_DO_NOT_RESTORE_PRESERVED)) { 655 return Collections.emptySet(); 656 } 657 658 try (Cursor cursor = getContentResolver().query(settingsUri, new String[]{ 659 Settings.NameValueTable.NAME, 660 Settings.NameValueTable.IS_PRESERVED_IN_RESTORE}, 661 /* selection */ null, /* selectionArgs */ null, /* sortOrder */ null)) { 662 663 if (!cursor.moveToFirst()) { 664 Slog.i(TAG, "No settings to be preserved in restore"); 665 return Collections.emptySet(); 666 } 667 668 int nameIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME); 669 int isPreservedIndex = cursor.getColumnIndex( 670 Settings.NameValueTable.IS_PRESERVED_IN_RESTORE); 671 672 Set<String> preservedSettings = new HashSet<>(); 673 while (!cursor.isAfterLast()) { 674 if (Boolean.parseBoolean(cursor.getString(isPreservedIndex))) { 675 preservedSettings.add(getQualifiedKeyForSetting(cursor.getString(nameIndex), 676 settingsUri)); 677 } 678 cursor.moveToNext(); 679 } 680 681 return preservedSettings; 682 } 683 } 684 685 /** 686 * Serialize the owner info and other lock settings 687 */ getLockSettings(@serIdInt int userId)688 private byte[] getLockSettings(@UserIdInt int userId) { 689 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this); 690 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId); 691 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId); 692 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId); 693 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId); 694 final boolean powerButtonInstantlyLocks = 695 lockPatternUtils.getPowerButtonInstantlyLocks(userId); 696 697 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 698 DataOutputStream out = new DataOutputStream(baos); 699 try { 700 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED); 701 out.writeUTF(ownerInfoEnabled ? "1" : "0"); 702 if (ownerInfo != null) { 703 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO); 704 out.writeUTF(ownerInfo != null ? ownerInfo : ""); 705 } 706 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) { 707 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED); 708 out.writeUTF(visiblePatternEnabled ? "1" : "0"); 709 } 710 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) { 711 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS); 712 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0"); 713 } 714 if (lockPatternUtils.isPinEnhancedPrivacyEverChosen(userId)) { 715 out.writeUTF(KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY); 716 out.writeUTF(lockPatternUtils.isPinEnhancedPrivacyEnabled(userId) ? "1" : "0"); 717 } 718 // End marker 719 out.writeUTF(""); 720 out.flush(); 721 } catch (IOException ioe) { 722 } 723 return baos.toByteArray(); 724 } 725 restoreSettings( BackupDataInput data, Uri contentUri, Set<String> movedToGlobal, Set<String> movedToSecure, Set<String> movedToSystem, int blockedSettingsArrayId, Set<String> dynamicBlockList, Set<String> settingsToPreserve)726 private void restoreSettings( 727 BackupDataInput data, 728 Uri contentUri, 729 Set<String> movedToGlobal, 730 Set<String> movedToSecure, 731 Set<String> movedToSystem, 732 int blockedSettingsArrayId, 733 Set<String> dynamicBlockList, 734 Set<String> settingsToPreserve) { 735 byte[] settings = new byte[data.getDataSize()]; 736 try { 737 data.readEntityData(settings, 0, settings.length); 738 } catch (IOException ioe) { 739 Log.e(TAG, "Couldn't read entity data"); 740 return; 741 } 742 restoreSettings( 743 settings, 744 settings.length, 745 contentUri, 746 movedToGlobal, 747 movedToSecure, 748 movedToSystem, 749 blockedSettingsArrayId, 750 dynamicBlockList, 751 settingsToPreserve); 752 } 753 restoreSettings( byte[] settings, int bytes, Uri contentUri, Set<String> movedToGlobal, Set<String> movedToSecure, Set<String> movedToSystem, int blockedSettingsArrayId, Set<String> dynamicBlockList, Set<String> settingsToPreserve)754 private void restoreSettings( 755 byte[] settings, 756 int bytes, 757 Uri contentUri, 758 Set<String> movedToGlobal, 759 Set<String> movedToSecure, 760 Set<String> movedToSystem, 761 int blockedSettingsArrayId, 762 Set<String> dynamicBlockList, 763 Set<String> settingsToPreserve) { 764 restoreSettings( 765 settings, 766 0, 767 bytes, 768 contentUri, 769 movedToGlobal, 770 movedToSecure, 771 movedToSystem, 772 blockedSettingsArrayId, 773 dynamicBlockList, 774 settingsToPreserve); 775 } 776 777 @VisibleForTesting restoreSettings( byte[] settings, int pos, int bytes, Uri contentUri, Set<String> movedToGlobal, Set<String> movedToSecure, Set<String> movedToSystem, int blockedSettingsArrayId, Set<String> dynamicBlockList, Set<String> settingsToPreserve)778 void restoreSettings( 779 byte[] settings, 780 int pos, 781 int bytes, 782 Uri contentUri, 783 Set<String> movedToGlobal, 784 Set<String> movedToSecure, 785 Set<String> movedToSystem, 786 int blockedSettingsArrayId, 787 Set<String> dynamicBlockList, 788 Set<String> settingsToPreserve) { 789 if (DEBUG) { 790 Log.i(TAG, "restoreSettings: " + contentUri); 791 } 792 793 SettingsBackupWhitelist whitelist = getBackupWhitelist(contentUri); 794 795 // Restore only the white list data. 796 final ArrayMap<String, String> cachedEntries = new ArrayMap<>(); 797 ContentValues contentValues = new ContentValues(2); 798 SettingsHelper settingsHelper = mSettingsHelper; 799 ContentResolver cr = getContentResolver(); 800 801 Set<String> blockedSettings = getBlockedSettings(blockedSettingsArrayId); 802 803 for (String key : whitelist.mSettingsWhitelist) { 804 boolean isBlockedBySystem = blockedSettings != null && blockedSettings.contains(key); 805 if (isBlockedBySystem || isBlockedByDynamicList(dynamicBlockList, contentUri, key)) { 806 Log.i( 807 TAG, 808 "Key " 809 + key 810 + " removed from restore by " 811 + (isBlockedBySystem ? "system" : "dynamic") 812 + " block list"); 813 continue; 814 } 815 816 // Filter out Settings.Secure.NAVIGATION_MODE from modified preserve settings. 817 // Let it take part in restore process. See also b/244532342. 818 boolean isSettingPreserved = settingsToPreserve.contains( 819 getQualifiedKeyForSetting(key, contentUri)); 820 if (isSettingPreserved && !Settings.Secure.NAVIGATION_MODE.equals(key)) { 821 Log.i(TAG, "Skipping restore for setting " + key + " as it is marked as " 822 + "preserved"); 823 continue; 824 } 825 826 if (LargeScreenSettings.doNotRestoreIfLargeScreenSetting(key, getBaseContext())) { 827 Log.i(TAG, "Skipping restore for setting " + key + " as the target device " 828 + "is a large screen (i.e tablet or foldable in unfolded state)"); 829 continue; 830 } 831 832 String value = null; 833 boolean hasValueToRestore = false; 834 if (cachedEntries.indexOfKey(key) >= 0) { 835 value = cachedEntries.remove(key); 836 hasValueToRestore = true; 837 } else { 838 // If the value not cached, let us look it up. 839 while (pos < bytes) { 840 int length = readInt(settings, pos); 841 pos += INTEGER_BYTE_COUNT; 842 String dataKey = length >= 0 ? new String(settings, pos, length) : null; 843 pos += length; 844 length = readInt(settings, pos); 845 pos += INTEGER_BYTE_COUNT; 846 String dataValue = null; 847 if (length >= 0) { 848 dataValue = new String(settings, pos, length); 849 pos += length; 850 } 851 if (key.equals(dataKey)) { 852 value = dataValue; 853 hasValueToRestore = true; 854 break; 855 } 856 cachedEntries.put(dataKey, dataValue); 857 } 858 } 859 860 if (!hasValueToRestore) { 861 continue; 862 } 863 864 // only restore the settings that have valid values 865 if (!isValidSettingValue(key, value, whitelist.mSettingsValidators)) { 866 Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass" 867 + " validation, value: " + value); 868 continue; 869 } 870 871 final Uri destination; 872 if (movedToGlobal != null && movedToGlobal.contains(key)) { 873 destination = Settings.Global.CONTENT_URI; 874 } else if (movedToSecure != null && movedToSecure.contains(key)) { 875 destination = Settings.Secure.CONTENT_URI; 876 } else if (movedToSystem != null && movedToSystem.contains(key)) { 877 destination = Settings.System.CONTENT_URI; 878 } else { 879 destination = contentUri; 880 } 881 882 // Value is written to NAVIGATION_MODE_RESTORE to mark navigation mode 883 // has been set before on source device. 884 // See also: b/244532342. 885 if (Settings.Secure.NAVIGATION_MODE.equals(key)) { 886 contentValues.clear(); 887 contentValues.put(Settings.NameValueTable.NAME, 888 Settings.Secure.NAVIGATION_MODE_RESTORE); 889 contentValues.put(Settings.NameValueTable.VALUE, value); 890 cr.insert(destination, contentValues); 891 // Avoid restore original setting if it has been preserved. 892 if (isSettingPreserved) { 893 Log.i(TAG, "Skipping restore for setting navigation_mode " 894 + "as it is marked as preserved"); 895 continue; 896 } 897 } 898 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value, 899 mRestoredFromSdkInt); 900 901 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value); 902 } 903 } 904 905 @VisibleForTesting getBackupWhitelist(Uri contentUri)906 SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) { 907 // Figure out the white list and redirects to the global table. We restore anything 908 // in either the backup whitelist or the legacy-restore whitelist for this table. 909 String[] whitelist; 910 Map<String, Validator> validators = null; 911 if (contentUri.equals(Settings.Secure.CONTENT_URI)) { 912 whitelist = ArrayUtils.concat(String.class, SecureSettings.SETTINGS_TO_BACKUP, 913 Settings.Secure.LEGACY_RESTORE_SETTINGS, 914 DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); 915 validators = SecureSettingsValidators.VALIDATORS; 916 } else if (contentUri.equals(Settings.System.CONTENT_URI)) { 917 whitelist = ArrayUtils.concat(String.class, SystemSettings.SETTINGS_TO_BACKUP, 918 Settings.System.LEGACY_RESTORE_SETTINGS); 919 validators = SystemSettingsValidators.VALIDATORS; 920 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) { 921 whitelist = ArrayUtils.concat(String.class, GlobalSettings.SETTINGS_TO_BACKUP, 922 Settings.Global.LEGACY_RESTORE_SETTINGS); 923 validators = GlobalSettingsValidators.VALIDATORS; 924 } else { 925 throw new IllegalArgumentException("Unknown URI: " + contentUri); 926 } 927 928 return new SettingsBackupWhitelist(whitelist, validators); 929 } 930 isBlockedByDynamicList(Set<String> dynamicBlockList, Uri areaUri, String key)931 private boolean isBlockedByDynamicList(Set<String> dynamicBlockList, Uri areaUri, String key) { 932 String contentKey = Uri.withAppendedPath(areaUri, key).toString(); 933 return dynamicBlockList.contains(contentKey); 934 } 935 936 @VisibleForTesting getQualifiedKeyForSetting(String settingName, Uri settingUri)937 static String getQualifiedKeyForSetting(String settingName, Uri settingUri) { 938 return Uri.withAppendedPath(settingUri, settingName).toString(); 939 } 940 941 // There may be other sources of blocked settings, so I'm separating out this 942 // code to make it easy to modify in the future. 943 @VisibleForTesting getBlockedSettings(int blockedSettingsArrayId)944 protected Set<String> getBlockedSettings(int blockedSettingsArrayId) { 945 String[] blockedSettings = getResources().getStringArray(blockedSettingsArrayId); 946 return new HashSet<>(Arrays.asList(blockedSettings)); 947 } 948 isValidSettingValue(String key, String value, Map<String, Validator> validators)949 private boolean isValidSettingValue(String key, String value, 950 Map<String, Validator> validators) { 951 if (key == null || validators == null) { 952 return false; 953 } 954 Validator validator = validators.get(key); 955 return (validator != null) && validator.validate(value); 956 } 957 958 /** 959 * Restores the owner info enabled and other settings in LockSettings. 960 * 961 * @param buffer 962 * @param nBytes 963 */ restoreLockSettings(@serIdInt int userId, byte[] buffer, int nBytes)964 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) { 965 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this); 966 967 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes); 968 DataInputStream in = new DataInputStream(bais); 969 try { 970 String key; 971 // Read until empty string marker 972 while ((key = in.readUTF()).length() > 0) { 973 final String value = in.readUTF(); 974 if (DEBUG_BACKUP) { 975 Log.v(TAG, "Restoring lock_settings " + key + " = " + value); 976 } 977 switch (key) { 978 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED: 979 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId); 980 break; 981 case KEY_LOCK_SETTINGS_OWNER_INFO: 982 lockPatternUtils.setOwnerInfo(value, userId); 983 break; 984 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED: 985 lockPatternUtils.reportPatternWasChosen(userId); 986 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId); 987 break; 988 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS: 989 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId); 990 break; 991 case KEY_LOCK_SETTINGS_PIN_ENHANCED_PRIVACY: 992 lockPatternUtils.setPinEnhancedPrivacyEnabled("1".equals(value), userId); 993 break; 994 } 995 } 996 in.close(); 997 } catch (IOException ioe) { 998 } 999 } 1000 restoreLockSettings(@serIdInt int userId, BackupDataInput data)1001 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) { 1002 final byte[] settings = new byte[data.getDataSize()]; 1003 try { 1004 data.readEntityData(settings, 0, settings.length); 1005 } catch (IOException ioe) { 1006 Log.e(TAG, "Couldn't read entity data"); 1007 return; 1008 } 1009 restoreLockSettings(userId, settings, settings.length); 1010 } 1011 1012 /** 1013 * Given a cursor and a set of keys, extract the required keys and 1014 * values and write them to a byte array. 1015 * 1016 * @param cursor A cursor with settings data. 1017 * @param settings The settings to extract. 1018 * @return The byte array of extracted values. 1019 */ extractRelevantValues(Cursor cursor, String[] settings)1020 private byte[] extractRelevantValues(Cursor cursor, String[] settings) { 1021 if (!cursor.moveToFirst()) { 1022 Log.e(TAG, "Couldn't read from the cursor"); 1023 return new byte[0]; 1024 } 1025 1026 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME); 1027 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE); 1028 1029 // Obtain the relevant data in a temporary array. 1030 int totalSize = 0; 1031 int backedUpSettingIndex = 0; 1032 final int settingsCount = settings.length; 1033 final byte[][] values = new byte[settingsCount * 2][]; // keys and values 1034 final ArrayMap<String, String> cachedEntries = new ArrayMap<>(); 1035 for (int i = 0; i < settingsCount; i++) { 1036 final String key = settings[i]; 1037 1038 // If the value not cached, let us look it up. 1039 String value = null; 1040 boolean hasValueToBackup = false; 1041 if (cachedEntries.indexOfKey(key) >= 0) { 1042 value = cachedEntries.remove(key); 1043 hasValueToBackup = true; 1044 } else { 1045 while (!cursor.isAfterLast()) { 1046 final String cursorKey = cursor.getString(nameColumnIndex); 1047 final String cursorValue = cursor.getString(valueColumnIndex); 1048 cursor.moveToNext(); 1049 if (key.equals(cursorKey)) { 1050 value = cursorValue; 1051 hasValueToBackup = true; 1052 break; 1053 } 1054 cachedEntries.put(cursorKey, cursorValue); 1055 } 1056 } 1057 1058 if (!hasValueToBackup) { 1059 continue; 1060 } 1061 1062 // Intercept the keys and see if they need special handling 1063 value = mSettingsHelper.onBackupValue(key, value); 1064 1065 // Write the key and value in the intermediary array. 1066 final byte[] keyBytes = key.getBytes(); 1067 totalSize += INTEGER_BYTE_COUNT + keyBytes.length; 1068 values[backedUpSettingIndex * 2] = keyBytes; 1069 1070 final byte[] valueBytes = (value != null) ? value.getBytes() : NULL_VALUE; 1071 totalSize += INTEGER_BYTE_COUNT + valueBytes.length; 1072 values[backedUpSettingIndex * 2 + 1] = valueBytes; 1073 1074 backedUpSettingIndex++; 1075 1076 if (DEBUG) { 1077 Log.d(TAG, "Backed up setting: " + key + "=" + value); 1078 } 1079 } 1080 1081 // Aggregate the result. 1082 byte[] result = new byte[totalSize]; 1083 int pos = 0; 1084 final int keyValuePairCount = backedUpSettingIndex * 2; 1085 for (int i = 0; i < keyValuePairCount; i++) { 1086 final byte[] value = values[i]; 1087 if (value != NULL_VALUE) { 1088 pos = writeInt(result, pos, value.length); 1089 pos = writeBytes(result, pos, value); 1090 } else { 1091 pos = writeInt(result, pos, NULL_SIZE); 1092 } 1093 } 1094 return result; 1095 } 1096 restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes)1097 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) { 1098 if (DEBUG_BACKUP) { 1099 Log.v(TAG, "Applying restored supplicant wifi data"); 1100 } 1101 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes); 1102 } 1103 getSoftAPConfiguration()1104 private byte[] getSoftAPConfiguration() { 1105 return mWifiManager.retrieveSoftApBackupData(); 1106 } 1107 restoreSoftApConfiguration(byte[] data)1108 private void restoreSoftApConfiguration(byte[] data) { 1109 SoftApConfiguration configInCloud = mWifiManager.restoreSoftApBackupData(data); 1110 if (configInCloud != null) { 1111 if (DEBUG) Log.d(TAG, "Successfully unMarshaled SoftApConfiguration "); 1112 // Depending on device hardware, we may need to notify the user of a setting change 1113 SoftApConfiguration storedConfig = mWifiManager.getSoftApConfiguration(); 1114 1115 if (isNeedToNotifyUserConfigurationHasChanged(configInCloud, storedConfig)) { 1116 Log.d(TAG, "restored ap configuration requires a conversion, notify the user" 1117 + ", configInCloud is " + configInCloud + " but storedConfig is " 1118 + storedConfig); 1119 WifiSoftApConfigChangedNotifier.notifyUserOfConfigConversion(this); 1120 } 1121 } 1122 } 1123 isNeedToNotifyUserConfigurationHasChanged(SoftApConfiguration configInCloud, SoftApConfiguration storedConfig)1124 private boolean isNeedToNotifyUserConfigurationHasChanged(SoftApConfiguration configInCloud, 1125 SoftApConfiguration storedConfig) { 1126 // Check if the cloud configuration was modified when restored to the device. 1127 // All elements of the configuration are compared except: 1128 // 1. Persistent randomized MAC address (which is per device) 1129 // 2. The flag indicating whether the configuration is "user modified" 1130 return !(Objects.equals(configInCloud.getWifiSsid(), storedConfig.getWifiSsid()) 1131 && Objects.equals(configInCloud.getBssid(), storedConfig.getBssid()) 1132 && Objects.equals(configInCloud.getPassphrase(), storedConfig.getPassphrase()) 1133 && configInCloud.isHiddenSsid() == storedConfig.isHiddenSsid() 1134 && configInCloud.getChannels().toString().equals( 1135 storedConfig.getChannels().toString()) 1136 && configInCloud.getSecurityType() == storedConfig.getSecurityType() 1137 && configInCloud.getMaxNumberOfClients() == storedConfig.getMaxNumberOfClients() 1138 && configInCloud.isAutoShutdownEnabled() == storedConfig.isAutoShutdownEnabled() 1139 && configInCloud.getShutdownTimeoutMillis() 1140 == storedConfig.getShutdownTimeoutMillis() 1141 && configInCloud.isClientControlByUserEnabled() 1142 == storedConfig.isClientControlByUserEnabled() 1143 && Objects.equals(configInCloud.getBlockedClientList(), 1144 storedConfig.getBlockedClientList()) 1145 && Objects.equals(configInCloud.getAllowedClientList(), 1146 storedConfig.getAllowedClientList()) 1147 && configInCloud.getMacRandomizationSetting() 1148 == storedConfig.getMacRandomizationSetting() 1149 && configInCloud.isBridgedModeOpportunisticShutdownEnabled() 1150 == storedConfig.isBridgedModeOpportunisticShutdownEnabled() 1151 && configInCloud.isIeee80211axEnabled() == storedConfig.isIeee80211axEnabled() 1152 && configInCloud.isIeee80211beEnabled() == storedConfig.isIeee80211beEnabled() 1153 && configInCloud.getBridgedModeOpportunisticShutdownTimeoutMillis() 1154 == storedConfig.getBridgedModeOpportunisticShutdownTimeoutMillis() 1155 && Objects.equals(configInCloud.getVendorElements(), 1156 storedConfig.getVendorElements()) 1157 && Arrays.equals(configInCloud.getAllowedAcsChannels( 1158 SoftApConfiguration.BAND_2GHZ), 1159 storedConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_2GHZ)) 1160 && Arrays.equals(configInCloud.getAllowedAcsChannels( 1161 SoftApConfiguration.BAND_5GHZ), 1162 storedConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_5GHZ)) 1163 && Arrays.equals(configInCloud.getAllowedAcsChannels( 1164 SoftApConfiguration.BAND_6GHZ), 1165 storedConfig.getAllowedAcsChannels(SoftApConfiguration.BAND_6GHZ)) 1166 && configInCloud.getMaxChannelBandwidth() == storedConfig.getMaxChannelBandwidth() 1167 ); 1168 } 1169 getNetworkPolicies()1170 private byte[] getNetworkPolicies() { 1171 NetworkPolicyManager networkPolicyManager = 1172 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE); 1173 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies(); 1174 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1175 if (policies != null && policies.length != 0) { 1176 DataOutputStream out = new DataOutputStream(baos); 1177 try { 1178 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION); 1179 out.writeInt(policies.length); 1180 for (NetworkPolicy policy : policies) { 1181 // We purposefully only backup policies that the user has 1182 // defined; any inferred policies might include 1183 // carrier-protected data that we can't export. 1184 if (policy != null && !policy.inferred) { 1185 byte[] marshaledPolicy = policy.getBytesForBackup(); 1186 out.writeByte(BackupUtils.NOT_NULL); 1187 out.writeInt(marshaledPolicy.length); 1188 out.write(marshaledPolicy); 1189 } else { 1190 out.writeByte(BackupUtils.NULL); 1191 } 1192 } 1193 } catch (IOException ioe) { 1194 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage()); 1195 baos.reset(); 1196 } 1197 } 1198 return baos.toByteArray(); 1199 } 1200 getNewWifiConfigData()1201 private byte[] getNewWifiConfigData() { 1202 return mWifiManager.retrieveBackupData(); 1203 } 1204 restoreNewWifiConfigData(byte[] bytes)1205 private void restoreNewWifiConfigData(byte[] bytes) { 1206 if (DEBUG_BACKUP) { 1207 Log.v(TAG, "Applying restored wifi data"); 1208 } 1209 mWifiManager.restoreBackupData(bytes); 1210 } 1211 restoreNetworkPolicies(byte[] data)1212 private void restoreNetworkPolicies(byte[] data) { 1213 NetworkPolicyManager networkPolicyManager = 1214 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE); 1215 if (data != null && data.length != 0) { 1216 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); 1217 try { 1218 int version = in.readInt(); 1219 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) { 1220 throw new BackupUtils.BadVersionException( 1221 "Unknown Backup Serialization Version"); 1222 } 1223 int length = in.readInt(); 1224 NetworkPolicy[] policies = new NetworkPolicy[length]; 1225 for (int i = 0; i < length; i++) { 1226 byte isNull = in.readByte(); 1227 if (isNull == BackupUtils.NULL) continue; 1228 int byteLength = in.readInt(); 1229 byte[] policyData = new byte[byteLength]; 1230 in.read(policyData, 0, byteLength); 1231 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup( 1232 new DataInputStream(new ByteArrayInputStream(policyData))); 1233 } 1234 // Only set the policies if there was no error in the restore operation 1235 networkPolicyManager.setNetworkPolicies(policies); 1236 } catch (NullPointerException | IOException | BackupUtils.BadVersionException 1237 | DateTimeException e) { 1238 // NPE can be thrown when trying to instantiate a NetworkPolicy 1239 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage()); 1240 } 1241 } 1242 } 1243 1244 @VisibleForTesting getDeviceSpecificConfiguration()1245 byte[] getDeviceSpecificConfiguration() throws IOException { 1246 try (ByteArrayOutputStream os = new ByteArrayOutputStream()) { 1247 writeHeader(os); 1248 os.write(getDeviceSpecificSettings()); 1249 return os.toByteArray(); 1250 } 1251 } 1252 1253 @VisibleForTesting writeHeader(OutputStream os)1254 void writeHeader(OutputStream os) throws IOException { 1255 os.write(toByteArray(DEVICE_SPECIFIC_VERSION)); 1256 os.write(toByteArray(Build.MANUFACTURER)); 1257 os.write(toByteArray(Build.PRODUCT)); 1258 } 1259 getDeviceSpecificSettings()1260 private byte[] getDeviceSpecificSettings() { 1261 try (Cursor cursor = 1262 getContentResolver() 1263 .query(Settings.Secure.CONTENT_URI, PROJECTION, null, null, null)) { 1264 return extractRelevantValues( 1265 cursor, DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP); 1266 } 1267 } 1268 1269 /** 1270 * Restore the device specific settings. 1271 * 1272 * @param data The byte array holding a backed up version of another devices settings. 1273 * @param blockedSettingsArrayId The string array resource holding the settings not to restore. 1274 * @param dynamicBlocklist The dynamic list of settings not to restore fed into this agent. 1275 * @return true if the restore succeeded, false if it was stopped. 1276 */ 1277 @VisibleForTesting restoreDeviceSpecificConfig(byte[] data, int blockedSettingsArrayId, Set<String> dynamicBlocklist, Set<String> preservedSettings)1278 boolean restoreDeviceSpecificConfig(byte[] data, int blockedSettingsArrayId, 1279 Set<String> dynamicBlocklist, Set<String> preservedSettings) { 1280 // We're using an AtomicInteger to wrap the position int and allow called methods to 1281 // modify it. 1282 AtomicInteger pos = new AtomicInteger(0); 1283 if (!isSourceAcceptable(data, pos)) { 1284 return false; 1285 } 1286 1287 Integer originalDensity = getPreviousDensity(); 1288 1289 int dataStart = pos.get(); 1290 restoreSettings( 1291 data, 1292 dataStart, 1293 data.length, 1294 Settings.Secure.CONTENT_URI, 1295 null, 1296 null, 1297 null, 1298 blockedSettingsArrayId, 1299 dynamicBlocklist, 1300 preservedSettings); 1301 1302 updateWindowManagerIfNeeded(originalDensity); 1303 1304 return true; 1305 } 1306 getSimSpecificSettingsData()1307 private byte[] getSimSpecificSettingsData() { 1308 byte[] simSpecificData = new byte[0]; 1309 PackageManager packageManager = getBaseContext().getPackageManager(); 1310 if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) { 1311 SubscriptionManager subManager = SubscriptionManager.from(getBaseContext()); 1312 simSpecificData = subManager.getAllSimSpecificSettingsForBackup(); 1313 Log.i(TAG, "sim specific data of length + " + simSpecificData.length 1314 + " successfully retrieved"); 1315 } 1316 1317 return simSpecificData; 1318 } 1319 restoreSimSpecificSettings(byte[] data)1320 private void restoreSimSpecificSettings(byte[] data) { 1321 PackageManager packageManager = getBaseContext().getPackageManager(); 1322 boolean hasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY); 1323 if (hasTelephony) { 1324 SubscriptionManager subManager = SubscriptionManager.from(getBaseContext()); 1325 subManager.restoreAllSimSpecificSettingsFromBackup(data); 1326 } 1327 } 1328 updateWindowManagerIfNeeded(Integer previousDensity)1329 private void updateWindowManagerIfNeeded(Integer previousDensity) { 1330 int newDensity; 1331 try { 1332 newDensity = getForcedDensity(); 1333 } catch (Settings.SettingNotFoundException e) { 1334 // If there's not density setting we can't perform a change. 1335 return; 1336 } 1337 1338 if (previousDensity == null || previousDensity != newDensity) { 1339 // From nothing to something is a change. 1340 DisplayDensityConfiguration.setForcedDisplayDensity( 1341 Display.DEFAULT_DISPLAY, newDensity); 1342 } 1343 } 1344 getPreviousDensity()1345 private Integer getPreviousDensity() { 1346 try { 1347 return getForcedDensity(); 1348 } catch (Settings.SettingNotFoundException e) { 1349 return null; 1350 } 1351 } 1352 getForcedDensity()1353 private int getForcedDensity() throws Settings.SettingNotFoundException { 1354 return Settings.Secure.getInt(getContentResolver(), Settings.Secure.DISPLAY_DENSITY_FORCED); 1355 } 1356 1357 @VisibleForTesting isSourceAcceptable(byte[] data, AtomicInteger pos)1358 boolean isSourceAcceptable(byte[] data, AtomicInteger pos) { 1359 int version = readInt(data, pos); 1360 if (version > DEVICE_SPECIFIC_VERSION) { 1361 Slog.w(TAG, "Unable to restore device specific information; Backup is too new"); 1362 return false; 1363 } 1364 1365 String sourceManufacturer = readString(data, pos); 1366 if (!Objects.equals(Build.MANUFACTURER, sourceManufacturer)) { 1367 Log.w( 1368 TAG, 1369 "Unable to restore device specific information; Manufacturer mismatch " 1370 + "(\'" 1371 + Build.MANUFACTURER 1372 + "\' and \'" 1373 + sourceManufacturer 1374 + "\')"); 1375 return false; 1376 } 1377 1378 String sourceProduct = readString(data, pos); 1379 if (!Objects.equals(Build.PRODUCT, sourceProduct)) { 1380 Log.w( 1381 TAG, 1382 "Unable to restore device specific information; Product mismatch (\'" 1383 + Build.PRODUCT 1384 + "\' and \'" 1385 + sourceProduct 1386 + "\')"); 1387 return false; 1388 } 1389 1390 return true; 1391 } 1392 1393 @VisibleForTesting toByteArray(String value)1394 static byte[] toByteArray(String value) { 1395 if (value == null) { 1396 return toByteArray(NULL_SIZE); 1397 } 1398 1399 byte[] stringBytes = value.getBytes(); 1400 byte[] sizeAndString = new byte[stringBytes.length + INTEGER_BYTE_COUNT]; 1401 writeInt(sizeAndString, 0, stringBytes.length); 1402 writeBytes(sizeAndString, INTEGER_BYTE_COUNT, stringBytes); 1403 return sizeAndString; 1404 } 1405 1406 @VisibleForTesting toByteArray(int value)1407 static byte[] toByteArray(int value) { 1408 byte[] result = new byte[INTEGER_BYTE_COUNT]; 1409 writeInt(result, 0, value); 1410 return result; 1411 } 1412 readString(byte[] data, AtomicInteger pos)1413 private String readString(byte[] data, AtomicInteger pos) { 1414 int byteCount = readInt(data, pos); 1415 if (byteCount == NULL_SIZE) { 1416 return null; 1417 } 1418 1419 int stringStart = pos.getAndAdd(byteCount); 1420 return new String(data, stringStart, byteCount); 1421 } 1422 1423 /** 1424 * Write an int in BigEndian into the byte array. 1425 * @param out byte array 1426 * @param pos current pos in array 1427 * @param value integer to write 1428 * @return the index after adding the size of an int (4) in bytes. 1429 */ writeInt(byte[] out, int pos, int value)1430 private static int writeInt(byte[] out, int pos, int value) { 1431 out[pos + 0] = (byte) ((value >> 24) & 0xFF); 1432 out[pos + 1] = (byte) ((value >> 16) & 0xFF); 1433 out[pos + 2] = (byte) ((value >> 8) & 0xFF); 1434 out[pos + 3] = (byte) ((value >> 0) & 0xFF); 1435 return pos + INTEGER_BYTE_COUNT; 1436 } 1437 writeBytes(byte[] out, int pos, byte[] value)1438 private static int writeBytes(byte[] out, int pos, byte[] value) { 1439 System.arraycopy(value, 0, out, pos, value.length); 1440 return pos + value.length; 1441 } 1442 readInt(byte[] in, AtomicInteger pos)1443 private int readInt(byte[] in, AtomicInteger pos) { 1444 return readInt(in, pos.getAndAdd(INTEGER_BYTE_COUNT)); 1445 } 1446 readInt(byte[] in, int pos)1447 private int readInt(byte[] in, int pos) { 1448 int result = ((in[pos] & 0xFF) << 24) 1449 | ((in[pos + 1] & 0xFF) << 16) 1450 | ((in[pos + 2] & 0xFF) << 8) 1451 | ((in[pos + 3] & 0xFF) << 0); 1452 return result; 1453 } 1454 1455 /** 1456 * Store the whitelist of settings to be backed up and validators for them. 1457 */ 1458 @VisibleForTesting 1459 static class SettingsBackupWhitelist { 1460 final String[] mSettingsWhitelist; 1461 final Map<String, Validator> mSettingsValidators; 1462 1463 SettingsBackupWhitelist(String[] settingsWhitelist, Map<String, Validator> settingsValidators)1464 SettingsBackupWhitelist(String[] settingsWhitelist, 1465 Map<String, Validator> settingsValidators) { 1466 mSettingsWhitelist = settingsWhitelist; 1467 mSettingsValidators = settingsValidators; 1468 } 1469 } 1470 } 1471