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