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.Nullable; 20 import android.annotation.UserIdInt; 21 import android.app.backup.BackupAgentHelper; 22 import android.app.backup.BackupDataInput; 23 import android.app.backup.BackupDataOutput; 24 import android.app.backup.FullBackupDataOutput; 25 import android.content.ContentResolver; 26 import android.content.ContentValues; 27 import android.content.Context; 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.WifiConfiguration; 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.SettingsValidators.Validator; 39 import android.util.ArrayMap; 40 import android.util.ArraySet; 41 import android.util.BackupUtils; 42 import android.util.Log; 43 44 import com.android.internal.widget.LockPatternUtils; 45 46 import java.io.BufferedOutputStream; 47 import java.io.ByteArrayInputStream; 48 import java.io.ByteArrayOutputStream; 49 import java.io.DataInputStream; 50 import java.io.DataOutputStream; 51 import java.io.EOFException; 52 import java.io.FileInputStream; 53 import java.io.FileOutputStream; 54 import java.io.IOException; 55 import java.time.DateTimeException; 56 import java.util.Arrays; 57 import java.util.HashSet; 58 import java.util.Map; 59 import java.util.zip.CRC32; 60 61 /** 62 * Performs backup and restore of the System and Secure settings. 63 * List of settings that are backed up are stored in the Settings.java file 64 */ 65 public class SettingsBackupAgent extends BackupAgentHelper { 66 private static final boolean DEBUG = false; 67 private static final boolean DEBUG_BACKUP = DEBUG || false; 68 69 private static final byte[] NULL_VALUE = new byte[0]; 70 private static final int NULL_SIZE = -1; 71 72 private static final String KEY_SYSTEM = "system"; 73 private static final String KEY_SECURE = "secure"; 74 private static final String KEY_GLOBAL = "global"; 75 private static final String KEY_LOCALE = "locale"; 76 private static final String KEY_LOCK_SETTINGS = "lock_settings"; 77 private static final String KEY_SOFTAP_CONFIG = "softap_config"; 78 private static final String KEY_NETWORK_POLICIES = "network_policies"; 79 private static final String KEY_WIFI_NEW_CONFIG = "wifi_new_config"; 80 81 // Versioning of the state file. Increment this version 82 // number any time the set of state items is altered. 83 private static final int STATE_VERSION = 7; 84 85 // Versioning of the Network Policies backup payload. 86 private static final int NETWORK_POLICIES_BACKUP_VERSION = 1; 87 88 89 // Slots in the checksum array. Never insert new items in the middle 90 // of this array; new slots must be appended. 91 private static final int STATE_SYSTEM = 0; 92 private static final int STATE_SECURE = 1; 93 private static final int STATE_LOCALE = 2; 94 private static final int STATE_WIFI_SUPPLICANT = 3; 95 private static final int STATE_WIFI_CONFIG = 4; 96 private static final int STATE_GLOBAL = 5; 97 private static final int STATE_LOCK_SETTINGS = 6; 98 private static final int STATE_SOFTAP_CONFIG = 7; 99 private static final int STATE_NETWORK_POLICIES = 8; 100 private static final int STATE_WIFI_NEW_CONFIG = 9; 101 102 private static final int STATE_SIZE = 10; // The current number of state items 103 104 // Number of entries in the checksum array at various version numbers 105 private static final int STATE_SIZES[] = { 106 0, 107 4, // version 1 108 5, // version 2 added STATE_WIFI_CONFIG 109 6, // version 3 added STATE_GLOBAL 110 7, // version 4 added STATE_LOCK_SETTINGS 111 8, // version 5 added STATE_SOFTAP_CONFIG 112 9, // version 6 added STATE_NETWORK_POLICIES 113 STATE_SIZE // version 7 added STATE_WIFI_NEW_CONFIG 114 }; 115 116 // Versioning of the 'full backup' format 117 // Increment this version any time a new item is added 118 private static final int FULL_BACKUP_VERSION = 6; 119 private static final int FULL_BACKUP_ADDED_GLOBAL = 2; // added the "global" entry 120 private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry 121 private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry 122 private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies" 123 private static final int FULL_BACKUP_ADDED_WIFI_NEW = 6; // added "wifi_new_config" entry 124 125 private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE; 126 127 private static final byte[] EMPTY_DATA = new byte[0]; 128 129 private static final String TAG = "SettingsBackupAgent"; 130 131 private static final String[] PROJECTION = { 132 Settings.NameValueTable.NAME, 133 Settings.NameValueTable.VALUE 134 }; 135 136 // the key to store the WIFI data under, should be sorted as last, so restore happens last. 137 // use very late unicode character to quasi-guarantee last sort position. 138 private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI"; 139 private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI"; 140 141 // Keys within the lock settings section 142 private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled"; 143 private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info"; 144 private static final String KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED = 145 "visible_pattern_enabled"; 146 private static final String KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS = 147 "power_button_instantly_locks"; 148 149 // Name of the temporary file we use during full backup/restore. This is 150 // stored in the full-backup tarfile as well, so should not be changed. 151 private static final String STAGE_FILE = "flattened-data"; 152 153 // List of keys that support restore to lower version of the SDK, introduced in Android P 154 private static final ArraySet<String> RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS = 155 new ArraySet<String>(Arrays.asList(new String[] { 156 KEY_NETWORK_POLICIES, 157 KEY_WIFI_NEW_CONFIG, 158 KEY_SYSTEM, 159 KEY_SECURE, 160 KEY_GLOBAL, 161 })); 162 163 private SettingsHelper mSettingsHelper; 164 165 private WifiManager mWifiManager; 166 167 // Version of the SDK that com.android.providers.settings package has been restored from. 168 // Populated in onRestore(). 169 private int mRestoredFromSdkInt; 170 171 @Override onCreate()172 public void onCreate() { 173 if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked"); 174 175 mSettingsHelper = new SettingsHelper(this); 176 mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE); 177 super.onCreate(); 178 } 179 180 @Override onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, ParcelFileDescriptor newState)181 public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data, 182 ParcelFileDescriptor newState) throws IOException { 183 184 byte[] systemSettingsData = getSystemSettings(); 185 byte[] secureSettingsData = getSecureSettings(); 186 byte[] globalSettingsData = getGlobalSettings(); 187 byte[] lockSettingsData = getLockSettings(UserHandle.myUserId()); 188 byte[] locale = mSettingsHelper.getLocaleData(); 189 byte[] softApConfigData = getSoftAPConfiguration(); 190 byte[] netPoliciesData = getNetworkPolicies(); 191 byte[] wifiFullConfigData = getNewWifiConfigData(); 192 193 long[] stateChecksums = readOldChecksums(oldState); 194 195 stateChecksums[STATE_SYSTEM] = 196 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data); 197 stateChecksums[STATE_SECURE] = 198 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data); 199 stateChecksums[STATE_GLOBAL] = 200 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data); 201 stateChecksums[STATE_LOCALE] = 202 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data); 203 stateChecksums[STATE_WIFI_SUPPLICANT] = 0; 204 stateChecksums[STATE_WIFI_CONFIG] = 0; 205 stateChecksums[STATE_LOCK_SETTINGS] = 206 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS, 207 lockSettingsData, data); 208 stateChecksums[STATE_SOFTAP_CONFIG] = 209 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG, 210 softApConfigData, data); 211 stateChecksums[STATE_NETWORK_POLICIES] = 212 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES, 213 netPoliciesData, data); 214 stateChecksums[STATE_WIFI_NEW_CONFIG] = 215 writeIfChanged(stateChecksums[STATE_WIFI_NEW_CONFIG], KEY_WIFI_NEW_CONFIG, 216 wifiFullConfigData, data); 217 218 writeNewChecksums(stateChecksums, newState); 219 } 220 221 @Override onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)222 public void onRestore(BackupDataInput data, int appVersionCode, 223 ParcelFileDescriptor newState) throws IOException { 224 225 if (DEBUG) { 226 Log.d(TAG, "onRestore(): appVersionCode: " + appVersionCode 227 + "; Build.VERSION.SDK_INT: " + Build.VERSION.SDK_INT); 228 } 229 230 boolean overrideRestoreAnyVersion = Settings.Global.getInt(getContentResolver(), 231 Settings.Global.OVERRIDE_SETTINGS_PROVIDER_RESTORE_ANY_VERSION, 0) == 1; 232 if ((appVersionCode > Build.VERSION.SDK_INT) && overrideRestoreAnyVersion) { 233 Log.w(TAG, "Ignoring restore from API" + appVersionCode + " to API" 234 + Build.VERSION.SDK_INT + " due to settings flag override."); 235 return; 236 } 237 238 // versionCode of com.android.providers.settings corresponds to SDK_INT 239 mRestoredFromSdkInt = appVersionCode; 240 241 HashSet<String> movedToGlobal = new HashSet<String>(); 242 Settings.System.getMovedToGlobalSettings(movedToGlobal); 243 Settings.Secure.getMovedToGlobalSettings(movedToGlobal); 244 byte[] restoredWifiSupplicantData = null; 245 byte[] restoredWifiIpConfigData = null; 246 247 while (data.readNextHeader()) { 248 final String key = data.getKey(); 249 final int size = data.getDataSize(); 250 251 // bail out of restoring from higher SDK_INT version for unsupported keys 252 if (appVersionCode > Build.VERSION.SDK_INT 253 && !RESTORE_FROM_HIGHER_SDK_INT_SUPPORTED_KEYS.contains(key)) { 254 Log.w(TAG, "Not restoring unrecognized key '" 255 + key + "' from future version " + appVersionCode); 256 data.skipEntityData(); 257 continue; 258 } 259 260 switch (key) { 261 case KEY_SYSTEM : 262 restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal); 263 mSettingsHelper.applyAudioSettings(); 264 break; 265 266 case KEY_SECURE : 267 restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal); 268 break; 269 270 case KEY_GLOBAL : 271 restoreSettings(data, Settings.Global.CONTENT_URI, null); 272 break; 273 274 case KEY_WIFI_SUPPLICANT : 275 restoredWifiSupplicantData = new byte[size]; 276 data.readEntityData(restoredWifiSupplicantData, 0, size); 277 break; 278 279 case KEY_LOCALE : 280 byte[] localeData = new byte[size]; 281 data.readEntityData(localeData, 0, size); 282 mSettingsHelper.setLocaleData(localeData, size); 283 break; 284 285 case KEY_WIFI_CONFIG : 286 restoredWifiIpConfigData = new byte[size]; 287 data.readEntityData(restoredWifiIpConfigData, 0, size); 288 break; 289 290 case KEY_LOCK_SETTINGS : 291 restoreLockSettings(UserHandle.myUserId(), data); 292 break; 293 294 case KEY_SOFTAP_CONFIG : 295 byte[] softapData = new byte[size]; 296 data.readEntityData(softapData, 0, size); 297 restoreSoftApConfiguration(softapData); 298 break; 299 300 case KEY_NETWORK_POLICIES: 301 byte[] netPoliciesData = new byte[size]; 302 data.readEntityData(netPoliciesData, 0, size); 303 restoreNetworkPolicies(netPoliciesData); 304 break; 305 306 case KEY_WIFI_NEW_CONFIG: 307 byte[] restoredWifiNewConfigData = new byte[size]; 308 data.readEntityData(restoredWifiNewConfigData, 0, size); 309 restoreNewWifiConfigData(restoredWifiNewConfigData); 310 break; 311 312 default : 313 data.skipEntityData(); 314 315 } 316 } 317 318 // Do this at the end so that we also pull in the ipconfig data. 319 if (restoredWifiSupplicantData != null) { 320 restoreSupplicantWifiConfigData( 321 restoredWifiSupplicantData, restoredWifiIpConfigData); 322 } 323 } 324 325 @Override onFullBackup(FullBackupDataOutput data)326 public void onFullBackup(FullBackupDataOutput data) throws IOException { 327 // Full backup of SettingsBackupAgent support was removed in Android P. If you want to adb 328 // backup com.android.providers.settings package use \"-keyvalue\" flag. 329 // Full restore of SettingsBackupAgent is still available for backwards compatibility. 330 } 331 332 @Override onRestoreFile(ParcelFileDescriptor data, long size, int type, String domain, String relpath, long mode, long mtime)333 public void onRestoreFile(ParcelFileDescriptor data, long size, 334 int type, String domain, String relpath, long mode, long mtime) 335 throws IOException { 336 if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked"); 337 // Our data is actually a blob of flattened settings data identical to that 338 // produced during incremental backups. Just unpack and apply it all in 339 // turn. 340 FileInputStream instream = new FileInputStream(data.getFileDescriptor()); 341 DataInputStream in = new DataInputStream(instream); 342 343 int version = in.readInt(); 344 if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version); 345 if (version <= FULL_BACKUP_VERSION) { 346 // Generate the moved-to-global lookup table 347 HashSet<String> movedToGlobal = new HashSet<String>(); 348 Settings.System.getMovedToGlobalSettings(movedToGlobal); 349 Settings.Secure.getMovedToGlobalSettings(movedToGlobal); 350 351 // system settings data first 352 int nBytes = in.readInt(); 353 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data"); 354 byte[] buffer = new byte[nBytes]; 355 in.readFully(buffer, 0, nBytes); 356 restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal); 357 358 // secure settings 359 nBytes = in.readInt(); 360 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data"); 361 if (nBytes > buffer.length) buffer = new byte[nBytes]; 362 in.readFully(buffer, 0, nBytes); 363 restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal); 364 365 // Global only if sufficiently new 366 if (version >= FULL_BACKUP_ADDED_GLOBAL) { 367 nBytes = in.readInt(); 368 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data"); 369 if (nBytes > buffer.length) buffer = new byte[nBytes]; 370 in.readFully(buffer, 0, nBytes); 371 movedToGlobal.clear(); // no redirection; this *is* the global namespace 372 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal); 373 } 374 375 // locale 376 nBytes = in.readInt(); 377 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data"); 378 if (nBytes > buffer.length) buffer = new byte[nBytes]; 379 in.readFully(buffer, 0, nBytes); 380 mSettingsHelper.setLocaleData(buffer, nBytes); 381 382 // Restore older backups performing the necessary migrations. 383 if (version < FULL_BACKUP_ADDED_WIFI_NEW) { 384 // wifi supplicant 385 int supplicant_size = in.readInt(); 386 if (DEBUG_BACKUP) Log.d(TAG, supplicant_size + " bytes of wifi supplicant data"); 387 byte[] supplicant_buffer = new byte[supplicant_size]; 388 in.readFully(supplicant_buffer, 0, supplicant_size); 389 390 // ip config 391 int ipconfig_size = in.readInt(); 392 if (DEBUG_BACKUP) Log.d(TAG, ipconfig_size + " bytes of ip config data"); 393 byte[] ipconfig_buffer = new byte[ipconfig_size]; 394 in.readFully(ipconfig_buffer, 0, nBytes); 395 restoreSupplicantWifiConfigData(supplicant_buffer, ipconfig_buffer); 396 } 397 398 if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) { 399 nBytes = in.readInt(); 400 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data"); 401 if (nBytes > buffer.length) buffer = new byte[nBytes]; 402 if (nBytes > 0) { 403 in.readFully(buffer, 0, nBytes); 404 restoreLockSettings(UserHandle.myUserId(), buffer, nBytes); 405 } 406 } 407 // softap config 408 if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) { 409 nBytes = in.readInt(); 410 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data"); 411 if (nBytes > buffer.length) buffer = new byte[nBytes]; 412 if (nBytes > 0) { 413 in.readFully(buffer, 0, nBytes); 414 restoreSoftApConfiguration(buffer); 415 } 416 } 417 // network policies 418 if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) { 419 nBytes = in.readInt(); 420 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data"); 421 if (nBytes > buffer.length) buffer = new byte[nBytes]; 422 if (nBytes > 0) { 423 in.readFully(buffer, 0, nBytes); 424 restoreNetworkPolicies(buffer); 425 } 426 } 427 // Restore full wifi config data 428 if (version >= FULL_BACKUP_ADDED_WIFI_NEW) { 429 nBytes = in.readInt(); 430 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of full wifi config data"); 431 if (nBytes > buffer.length) buffer = new byte[nBytes]; 432 in.readFully(buffer, 0, nBytes); 433 restoreNewWifiConfigData(buffer); 434 } 435 436 if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete."); 437 } else { 438 data.close(); 439 throw new IOException("Invalid file schema"); 440 } 441 } 442 readOldChecksums(ParcelFileDescriptor oldState)443 private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException { 444 long[] stateChecksums = new long[STATE_SIZE]; 445 446 DataInputStream dataInput = new DataInputStream( 447 new FileInputStream(oldState.getFileDescriptor())); 448 449 try { 450 int stateVersion = dataInput.readInt(); 451 if (stateVersion > STATE_VERSION) { 452 // Constrain the maximum state version this backup agent 453 // can handle in case a newer or corrupt backup set existed 454 stateVersion = STATE_VERSION; 455 } 456 for (int i = 0; i < STATE_SIZES[stateVersion]; i++) { 457 stateChecksums[i] = dataInput.readLong(); 458 } 459 } catch (EOFException eof) { 460 // With the default 0 checksum we'll wind up forcing a backup of 461 // any unhandled data sets, which is appropriate. 462 } 463 dataInput.close(); 464 return stateChecksums; 465 } 466 writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)467 private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState) 468 throws IOException { 469 DataOutputStream dataOutput = new DataOutputStream( 470 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor()))); 471 472 dataOutput.writeInt(STATE_VERSION); 473 for (int i = 0; i < STATE_SIZE; i++) { 474 dataOutput.writeLong(checksums[i]); 475 } 476 dataOutput.close(); 477 } 478 writeIfChanged(long oldChecksum, String key, byte[] data, BackupDataOutput output)479 private long writeIfChanged(long oldChecksum, String key, byte[] data, 480 BackupDataOutput output) { 481 CRC32 checkSummer = new CRC32(); 482 checkSummer.update(data); 483 long newChecksum = checkSummer.getValue(); 484 if (oldChecksum == newChecksum) { 485 return oldChecksum; 486 } 487 try { 488 if (DEBUG_BACKUP) { 489 Log.v(TAG, "Writing entity " + key + " of size " + data.length); 490 } 491 output.writeEntityHeader(key, data.length); 492 output.writeEntityData(data, data.length); 493 } catch (IOException ioe) { 494 // Bail 495 } 496 return newChecksum; 497 } 498 getSystemSettings()499 private byte[] getSystemSettings() { 500 Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null, 501 null, null); 502 try { 503 return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP); 504 } finally { 505 cursor.close(); 506 } 507 } 508 getSecureSettings()509 private byte[] getSecureSettings() { 510 Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null, 511 null, null); 512 try { 513 return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP); 514 } finally { 515 cursor.close(); 516 } 517 } 518 getGlobalSettings()519 private byte[] getGlobalSettings() { 520 Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null, 521 null, null); 522 try { 523 return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP); 524 } finally { 525 cursor.close(); 526 } 527 } 528 529 /** 530 * Serialize the owner info and other lock settings 531 */ getLockSettings(@serIdInt int userId)532 private byte[] getLockSettings(@UserIdInt int userId) { 533 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this); 534 final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(userId); 535 final String ownerInfo = lockPatternUtils.getOwnerInfo(userId); 536 final boolean lockPatternEnabled = lockPatternUtils.isLockPatternEnabled(userId); 537 final boolean visiblePatternEnabled = lockPatternUtils.isVisiblePatternEnabled(userId); 538 final boolean powerButtonInstantlyLocks = 539 lockPatternUtils.getPowerButtonInstantlyLocks(userId); 540 541 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 542 DataOutputStream out = new DataOutputStream(baos); 543 try { 544 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED); 545 out.writeUTF(ownerInfoEnabled ? "1" : "0"); 546 if (ownerInfo != null) { 547 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO); 548 out.writeUTF(ownerInfo != null ? ownerInfo : ""); 549 } 550 if (lockPatternUtils.isVisiblePatternEverChosen(userId)) { 551 out.writeUTF(KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED); 552 out.writeUTF(visiblePatternEnabled ? "1" : "0"); 553 } 554 if (lockPatternUtils.isPowerButtonInstantlyLocksEverChosen(userId)) { 555 out.writeUTF(KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS); 556 out.writeUTF(powerButtonInstantlyLocks ? "1" : "0"); 557 } 558 // End marker 559 out.writeUTF(""); 560 out.flush(); 561 } catch (IOException ioe) { 562 } 563 return baos.toByteArray(); 564 } 565 restoreSettings(BackupDataInput data, Uri contentUri, HashSet<String> movedToGlobal)566 private void restoreSettings(BackupDataInput data, Uri contentUri, 567 HashSet<String> movedToGlobal) { 568 byte[] settings = new byte[data.getDataSize()]; 569 try { 570 data.readEntityData(settings, 0, settings.length); 571 } catch (IOException ioe) { 572 Log.e(TAG, "Couldn't read entity data"); 573 return; 574 } 575 restoreSettings(settings, settings.length, contentUri, movedToGlobal); 576 } 577 restoreSettings(byte[] settings, int bytes, Uri contentUri, HashSet<String> movedToGlobal)578 private void restoreSettings(byte[] settings, int bytes, Uri contentUri, 579 HashSet<String> movedToGlobal) { 580 if (DEBUG) { 581 Log.i(TAG, "restoreSettings: " + contentUri); 582 } 583 584 // Figure out the white list and redirects to the global table. We restore anything 585 // in either the backup whitelist or the legacy-restore whitelist for this table. 586 final String[] whitelist; 587 Map<String, Validator> validators = null; 588 if (contentUri.equals(Settings.Secure.CONTENT_URI)) { 589 whitelist = concat(Settings.Secure.SETTINGS_TO_BACKUP, 590 Settings.Secure.LEGACY_RESTORE_SETTINGS); 591 validators = Settings.Secure.VALIDATORS; 592 } else if (contentUri.equals(Settings.System.CONTENT_URI)) { 593 whitelist = concat(Settings.System.SETTINGS_TO_BACKUP, 594 Settings.System.LEGACY_RESTORE_SETTINGS); 595 validators = Settings.System.VALIDATORS; 596 } else if (contentUri.equals(Settings.Global.CONTENT_URI)) { 597 whitelist = concat(Settings.Global.SETTINGS_TO_BACKUP, 598 Settings.Global.LEGACY_RESTORE_SETTINGS); 599 validators = Settings.Global.VALIDATORS; 600 } else { 601 throw new IllegalArgumentException("Unknown URI: " + contentUri); 602 } 603 604 // Restore only the white list data. 605 int pos = 0; 606 final ArrayMap<String, String> cachedEntries = new ArrayMap<>(); 607 ContentValues contentValues = new ContentValues(2); 608 SettingsHelper settingsHelper = mSettingsHelper; 609 ContentResolver cr = getContentResolver(); 610 611 final int whiteListSize = whitelist.length; 612 for (int i = 0; i < whiteListSize; i++) { 613 String key = whitelist[i]; 614 615 String value = null; 616 boolean hasValueToRestore = false; 617 if (cachedEntries.indexOfKey(key) >= 0) { 618 value = cachedEntries.remove(key); 619 hasValueToRestore = true; 620 } else { 621 // If the value not cached, let us look it up. 622 while (pos < bytes) { 623 int length = readInt(settings, pos); 624 pos += INTEGER_BYTE_COUNT; 625 String dataKey = length >= 0 ? new String(settings, pos, length) : null; 626 pos += length; 627 length = readInt(settings, pos); 628 pos += INTEGER_BYTE_COUNT; 629 String dataValue = null; 630 if (length >= 0) { 631 dataValue = new String(settings, pos, length); 632 pos += length; 633 } 634 if (key.equals(dataKey)) { 635 value = dataValue; 636 hasValueToRestore = true; 637 break; 638 } 639 cachedEntries.put(dataKey, dataValue); 640 } 641 } 642 643 if (!hasValueToRestore) { 644 continue; 645 } 646 647 // only restore the settings that have valid values 648 if (!isValidSettingValue(key, value, validators)) { 649 Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass" 650 + " validation, value: " + value); 651 continue; 652 } 653 654 final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key)) 655 ? Settings.Global.CONTENT_URI 656 : contentUri; 657 settingsHelper.restoreValue(this, cr, contentValues, destination, key, value, 658 mRestoredFromSdkInt); 659 660 if (DEBUG) { 661 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value); 662 } 663 } 664 } 665 isValidSettingValue(String key, String value, Map<String, Validator> validators)666 private boolean isValidSettingValue(String key, String value, 667 Map<String, Validator> validators) { 668 if (key == null || validators == null) { 669 return false; 670 } 671 Validator validator = validators.get(key); 672 return (validator != null) && validator.validate(value); 673 } 674 concat(String[] first, @Nullable String[] second)675 private final String[] concat(String[] first, @Nullable String[] second) { 676 if (second == null || second.length == 0) { 677 return first; 678 } 679 final int firstLen = first.length; 680 final int secondLen = second.length; 681 String[] both = new String[firstLen + secondLen]; 682 System.arraycopy(first, 0, both, 0, firstLen); 683 System.arraycopy(second, 0, both, firstLen, secondLen); 684 return both; 685 } 686 687 /** 688 * Restores the owner info enabled and other settings in LockSettings. 689 * 690 * @param buffer 691 * @param nBytes 692 */ restoreLockSettings(@serIdInt int userId, byte[] buffer, int nBytes)693 private void restoreLockSettings(@UserIdInt int userId, byte[] buffer, int nBytes) { 694 final LockPatternUtils lockPatternUtils = new LockPatternUtils(this); 695 696 ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes); 697 DataInputStream in = new DataInputStream(bais); 698 try { 699 String key; 700 // Read until empty string marker 701 while ((key = in.readUTF()).length() > 0) { 702 final String value = in.readUTF(); 703 if (DEBUG_BACKUP) { 704 Log.v(TAG, "Restoring lock_settings " + key + " = " + value); 705 } 706 switch (key) { 707 case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED: 708 lockPatternUtils.setOwnerInfoEnabled("1".equals(value), userId); 709 break; 710 case KEY_LOCK_SETTINGS_OWNER_INFO: 711 lockPatternUtils.setOwnerInfo(value, userId); 712 break; 713 case KEY_LOCK_SETTINGS_VISIBLE_PATTERN_ENABLED: 714 lockPatternUtils.reportPatternWasChosen(userId); 715 lockPatternUtils.setVisiblePatternEnabled("1".equals(value), userId); 716 break; 717 case KEY_LOCK_SETTINGS_POWER_BUTTON_INSTANTLY_LOCKS: 718 lockPatternUtils.setPowerButtonInstantlyLocks("1".equals(value), userId); 719 break; 720 } 721 } 722 in.close(); 723 } catch (IOException ioe) { 724 } 725 } 726 restoreLockSettings(@serIdInt int userId, BackupDataInput data)727 private void restoreLockSettings(@UserIdInt int userId, BackupDataInput data) { 728 final byte[] settings = new byte[data.getDataSize()]; 729 try { 730 data.readEntityData(settings, 0, settings.length); 731 } catch (IOException ioe) { 732 Log.e(TAG, "Couldn't read entity data"); 733 return; 734 } 735 restoreLockSettings(userId, settings, settings.length); 736 } 737 738 /** 739 * Given a cursor and a set of keys, extract the required keys and 740 * values and write them to a byte array. 741 * 742 * @param cursor A cursor with settings data. 743 * @param settings The settings to extract. 744 * @return The byte array of extracted values. 745 */ extractRelevantValues(Cursor cursor, String[] settings)746 private byte[] extractRelevantValues(Cursor cursor, String[] settings) { 747 if (!cursor.moveToFirst()) { 748 Log.e(TAG, "Couldn't read from the cursor"); 749 return new byte[0]; 750 } 751 752 final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME); 753 final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE); 754 755 // Obtain the relevant data in a temporary array. 756 int totalSize = 0; 757 int backedUpSettingIndex = 0; 758 final int settingsCount = settings.length; 759 final byte[][] values = new byte[settingsCount * 2][]; // keys and values 760 final ArrayMap<String, String> cachedEntries = new ArrayMap<>(); 761 for (int i = 0; i < settingsCount; i++) { 762 final String key = settings[i]; 763 764 // If the value not cached, let us look it up. 765 String value = null; 766 boolean hasValueToBackup = false; 767 if (cachedEntries.indexOfKey(key) >= 0) { 768 value = cachedEntries.remove(key); 769 hasValueToBackup = true; 770 } else { 771 while (!cursor.isAfterLast()) { 772 final String cursorKey = cursor.getString(nameColumnIndex); 773 final String cursorValue = cursor.getString(valueColumnIndex); 774 cursor.moveToNext(); 775 if (key.equals(cursorKey)) { 776 value = cursorValue; 777 hasValueToBackup = true; 778 break; 779 } 780 cachedEntries.put(cursorKey, cursorValue); 781 } 782 } 783 784 if (!hasValueToBackup) { 785 continue; 786 } 787 788 // Intercept the keys and see if they need special handling 789 value = mSettingsHelper.onBackupValue(key, value); 790 791 // Write the key and value in the intermediary array. 792 final byte[] keyBytes = key.getBytes(); 793 totalSize += INTEGER_BYTE_COUNT + keyBytes.length; 794 values[backedUpSettingIndex * 2] = keyBytes; 795 796 final byte[] valueBytes = (value != null) ? value.getBytes() : NULL_VALUE; 797 totalSize += INTEGER_BYTE_COUNT + valueBytes.length; 798 values[backedUpSettingIndex * 2 + 1] = valueBytes; 799 800 backedUpSettingIndex++; 801 802 if (DEBUG) { 803 Log.d(TAG, "Backed up setting: " + key + "=" + value); 804 } 805 } 806 807 // Aggregate the result. 808 byte[] result = new byte[totalSize]; 809 int pos = 0; 810 final int keyValuePairCount = backedUpSettingIndex * 2; 811 for (int i = 0; i < keyValuePairCount; i++) { 812 final byte[] value = values[i]; 813 if (value != NULL_VALUE) { 814 pos = writeInt(result, pos, value.length); 815 pos = writeBytes(result, pos, value); 816 } else { 817 pos = writeInt(result, pos, NULL_SIZE); 818 } 819 } 820 return result; 821 } 822 restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes)823 private void restoreSupplicantWifiConfigData(byte[] supplicant_bytes, byte[] ipconfig_bytes) { 824 if (DEBUG_BACKUP) { 825 Log.v(TAG, "Applying restored supplicant wifi data"); 826 } 827 mWifiManager.restoreSupplicantBackupData(supplicant_bytes, ipconfig_bytes); 828 } 829 getSoftAPConfiguration()830 private byte[] getSoftAPConfiguration() { 831 try { 832 return mWifiManager.getWifiApConfiguration().getBytesForBackup(); 833 } catch (IOException ioe) { 834 Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage()); 835 return new byte[0]; 836 } 837 } 838 restoreSoftApConfiguration(byte[] data)839 private void restoreSoftApConfiguration(byte[] data) { 840 try { 841 WifiConfiguration config = WifiConfiguration 842 .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data))); 843 if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration "); 844 int originalApBand = config.apBand; 845 mWifiManager.setWifiApConfiguration(config); 846 847 // Depending on device hardware, we may need to notify the user of a setting change for 848 // the apBand preference 849 boolean dualMode = mWifiManager.isDualModeSupported(); 850 int storedApBand = mWifiManager.getWifiApConfiguration().apBand; 851 if (dualMode) { 852 if (storedApBand != originalApBand) { 853 Log.d(TAG, "restored ap configuration requires a conversion, notify the user"); 854 mWifiManager.notifyUserOfApBandConversion(); 855 } 856 } 857 } catch (IOException | BackupUtils.BadVersionException e) { 858 Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage()); 859 } 860 } 861 getNetworkPolicies()862 private byte[] getNetworkPolicies() { 863 NetworkPolicyManager networkPolicyManager = 864 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE); 865 NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies(); 866 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 867 if (policies != null && policies.length != 0) { 868 DataOutputStream out = new DataOutputStream(baos); 869 try { 870 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION); 871 out.writeInt(policies.length); 872 for (NetworkPolicy policy : policies) { 873 // We purposefully only backup policies that the user has 874 // defined; any inferred policies might include 875 // carrier-protected data that we can't export. 876 if (policy != null && !policy.inferred) { 877 byte[] marshaledPolicy = policy.getBytesForBackup(); 878 out.writeByte(BackupUtils.NOT_NULL); 879 out.writeInt(marshaledPolicy.length); 880 out.write(marshaledPolicy); 881 } else { 882 out.writeByte(BackupUtils.NULL); 883 } 884 } 885 } catch (IOException ioe) { 886 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage()); 887 baos.reset(); 888 } 889 } 890 return baos.toByteArray(); 891 } 892 getNewWifiConfigData()893 private byte[] getNewWifiConfigData() { 894 return mWifiManager.retrieveBackupData(); 895 } 896 restoreNewWifiConfigData(byte[] bytes)897 private void restoreNewWifiConfigData(byte[] bytes) { 898 if (DEBUG_BACKUP) { 899 Log.v(TAG, "Applying restored wifi data"); 900 } 901 mWifiManager.restoreBackupData(bytes); 902 } 903 restoreNetworkPolicies(byte[] data)904 private void restoreNetworkPolicies(byte[] data) { 905 NetworkPolicyManager networkPolicyManager = 906 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE); 907 if (data != null && data.length != 0) { 908 DataInputStream in = new DataInputStream(new ByteArrayInputStream(data)); 909 try { 910 int version = in.readInt(); 911 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) { 912 throw new BackupUtils.BadVersionException( 913 "Unknown Backup Serialization Version"); 914 } 915 int length = in.readInt(); 916 NetworkPolicy[] policies = new NetworkPolicy[length]; 917 for (int i = 0; i < length; i++) { 918 byte isNull = in.readByte(); 919 if (isNull == BackupUtils.NULL) continue; 920 int byteLength = in.readInt(); 921 byte[] policyData = new byte[byteLength]; 922 in.read(policyData, 0, byteLength); 923 policies[i] = NetworkPolicy.getNetworkPolicyFromBackup( 924 new DataInputStream(new ByteArrayInputStream(policyData))); 925 } 926 // Only set the policies if there was no error in the restore operation 927 networkPolicyManager.setNetworkPolicies(policies); 928 } catch (NullPointerException | IOException | BackupUtils.BadVersionException 929 | DateTimeException e) { 930 // NPE can be thrown when trying to instantiate a NetworkPolicy 931 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage()); 932 } 933 } 934 } 935 936 /** 937 * Write an int in BigEndian into the byte array. 938 * @param out byte array 939 * @param pos current pos in array 940 * @param value integer to write 941 * @return the index after adding the size of an int (4) in bytes. 942 */ writeInt(byte[] out, int pos, int value)943 private int writeInt(byte[] out, int pos, int value) { 944 out[pos + 0] = (byte) ((value >> 24) & 0xFF); 945 out[pos + 1] = (byte) ((value >> 16) & 0xFF); 946 out[pos + 2] = (byte) ((value >> 8) & 0xFF); 947 out[pos + 3] = (byte) ((value >> 0) & 0xFF); 948 return pos + INTEGER_BYTE_COUNT; 949 } 950 writeBytes(byte[] out, int pos, byte[] value)951 private int writeBytes(byte[] out, int pos, byte[] value) { 952 System.arraycopy(value, 0, out, pos, value.length); 953 return pos + value.length; 954 } 955 readInt(byte[] in, int pos)956 private int readInt(byte[] in, int pos) { 957 int result = ((in[pos] & 0xFF) << 24) 958 | ((in[pos + 1] & 0xFF) << 16) 959 | ((in[pos + 2] & 0xFF) << 8) 960 | ((in[pos + 3] & 0xFF) << 0); 961 return result; 962 } 963 } 964