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