• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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