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