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