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