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