Home | History | Annotate | Download | only in settings
      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.WifiConfiguration.KeyMgmt;
     32 import android.net.wifi.WifiManager;
     33 import android.os.FileUtils;
     34 import android.os.Handler;
     35 import android.os.ParcelFileDescriptor;
     36 import android.os.Process;
     37 import android.os.UserHandle;
     38 import android.provider.Settings;
     39 import android.util.BackupUtils;
     40 import android.util.Log;
     41 
     42 import com.android.internal.widget.LockPatternUtils;
     43 
     44 import libcore.io.IoUtils;
     45 
     46 import java.io.BufferedOutputStream;
     47 import java.io.BufferedReader;
     48 import java.io.BufferedWriter;
     49 import java.io.ByteArrayInputStream;
     50 import java.io.ByteArrayOutputStream;
     51 import java.io.CharArrayReader;
     52 import java.io.DataInputStream;
     53 import java.io.DataOutputStream;
     54 import java.io.EOFException;
     55 import java.io.File;
     56 import java.io.FileInputStream;
     57 import java.io.FileOutputStream;
     58 import java.io.FileReader;
     59 import java.io.FileWriter;
     60 import java.io.IOException;
     61 import java.io.InputStream;
     62 import java.io.OutputStream;
     63 import java.io.OutputStreamWriter;
     64 import java.io.Writer;
     65 import java.util.ArrayList;
     66 import java.util.BitSet;
     67 import java.util.HashMap;
     68 import java.util.HashSet;
     69 import java.util.List;
     70 import java.util.Map;
     71 import java.util.Objects;
     72 import java.util.zip.CRC32;
     73 
     74 /**
     75  * Performs backup and restore of the System and Secure settings.
     76  * List of settings that are backed up are stored in the Settings.java file
     77  */
     78 public class SettingsBackupAgent extends BackupAgentHelper {
     79     private static final boolean DEBUG = false;
     80     private static final boolean DEBUG_BACKUP = DEBUG || false;
     81 
     82     private static final String KEY_SYSTEM = "system";
     83     private static final String KEY_SECURE = "secure";
     84     private static final String KEY_GLOBAL = "global";
     85     private static final String KEY_LOCALE = "locale";
     86     private static final String KEY_LOCK_SETTINGS = "lock_settings";
     87     private static final String KEY_SOFTAP_CONFIG = "softap_config";
     88     private static final String KEY_NETWORK_POLICIES = "network_policies";
     89 
     90     // Versioning of the state file.  Increment this version
     91     // number any time the set of state items is altered.
     92     private static final int STATE_VERSION = 6;
     93 
     94     // Versioning of the Network Policies backup payload.
     95     private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
     96 
     97 
     98     // Slots in the checksum array.  Never insert new items in the middle
     99     // of this array; new slots must be appended.
    100     private static final int STATE_SYSTEM           = 0;
    101     private static final int STATE_SECURE           = 1;
    102     private static final int STATE_LOCALE           = 2;
    103     private static final int STATE_WIFI_SUPPLICANT  = 3;
    104     private static final int STATE_WIFI_CONFIG      = 4;
    105     private static final int STATE_GLOBAL           = 5;
    106     private static final int STATE_LOCK_SETTINGS    = 6;
    107     private static final int STATE_SOFTAP_CONFIG    = 7;
    108     private static final int STATE_NETWORK_POLICIES = 8;
    109 
    110     private static final int STATE_SIZE             = 9; // The current number of state items
    111 
    112     // Number of entries in the checksum array at various version numbers
    113     private static final int STATE_SIZES[] = {
    114             0,
    115             4,              // version 1
    116             5,              // version 2 added STATE_WIFI_CONFIG
    117             6,              // version 3 added STATE_GLOBAL
    118             7,              // version 4 added STATE_LOCK_SETTINGS
    119             8,              // version 5 added STATE_SOFTAP_CONFIG
    120             STATE_SIZE      // version 6 added STATE_NETWORK_POLICIES
    121     };
    122 
    123     // Versioning of the 'full backup' format
    124     // Increment this version any time a new item is added
    125     private static final int FULL_BACKUP_VERSION = 5;
    126     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
    127     private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
    128     private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
    129     private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
    130 
    131     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
    132 
    133     private static final byte[] EMPTY_DATA = new byte[0];
    134 
    135     private static final String TAG = "SettingsBackupAgent";
    136 
    137     private static final String[] PROJECTION = {
    138             Settings.NameValueTable.NAME,
    139             Settings.NameValueTable.VALUE
    140     };
    141 
    142     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
    143     private static final String FILE_WIFI_SUPPLICANT_TEMPLATE =
    144             "/system/etc/wifi/wpa_supplicant.conf";
    145 
    146     // the key to store the WIFI data under, should be sorted as last, so restore happens last.
    147     // use very late unicode character to quasi-guarantee last sort position.
    148     private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
    149     private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
    150 
    151     // Keys within the lock settings section
    152     private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
    153     private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
    154 
    155     // Name of the temporary file we use during full backup/restore.  This is
    156     // stored in the full-backup tarfile as well, so should not be changed.
    157     private static final String STAGE_FILE = "flattened-data";
    158 
    159     // Delay in milliseconds between the restore operation and when we will bounce
    160     // wifi in order to rewrite the supplicant config etc.
    161     private static final long WIFI_BOUNCE_DELAY_MILLIS = 60 * 1000; // one minute
    162 
    163     private SettingsHelper mSettingsHelper;
    164     private WifiManager mWfm;
    165     private String mWifiConfigFile;
    166 
    167     // Chain of asynchronous operations used when rewriting the wifi supplicant config file
    168     WifiDisableRunnable mWifiDisable = null;
    169     WifiRestoreRunnable mWifiRestore = null;
    170     int mRetainedWifiState; // used only during config file rewrite
    171 
    172     // Class for capturing a network definition from the wifi supplicant config file
    173     static class Network {
    174         String ssid = "";  // equals() and hashCode() need these to be non-null
    175         String key_mgmt = "";
    176         boolean certUsed = false;
    177         boolean hasWepKey = false;
    178         boolean isEap = false;
    179         final ArrayList<String> rawLines = new ArrayList<String>();
    180 
    181         public static Network readFromStream(BufferedReader in) {
    182             final Network n = new Network();
    183             String line;
    184             try {
    185                 while (in.ready()) {
    186                     line = in.readLine();
    187                     if (line == null || line.startsWith("}")) {
    188                         break;
    189                     }
    190                     n.rememberLine(line);
    191                 }
    192             } catch (IOException e) {
    193                 return null;
    194             }
    195             return n;
    196         }
    197 
    198         void rememberLine(String line) {
    199             // can't rely on particular whitespace patterns so strip leading/trailing
    200             line = line.trim();
    201             if (line.isEmpty()) return; // only whitespace; drop the line
    202             rawLines.add(line);
    203 
    204             // remember the ssid and key_mgmt lines for duplicate culling
    205             if (line.startsWith("ssid=")) {
    206                 ssid = line;
    207             } else if (line.startsWith("key_mgmt=")) {
    208                 key_mgmt = line;
    209                 if (line.contains("EAP")) {
    210                     isEap = true;
    211                 }
    212             } else if (line.startsWith("client_cert=")) {
    213                 certUsed = true;
    214             } else if (line.startsWith("ca_cert=")) {
    215                 certUsed = true;
    216             } else if (line.startsWith("ca_path=")) {
    217                 certUsed = true;
    218             } else if (line.startsWith("wep_")) {
    219                 hasWepKey = true;
    220             } else if (line.startsWith("eap=")) {
    221                 isEap = true;
    222             }
    223         }
    224 
    225         public void write(Writer w) throws IOException {
    226             w.write("\nnetwork={\n");
    227             for (String line : rawLines) {
    228                 w.write("\t" + line + "\n");
    229             }
    230             w.write("}\n");
    231         }
    232 
    233         public void dump() {
    234             Log.v(TAG, "network={");
    235             for (String line : rawLines) {
    236                 Log.v(TAG, "   " + line);
    237             }
    238             Log.v(TAG, "}");
    239         }
    240 
    241         // Calculate the equivalent of WifiConfiguration's configKey()
    242         public String configKey() {
    243             if (ssid == null) {
    244                 // No SSID => malformed network definition
    245                 return null;
    246             }
    247 
    248             final String bareSsid = ssid.substring(ssid.indexOf('=') + 1);
    249 
    250             final BitSet types = new BitSet();
    251             if (key_mgmt == null) {
    252                 // no key_mgmt specified; this is defined as equivalent to "WPA-PSK WPA-EAP"
    253                 types.set(KeyMgmt.WPA_PSK);
    254                 types.set(KeyMgmt.WPA_EAP);
    255             } else {
    256                 // Need to parse the key_mgmt line
    257                 final String bareKeyMgmt = key_mgmt.substring(key_mgmt.indexOf('=') + 1);
    258                 String[] typeStrings = bareKeyMgmt.split("\\s+");
    259 
    260                 // Parse out all the key management regimes permitted for this network.  The literal
    261                 // strings here are the standard values permitted in wpa_supplicant.conf.
    262                 for (int i = 0; i < typeStrings.length; i++) {
    263                     final String ktype = typeStrings[i];
    264                     if (ktype.equals("WPA-PSK")) {
    265                         Log.v(TAG, "  + setting WPA_PSK bit");
    266                         types.set(KeyMgmt.WPA_PSK);
    267                     } else if (ktype.equals("WPA-EAP")) {
    268                         Log.v(TAG, "  + setting WPA_EAP bit");
    269                         types.set(KeyMgmt.WPA_EAP);
    270                     } else if (ktype.equals("IEEE8021X")) {
    271                         Log.v(TAG, "  + setting IEEE8021X bit");
    272                         types.set(KeyMgmt.IEEE8021X);
    273                     }
    274                 }
    275             }
    276 
    277             // Now build the canonical config key paralleling the WifiConfiguration semantics
    278             final String key;
    279             if (types.get(KeyMgmt.WPA_PSK)) {
    280                 key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_PSK];
    281             } else if (types.get(KeyMgmt.WPA_EAP) || types.get(KeyMgmt.IEEE8021X)) {
    282                 key = bareSsid + KeyMgmt.strings[KeyMgmt.WPA_EAP];
    283             } else if (hasWepKey) {
    284                 key = bareSsid + "WEP";  // hardcoded this way in WifiConfiguration
    285             } else {
    286                 key = bareSsid + KeyMgmt.strings[KeyMgmt.NONE];
    287             }
    288             return key;
    289         }
    290 
    291         // Same approach as Pair.equals() and Pair.hashCode()
    292         @Override
    293         public boolean equals(Object o) {
    294             if (o == this) return true;
    295             if (!(o instanceof Network)) return false;
    296             final Network other;
    297             try {
    298                 other = (Network) o;
    299             } catch (ClassCastException e) {
    300                 return false;
    301             }
    302             return ssid.equals(other.ssid) && key_mgmt.equals(other.key_mgmt);
    303         }
    304 
    305         @Override
    306         public int hashCode() {
    307             int result = 17;
    308             result = 31 * result + ssid.hashCode();
    309             result = 31 * result + key_mgmt.hashCode();
    310             return result;
    311         }
    312     }
    313 
    314     boolean networkInWhitelist(Network net, List<WifiConfiguration> whitelist) {
    315         final String netConfigKey = net.configKey();
    316         final int N = whitelist.size();
    317         for (int i = 0; i < N; i++) {
    318             if (Objects.equals(netConfigKey, whitelist.get(i).configKey(true))) {
    319                 return true;
    320             }
    321         }
    322         return false;
    323     }
    324 
    325     // Ingest multiple wifi config file fragments, looking for network={} blocks
    326     // and eliminating duplicates
    327     class WifiNetworkSettings {
    328         // One for fast lookup, one for maintaining ordering
    329         final HashSet<Network> mKnownNetworks = new HashSet<Network>();
    330         final ArrayList<Network> mNetworks = new ArrayList<Network>(8);
    331 
    332         public void readNetworks(BufferedReader in, List<WifiConfiguration> whitelist,
    333                 boolean acceptEapNetworks) {
    334             try {
    335                 String line;
    336                 while (in.ready()) {
    337                     line = in.readLine();
    338                     if (line != null) {
    339                         // Parse out 'network=' decls so we can ignore duplicates
    340                         if (line.startsWith("network")) {
    341                             Network net = Network.readFromStream(in);
    342                             if (whitelist != null) {
    343                                 if (!networkInWhitelist(net, whitelist)) {
    344                                     if (DEBUG_BACKUP) {
    345                                         Log.v(TAG, "Network not in whitelist, skipping: "
    346                                                 + net.ssid + " / " + net.key_mgmt);
    347                                     }
    348                                     continue;
    349                                 }
    350                             }
    351                             // Don't propagate EAP network definitions
    352                             if (net.isEap && !acceptEapNetworks) {
    353                                 if (DEBUG_BACKUP) {
    354                                     Log.v(TAG, "Skipping EAP network " + net.ssid + " / " + net.key_mgmt);
    355                                 }
    356                                 continue;
    357                             }
    358                             if (!mKnownNetworks.contains(net)) {
    359                                 if (DEBUG_BACKUP) {
    360                                     Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
    361                                 }
    362                                 mKnownNetworks.add(net);
    363                                 mNetworks.add(net);
    364                             } else {
    365                                 if (DEBUG_BACKUP) {
    366                                     Log.v(TAG, "Dupe; skipped " + net.ssid + " / " + net.key_mgmt);
    367                                 }
    368                             }
    369                         }
    370                     }
    371                 }
    372             } catch (IOException e) {
    373                 // whatever happened, we're done now
    374             }
    375         }
    376 
    377         public void write(Writer w) throws IOException {
    378             for (Network net : mNetworks) {
    379                 if (net.certUsed) {
    380                     // Networks that use certificates for authentication can't be restored
    381                     // because the certificates they need don't get restored (because they
    382                     // are stored in keystore, and can't be restored)
    383                     continue;
    384                 }
    385 
    386                 if (net.isEap) {
    387                     // Similarly, omit EAP network definitions to avoid propagating
    388                     // controlled enterprise network definitions.
    389                     continue;
    390                 }
    391 
    392                 net.write(w);
    393             }
    394         }
    395 
    396         public void dump() {
    397             for (Network net : mNetworks) {
    398                 net.dump();
    399             }
    400         }
    401     }
    402 
    403     @Override
    404     public void onCreate() {
    405         if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
    406 
    407         mSettingsHelper = new SettingsHelper(this);
    408         super.onCreate();
    409 
    410         WifiManager mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    411         if (mWfm != null) mWifiConfigFile = mWfm.getConfigFile();
    412     }
    413 
    414     @Override
    415     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
    416             ParcelFileDescriptor newState) throws IOException {
    417 
    418         byte[] systemSettingsData = getSystemSettings();
    419         byte[] secureSettingsData = getSecureSettings();
    420         byte[] globalSettingsData = getGlobalSettings();
    421         byte[] lockSettingsData   = getLockSettings();
    422         byte[] locale = mSettingsHelper.getLocaleData();
    423         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
    424         byte[] wifiConfigData = getFileData(mWifiConfigFile);
    425         byte[] softApConfigData = getSoftAPConfiguration();
    426         byte[] netPoliciesData = getNetworkPolicies();
    427 
    428         long[] stateChecksums = readOldChecksums(oldState);
    429 
    430         stateChecksums[STATE_SYSTEM] =
    431                 writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
    432         stateChecksums[STATE_SECURE] =
    433                 writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
    434         stateChecksums[STATE_GLOBAL] =
    435                 writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
    436         stateChecksums[STATE_LOCALE] =
    437                 writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
    438         stateChecksums[STATE_WIFI_SUPPLICANT] =
    439                 writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
    440                         wifiSupplicantData, data);
    441         stateChecksums[STATE_WIFI_CONFIG] =
    442                 writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
    443                         data);
    444         stateChecksums[STATE_LOCK_SETTINGS] =
    445                 writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
    446                         lockSettingsData, data);
    447         stateChecksums[STATE_SOFTAP_CONFIG] =
    448                 writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
    449                         softApConfigData, data);
    450         stateChecksums[STATE_NETWORK_POLICIES] =
    451                 writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
    452                         netPoliciesData, data);
    453 
    454         writeNewChecksums(stateChecksums, newState);
    455     }
    456 
    457     class WifiDisableRunnable implements Runnable {
    458         final WifiRestoreRunnable mNextPhase;
    459 
    460         public WifiDisableRunnable(WifiRestoreRunnable next) {
    461             mNextPhase = next;
    462         }
    463 
    464         @Override
    465         public void run() {
    466             if (DEBUG_BACKUP) {
    467                 Log.v(TAG, "Disabling wifi during restore");
    468             }
    469             final ContentResolver cr = getContentResolver();
    470             final int scanAlways = Settings.Global.getInt(cr,
    471                     Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
    472             final int retainedWifiState = enableWifi(false);
    473             if (scanAlways != 0) {
    474                 Settings.Global.putInt(cr,
    475                         Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, 0);
    476             }
    477 
    478             // Tell the final stage how to clean up after itself
    479             mNextPhase.setPriorState(retainedWifiState, scanAlways);
    480 
    481             // And run it after a modest pause to give broadcasts and content
    482             // observers time an opportunity to run on this looper thread, so
    483             // that the wifi stack actually goes all the way down.
    484             new Handler(getMainLooper()).postDelayed(mNextPhase, 2500);
    485         }
    486     }
    487 
    488     class WifiRestoreRunnable implements Runnable {
    489         private byte[] restoredSupplicantData;
    490         private byte[] restoredWifiConfigFile;
    491         private int retainedWifiState;  // provided by disable stage
    492         private int scanAlways; // provided by disable stage
    493 
    494         void setPriorState(int retainedState, int always) {
    495             retainedWifiState = retainedState;
    496             scanAlways = always;
    497         }
    498 
    499         void incorporateWifiSupplicant(BackupDataInput data) {
    500             restoredSupplicantData = new byte[data.getDataSize()];
    501             if (restoredSupplicantData.length <= 0) return;
    502             try {
    503                 data.readEntityData(restoredSupplicantData, 0, data.getDataSize());
    504             } catch (IOException e) {
    505                 Log.w(TAG, "Unable to read supplicant data");
    506                 restoredSupplicantData = null;
    507             }
    508         }
    509 
    510         void incorporateWifiConfigFile(BackupDataInput data) {
    511             restoredWifiConfigFile = new byte[data.getDataSize()];
    512             if (restoredWifiConfigFile.length <= 0) return;
    513             try {
    514                 data.readEntityData(restoredWifiConfigFile, 0, data.getDataSize());
    515             } catch (IOException e) {
    516                 Log.w(TAG, "Unable to read config file");
    517                 restoredWifiConfigFile = null;
    518             }
    519         }
    520 
    521         @Override
    522         public void run() {
    523             if (restoredSupplicantData != null || restoredWifiConfigFile != null) {
    524                 if (DEBUG_BACKUP) {
    525                     Log.v(TAG, "Applying restored wifi data");
    526                 }
    527                 if (restoredSupplicantData != null) {
    528                     restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
    529                             restoredSupplicantData, restoredSupplicantData.length);
    530                     FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
    531                             FileUtils.S_IRUSR | FileUtils.S_IWUSR
    532                             | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
    533                             Process.myUid(), Process.WIFI_UID);
    534                 }
    535                 if (restoredWifiConfigFile != null) {
    536                     restoreFileData(mWifiConfigFile,
    537                             restoredWifiConfigFile, restoredWifiConfigFile.length);
    538                 }
    539                 // restore the previous WIFI state.
    540                 if (scanAlways != 0) {
    541                     Settings.Global.putInt(getContentResolver(),
    542                             Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways);
    543                 }
    544                 enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
    545                         || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
    546             }
    547         }
    548     }
    549 
    550     // Instantiate the wifi-config restore runnable, scheduling it for execution
    551     // a minute hence
    552     void initWifiRestoreIfNecessary() {
    553         if (mWifiRestore == null) {
    554             mWifiRestore = new WifiRestoreRunnable();
    555             mWifiDisable = new WifiDisableRunnable(mWifiRestore);
    556         }
    557     }
    558 
    559     @Override
    560     public void onRestore(BackupDataInput data, int appVersionCode,
    561             ParcelFileDescriptor newState) throws IOException {
    562 
    563         HashSet<String> movedToGlobal = new HashSet<String>();
    564         Settings.System.getMovedToGlobalSettings(movedToGlobal);
    565         Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
    566 
    567         while (data.readNextHeader()) {
    568             final String key = data.getKey();
    569             final int size = data.getDataSize();
    570             switch (key) {
    571                 case KEY_SYSTEM :
    572                     restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
    573                     mSettingsHelper.applyAudioSettings();
    574                     break;
    575 
    576                 case KEY_SECURE :
    577                     restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
    578                     break;
    579 
    580                 case KEY_GLOBAL :
    581                     restoreSettings(data, Settings.Global.CONTENT_URI, null);
    582                     break;
    583 
    584                 case KEY_WIFI_SUPPLICANT :
    585                     initWifiRestoreIfNecessary();
    586                     mWifiRestore.incorporateWifiSupplicant(data);
    587                     break;
    588 
    589                 case KEY_LOCALE :
    590                     byte[] localeData = new byte[size];
    591                     data.readEntityData(localeData, 0, size);
    592                     mSettingsHelper.setLocaleData(localeData, size);
    593                     break;
    594 
    595                 case KEY_WIFI_CONFIG :
    596                     initWifiRestoreIfNecessary();
    597                     mWifiRestore.incorporateWifiConfigFile(data);
    598                     break;
    599 
    600                 case KEY_LOCK_SETTINGS :
    601                     restoreLockSettings(data);
    602                     break;
    603 
    604                 case KEY_SOFTAP_CONFIG :
    605                     byte[] softapData = new byte[size];
    606                     data.readEntityData(softapData, 0, size);
    607                     restoreSoftApConfiguration(softapData);
    608                     break;
    609 
    610                 case KEY_NETWORK_POLICIES:
    611                     byte[] netPoliciesData = new byte[size];
    612                     data.readEntityData(netPoliciesData, 0, size);
    613                     restoreNetworkPolicies(netPoliciesData);
    614                     break;
    615 
    616                 default :
    617                     data.skipEntityData();
    618 
    619             }
    620         }
    621 
    622         // If we have wifi data to restore, post a runnable to perform the
    623         // bounce-and-update operation a little ways in the future.  The
    624         // 'disable' runnable brings down the stack and remembers its state,
    625         // and in turn schedules the 'restore' runnable to do the rewrite
    626         // and cleanup operations.
    627         if (mWifiRestore != null) {
    628             long wifiBounceDelayMillis = Settings.Global.getLong(
    629                     getContentResolver(),
    630                     Settings.Global.WIFI_BOUNCE_DELAY_OVERRIDE_MS,
    631                     WIFI_BOUNCE_DELAY_MILLIS);
    632             new Handler(getMainLooper()).postDelayed(mWifiDisable, wifiBounceDelayMillis);
    633         }
    634     }
    635 
    636     @Override
    637     public void onFullBackup(FullBackupDataOutput data)  throws IOException {
    638         byte[] systemSettingsData = getSystemSettings();
    639         byte[] secureSettingsData = getSecureSettings();
    640         byte[] globalSettingsData = getGlobalSettings();
    641         byte[] lockSettingsData   = getLockSettings();
    642         byte[] locale = mSettingsHelper.getLocaleData();
    643         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
    644         byte[] wifiConfigData = getFileData(mWifiConfigFile);
    645         byte[] softApConfigData = getSoftAPConfiguration();
    646         byte[] netPoliciesData = getNetworkPolicies();
    647 
    648         // Write the data to the staging file, then emit that as our tarfile
    649         // representation of the backed-up settings.
    650         String root = getFilesDir().getAbsolutePath();
    651         File stage = new File(root, STAGE_FILE);
    652         try {
    653             FileOutputStream filestream = new FileOutputStream(stage);
    654             BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
    655             DataOutputStream out = new DataOutputStream(bufstream);
    656 
    657             if (DEBUG_BACKUP) Log.d(TAG, "Writing flattened data version " + FULL_BACKUP_VERSION);
    658             out.writeInt(FULL_BACKUP_VERSION);
    659 
    660             if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
    661             out.writeInt(systemSettingsData.length);
    662             out.write(systemSettingsData);
    663             if (DEBUG_BACKUP) {
    664                 Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
    665             }
    666             out.writeInt(secureSettingsData.length);
    667             out.write(secureSettingsData);
    668             if (DEBUG_BACKUP) {
    669                 Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
    670             }
    671             out.writeInt(globalSettingsData.length);
    672             out.write(globalSettingsData);
    673             if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
    674             out.writeInt(locale.length);
    675             out.write(locale);
    676             if (DEBUG_BACKUP) {
    677                 Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
    678             }
    679             out.writeInt(wifiSupplicantData.length);
    680             out.write(wifiSupplicantData);
    681             if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
    682             out.writeInt(wifiConfigData.length);
    683             out.write(wifiConfigData);
    684             if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
    685             out.writeInt(lockSettingsData.length);
    686             out.write(lockSettingsData);
    687             if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
    688             out.writeInt(softApConfigData.length);
    689             out.write(softApConfigData);
    690             if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of net policies data");
    691             out.writeInt(netPoliciesData.length);
    692             out.write(netPoliciesData);
    693 
    694             out.flush();    // also flushes downstream
    695 
    696             // now we're set to emit the tar stream
    697             fullBackupFile(stage, data);
    698         } finally {
    699             stage.delete();
    700         }
    701     }
    702 
    703     @Override
    704     public void onRestoreFile(ParcelFileDescriptor data, long size,
    705             int type, String domain, String relpath, long mode, long mtime)
    706             throws IOException {
    707         if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
    708         // Our data is actually a blob of flattened settings data identical to that
    709         // produced during incremental backups.  Just unpack and apply it all in
    710         // turn.
    711         FileInputStream instream = new FileInputStream(data.getFileDescriptor());
    712         DataInputStream in = new DataInputStream(instream);
    713 
    714         int version = in.readInt();
    715         if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
    716         if (version <= FULL_BACKUP_VERSION) {
    717             // Generate the moved-to-global lookup table
    718             HashSet<String> movedToGlobal = new HashSet<String>();
    719             Settings.System.getMovedToGlobalSettings(movedToGlobal);
    720             Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
    721 
    722             // system settings data first
    723             int nBytes = in.readInt();
    724             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
    725             byte[] buffer = new byte[nBytes];
    726             in.readFully(buffer, 0, nBytes);
    727             restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal);
    728 
    729             // secure settings
    730             nBytes = in.readInt();
    731             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
    732             if (nBytes > buffer.length) buffer = new byte[nBytes];
    733             in.readFully(buffer, 0, nBytes);
    734             restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI, movedToGlobal);
    735 
    736             // Global only if sufficiently new
    737             if (version >= FULL_BACKUP_ADDED_GLOBAL) {
    738                 nBytes = in.readInt();
    739                 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of global settings data");
    740                 if (nBytes > buffer.length) buffer = new byte[nBytes];
    741                 in.readFully(buffer, 0, nBytes);
    742                 movedToGlobal.clear();  // no redirection; this *is* the global namespace
    743                 restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal);
    744             }
    745 
    746             // locale
    747             nBytes = in.readInt();
    748             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
    749             if (nBytes > buffer.length) buffer = new byte[nBytes];
    750             in.readFully(buffer, 0, nBytes);
    751             mSettingsHelper.setLocaleData(buffer, nBytes);
    752 
    753             // wifi supplicant
    754             nBytes = in.readInt();
    755             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi supplicant data");
    756             if (nBytes > buffer.length) buffer = new byte[nBytes];
    757             in.readFully(buffer, 0, nBytes);
    758             int retainedWifiState = enableWifi(false);
    759             restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
    760             FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
    761                     FileUtils.S_IRUSR | FileUtils.S_IWUSR
    762                     | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
    763                     Process.myUid(), Process.WIFI_UID);
    764             // retain the previous WIFI state.
    765             enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
    766                     || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
    767 
    768             // wifi config
    769             nBytes = in.readInt();
    770             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi config data");
    771             if (nBytes > buffer.length) buffer = new byte[nBytes];
    772             in.readFully(buffer, 0, nBytes);
    773             restoreFileData(mWifiConfigFile, buffer, nBytes);
    774 
    775             if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
    776                 nBytes = in.readInt();
    777                 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
    778                 if (nBytes > buffer.length) buffer = new byte[nBytes];
    779                 if (nBytes > 0) {
    780                     in.readFully(buffer, 0, nBytes);
    781                     restoreLockSettings(buffer, nBytes);
    782                 }
    783             }
    784             // softap config
    785             if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
    786                 nBytes = in.readInt();
    787                 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
    788                 if (nBytes > buffer.length) buffer = new byte[nBytes];
    789                 if (nBytes > 0) {
    790                     in.readFully(buffer, 0, nBytes);
    791                     restoreSoftApConfiguration(buffer);
    792                 }
    793             }
    794             // network policies
    795             if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
    796                 nBytes = in.readInt();
    797                 if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
    798                 if (nBytes > buffer.length) buffer = new byte[nBytes];
    799                 if (nBytes > 0) {
    800                     in.readFully(buffer, 0, nBytes);
    801                     restoreNetworkPolicies(buffer);
    802                 }
    803             }
    804             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
    805         } else {
    806             data.close();
    807             throw new IOException("Invalid file schema");
    808         }
    809     }
    810 
    811     private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
    812         long[] stateChecksums = new long[STATE_SIZE];
    813 
    814         DataInputStream dataInput = new DataInputStream(
    815                 new FileInputStream(oldState.getFileDescriptor()));
    816 
    817         try {
    818             int stateVersion = dataInput.readInt();
    819             if (stateVersion > STATE_VERSION) {
    820                 // Constrain the maximum state version this backup agent
    821                 // can handle in case a newer or corrupt backup set existed
    822                 stateVersion = STATE_VERSION;
    823             }
    824             for (int i = 0; i < STATE_SIZES[stateVersion]; i++) {
    825                 stateChecksums[i] = dataInput.readLong();
    826             }
    827         } catch (EOFException eof) {
    828             // With the default 0 checksum we'll wind up forcing a backup of
    829             // any unhandled data sets, which is appropriate.
    830         }
    831         dataInput.close();
    832         return stateChecksums;
    833     }
    834 
    835     private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
    836             throws IOException {
    837         DataOutputStream dataOutput = new DataOutputStream(
    838                 new BufferedOutputStream(new FileOutputStream(newState.getFileDescriptor())));
    839 
    840         dataOutput.writeInt(STATE_VERSION);
    841         for (int i = 0; i < STATE_SIZE; i++) {
    842             dataOutput.writeLong(checksums[i]);
    843         }
    844         dataOutput.close();
    845     }
    846 
    847     private long writeIfChanged(long oldChecksum, String key, byte[] data,
    848             BackupDataOutput output) {
    849         CRC32 checkSummer = new CRC32();
    850         checkSummer.update(data);
    851         long newChecksum = checkSummer.getValue();
    852         if (oldChecksum == newChecksum) {
    853             return oldChecksum;
    854         }
    855         try {
    856             if (DEBUG_BACKUP) {
    857                 Log.v(TAG, "Writing entity " + key + " of size " + data.length);
    858             }
    859             output.writeEntityHeader(key, data.length);
    860             output.writeEntityData(data, data.length);
    861         } catch (IOException ioe) {
    862             // Bail
    863         }
    864         return newChecksum;
    865     }
    866 
    867     private byte[] getSystemSettings() {
    868         Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
    869                 null, null);
    870         try {
    871             return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
    872         } finally {
    873             cursor.close();
    874         }
    875     }
    876 
    877     private byte[] getSecureSettings() {
    878         Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
    879                 null, null);
    880         try {
    881             return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
    882         } finally {
    883             cursor.close();
    884         }
    885     }
    886 
    887     private byte[] getGlobalSettings() {
    888         Cursor cursor = getContentResolver().query(Settings.Global.CONTENT_URI, PROJECTION, null,
    889                 null, null);
    890         try {
    891             return extractRelevantValues(cursor, Settings.Global.SETTINGS_TO_BACKUP);
    892         } finally {
    893             cursor.close();
    894         }
    895     }
    896 
    897     /**
    898      * Serialize the owner info settings
    899      */
    900     private byte[] getLockSettings() {
    901         final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
    902         final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled(UserHandle.myUserId());
    903         final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
    904 
    905         ByteArrayOutputStream baos = new ByteArrayOutputStream();
    906         DataOutputStream out = new DataOutputStream(baos);
    907         try {
    908             out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
    909             out.writeUTF(ownerInfoEnabled ? "1" : "0");
    910             if (ownerInfo != null) {
    911                 out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
    912                 out.writeUTF(ownerInfo != null ? ownerInfo : "");
    913             }
    914             // End marker
    915             out.writeUTF("");
    916             out.flush();
    917         } catch (IOException ioe) {
    918         }
    919         return baos.toByteArray();
    920     }
    921 
    922     private void restoreSettings(BackupDataInput data, Uri contentUri,
    923             HashSet<String> movedToGlobal) {
    924         byte[] settings = new byte[data.getDataSize()];
    925         try {
    926             data.readEntityData(settings, 0, settings.length);
    927         } catch (IOException ioe) {
    928             Log.e(TAG, "Couldn't read entity data");
    929             return;
    930         }
    931         restoreSettings(settings, settings.length, contentUri, movedToGlobal);
    932     }
    933 
    934     private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
    935             HashSet<String> movedToGlobal) {
    936         if (DEBUG) {
    937             Log.i(TAG, "restoreSettings: " + contentUri);
    938         }
    939 
    940         // Figure out the white list and redirects to the global table.
    941         final String[] whitelist;
    942         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
    943             whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
    944         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
    945             whitelist = Settings.System.SETTINGS_TO_BACKUP;
    946         } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
    947             whitelist = Settings.Global.SETTINGS_TO_BACKUP;
    948         } else {
    949             throw new IllegalArgumentException("Unknown URI: " + contentUri);
    950         }
    951 
    952         // Restore only the white list data.
    953         int pos = 0;
    954         Map<String, String> cachedEntries = new HashMap<String, String>();
    955         ContentValues contentValues = new ContentValues(2);
    956         SettingsHelper settingsHelper = mSettingsHelper;
    957         ContentResolver cr = getContentResolver();
    958 
    959         final int whiteListSize = whitelist.length;
    960         for (int i = 0; i < whiteListSize; i++) {
    961             String key = whitelist[i];
    962             String value = cachedEntries.remove(key);
    963 
    964             // If the value not cached, let us look it up.
    965             if (value == null) {
    966                 while (pos < bytes) {
    967                     int length = readInt(settings, pos);
    968                     pos += INTEGER_BYTE_COUNT;
    969                     String dataKey = length > 0 ? new String(settings, pos, length) : null;
    970                     pos += length;
    971                     length = readInt(settings, pos);
    972                     pos += INTEGER_BYTE_COUNT;
    973                     String dataValue = length > 0 ? new String(settings, pos, length) : null;
    974                     pos += length;
    975                     if (key.equals(dataKey)) {
    976                         value = dataValue;
    977                         break;
    978                     }
    979                     cachedEntries.put(dataKey, dataValue);
    980                 }
    981             }
    982 
    983             if (value == null) {
    984                 continue;
    985             }
    986 
    987             final Uri destination = (movedToGlobal != null && movedToGlobal.contains(key))
    988                     ? Settings.Global.CONTENT_URI
    989                     : contentUri;
    990             settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
    991 
    992             if (DEBUG) {
    993                 Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
    994             }
    995         }
    996     }
    997 
    998     /**
    999      * Restores the owner info enabled and owner info settings in LockSettings.
   1000      *
   1001      * @param buffer
   1002      * @param nBytes
   1003      */
   1004     private void restoreLockSettings(byte[] buffer, int nBytes) {
   1005         final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
   1006 
   1007         ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
   1008         DataInputStream in = new DataInputStream(bais);
   1009         try {
   1010             String key;
   1011             // Read until empty string marker
   1012             while ((key = in.readUTF()).length() > 0) {
   1013                 final String value = in.readUTF();
   1014                 if (DEBUG_BACKUP) {
   1015                     Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
   1016                 }
   1017                 switch (key) {
   1018                     case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
   1019                         lockPatternUtils.setOwnerInfoEnabled("1".equals(value),
   1020                                 UserHandle.myUserId());
   1021                         break;
   1022                     case KEY_LOCK_SETTINGS_OWNER_INFO:
   1023                         lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
   1024                         break;
   1025                 }
   1026             }
   1027             in.close();
   1028         } catch (IOException ioe) {
   1029         }
   1030     }
   1031 
   1032     private void restoreLockSettings(BackupDataInput data) {
   1033         final byte[] settings = new byte[data.getDataSize()];
   1034         try {
   1035             data.readEntityData(settings, 0, settings.length);
   1036         } catch (IOException ioe) {
   1037             Log.e(TAG, "Couldn't read entity data");
   1038             return;
   1039         }
   1040         restoreLockSettings(settings, settings.length);
   1041     }
   1042 
   1043     /**
   1044      * Given a cursor and a set of keys, extract the required keys and
   1045      * values and write them to a byte array.
   1046      *
   1047      * @param cursor A cursor with settings data.
   1048      * @param settings The settings to extract.
   1049      * @return The byte array of extracted values.
   1050      */
   1051     private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
   1052         final int settingsCount = settings.length;
   1053         byte[][] values = new byte[settingsCount * 2][]; // keys and values
   1054         if (!cursor.moveToFirst()) {
   1055             Log.e(TAG, "Couldn't read from the cursor");
   1056             return new byte[0];
   1057         }
   1058 
   1059         // Obtain the relevant data in a temporary array.
   1060         int totalSize = 0;
   1061         int backedUpSettingIndex = 0;
   1062         Map<String, String> cachedEntries = new HashMap<String, String>();
   1063         for (int i = 0; i < settingsCount; i++) {
   1064             String key = settings[i];
   1065             String value = cachedEntries.remove(key);
   1066 
   1067             final int nameColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
   1068             final int valueColumnIndex = cursor.getColumnIndex(Settings.NameValueTable.VALUE);
   1069 
   1070             // If the value not cached, let us look it up.
   1071             if (value == null) {
   1072                 while (!cursor.isAfterLast()) {
   1073                     String cursorKey = cursor.getString(nameColumnIndex);
   1074                     String cursorValue = cursor.getString(valueColumnIndex);
   1075                     cursor.moveToNext();
   1076                     if (key.equals(cursorKey)) {
   1077                         value = cursorValue;
   1078                         break;
   1079                     }
   1080                     cachedEntries.put(cursorKey, cursorValue);
   1081                 }
   1082             }
   1083 
   1084             // Intercept the keys and see if they need special handling
   1085             value = mSettingsHelper.onBackupValue(key, value);
   1086 
   1087             if (value == null) {
   1088                 continue;
   1089             }
   1090             // Write the key and value in the intermediary array.
   1091             byte[] keyBytes = key.getBytes();
   1092             totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
   1093             values[backedUpSettingIndex * 2] = keyBytes;
   1094 
   1095             byte[] valueBytes = value.getBytes();
   1096             totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
   1097             values[backedUpSettingIndex * 2 + 1] = valueBytes;
   1098 
   1099             backedUpSettingIndex++;
   1100 
   1101             if (DEBUG) {
   1102                 Log.d(TAG, "Backed up setting: " + key + "=" + value);
   1103             }
   1104         }
   1105 
   1106         // Aggregate the result.
   1107         byte[] result = new byte[totalSize];
   1108         int pos = 0;
   1109         final int keyValuePairCount = backedUpSettingIndex * 2;
   1110         for (int i = 0; i < keyValuePairCount; i++) {
   1111             pos = writeInt(result, pos, values[i].length);
   1112             pos = writeBytes(result, pos, values[i]);
   1113         }
   1114         return result;
   1115     }
   1116 
   1117     private byte[] getFileData(String filename) {
   1118         InputStream is = null;
   1119         try {
   1120             File file = new File(filename);
   1121             is = new FileInputStream(file);
   1122 
   1123             //Will truncate read on a very long file,
   1124             //should not happen for a config file
   1125             byte[] bytes = new byte[(int) file.length()];
   1126 
   1127             int offset = 0;
   1128             int numRead = 0;
   1129             while (offset < bytes.length
   1130                     && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
   1131                 offset += numRead;
   1132             }
   1133 
   1134             //read failure
   1135             if (offset < bytes.length) {
   1136                 Log.w(TAG, "Couldn't backup " + filename);
   1137                 return EMPTY_DATA;
   1138             }
   1139             return bytes;
   1140         } catch (IOException ioe) {
   1141             Log.w(TAG, "Couldn't backup " + filename);
   1142             return EMPTY_DATA;
   1143         } finally {
   1144             if (is != null) {
   1145                 try {
   1146                     is.close();
   1147                 } catch (IOException e) {
   1148                 }
   1149             }
   1150         }
   1151     }
   1152 
   1153     private void restoreFileData(String filename, byte[] bytes, int size) {
   1154         try {
   1155             File file = new File(filename);
   1156             if (file.exists()) file.delete();
   1157 
   1158             OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
   1159             os.write(bytes, 0, size);
   1160             os.close();
   1161         } catch (IOException ioe) {
   1162             Log.w(TAG, "Couldn't restore " + filename);
   1163         }
   1164     }
   1165 
   1166 
   1167     private byte[] getWifiSupplicant(String filename) {
   1168         BufferedReader br = null;
   1169         try {
   1170             File file = new File(filename);
   1171             if (!file.exists()) {
   1172                 return EMPTY_DATA;
   1173             }
   1174 
   1175             WifiManager wifi = (WifiManager) getSystemService(WIFI_SERVICE);
   1176             List<WifiConfiguration> configs = wifi.getConfiguredNetworks();
   1177 
   1178             WifiNetworkSettings fromFile = new WifiNetworkSettings();
   1179             br = new BufferedReader(new FileReader(file));
   1180             fromFile.readNetworks(br, configs, false);
   1181 
   1182             // Write the parsed networks into a packed byte array
   1183             if (fromFile.mKnownNetworks.size() > 0) {
   1184                 ByteArrayOutputStream bos = new ByteArrayOutputStream();
   1185                 OutputStreamWriter out = new OutputStreamWriter(bos);
   1186                 fromFile.write(out);
   1187                 out.flush();
   1188                 return bos.toByteArray();
   1189             } else {
   1190                 return EMPTY_DATA;
   1191             }
   1192         } catch (IOException ioe) {
   1193             Log.w(TAG, "Couldn't backup " + filename);
   1194             return EMPTY_DATA;
   1195         } finally {
   1196             IoUtils.closeQuietly(br);
   1197         }
   1198     }
   1199 
   1200     private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
   1201         try {
   1202             WifiNetworkSettings supplicantImage = new WifiNetworkSettings();
   1203 
   1204             File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
   1205             if (supplicantFile.exists()) {
   1206                 // Retain the existing APs; we'll append the restored ones to them
   1207                 BufferedReader in = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT));
   1208                 supplicantImage.readNetworks(in, null, true);
   1209                 in.close();
   1210 
   1211                 supplicantFile.delete();
   1212             }
   1213 
   1214             // Incorporate the restore AP information
   1215             if (size > 0) {
   1216                 char[] restoredAsBytes = new char[size];
   1217                 for (int i = 0; i < size; i++) restoredAsBytes[i] = (char) bytes[i];
   1218                 BufferedReader in = new BufferedReader(new CharArrayReader(restoredAsBytes));
   1219                 supplicantImage.readNetworks(in, null, false);
   1220 
   1221                 if (DEBUG_BACKUP) {
   1222                     Log.v(TAG, "Final AP list:");
   1223                     supplicantImage.dump();
   1224                 }
   1225             }
   1226 
   1227             // Install the correct default template
   1228             BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
   1229             copyWifiSupplicantTemplate(bw);
   1230 
   1231             // Write the restored supplicant config and we're done
   1232             supplicantImage.write(bw);
   1233             bw.close();
   1234         } catch (IOException ioe) {
   1235             Log.w(TAG, "Couldn't restore " + filename);
   1236         }
   1237     }
   1238 
   1239     private void copyWifiSupplicantTemplate(BufferedWriter bw) {
   1240         try {
   1241             BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
   1242             char[] temp = new char[1024];
   1243             int size;
   1244             while ((size = br.read(temp)) > 0) {
   1245                 bw.write(temp, 0, size);
   1246             }
   1247             br.close();
   1248         } catch (IOException ioe) {
   1249             Log.w(TAG, "Couldn't copy wpa_supplicant file");
   1250         }
   1251     }
   1252 
   1253     private byte[] getSoftAPConfiguration() {
   1254         WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
   1255         try {
   1256             return wifiManager.getWifiApConfiguration().getBytesForBackup();
   1257         } catch (IOException ioe) {
   1258             Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
   1259             return new byte[0];
   1260         }
   1261     }
   1262 
   1263     private void restoreSoftApConfiguration(byte[] data) {
   1264         WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
   1265         try {
   1266             WifiConfiguration config = WifiConfiguration
   1267                     .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
   1268             if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
   1269             wifiManager.setWifiApConfiguration(config);
   1270         } catch (IOException | BackupUtils.BadVersionException e) {
   1271             Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
   1272         }
   1273     }
   1274 
   1275     private byte[] getNetworkPolicies() {
   1276         NetworkPolicyManager networkPolicyManager =
   1277                 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
   1278         NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
   1279         ByteArrayOutputStream baos = new ByteArrayOutputStream();
   1280         if (policies != null && policies.length != 0) {
   1281             DataOutputStream out = new DataOutputStream(baos);
   1282             try {
   1283                 out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
   1284                 out.writeInt(policies.length);
   1285                 for (NetworkPolicy policy : policies) {
   1286                     if (policy != null) {
   1287                         byte[] marshaledPolicy = policy.getBytesForBackup();
   1288                         out.writeByte(BackupUtils.NOT_NULL);
   1289                         out.writeInt(marshaledPolicy.length);
   1290                         out.write(marshaledPolicy);
   1291                     } else {
   1292                         out.writeByte(BackupUtils.NULL);
   1293                     }
   1294                 }
   1295             } catch (IOException ioe) {
   1296                 Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
   1297                 baos.reset();
   1298             }
   1299         }
   1300         return baos.toByteArray();
   1301     }
   1302 
   1303     private void restoreNetworkPolicies(byte[] data) {
   1304         NetworkPolicyManager networkPolicyManager =
   1305                 (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
   1306         if (data != null && data.length != 0) {
   1307             DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
   1308             try {
   1309                 int version = in.readInt();
   1310                 if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
   1311                     throw new BackupUtils.BadVersionException(
   1312                             "Unknown Backup Serialization Version");
   1313                 }
   1314                 int length = in.readInt();
   1315                 NetworkPolicy[] policies = new NetworkPolicy[length];
   1316                 for (int i = 0; i < length; i++) {
   1317                     byte isNull = in.readByte();
   1318                     if (isNull == BackupUtils.NULL) continue;
   1319                     int byteLength = in.readInt();
   1320                     byte[] policyData = new byte[byteLength];
   1321                     in.read(policyData, 0, byteLength);
   1322                     policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
   1323                             new DataInputStream(new ByteArrayInputStream(policyData)));
   1324                 }
   1325                 // Only set the policies if there was no error in the restore operation
   1326                 networkPolicyManager.setNetworkPolicies(policies);
   1327             } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
   1328                 // NPE can be thrown when trying to instantiate a NetworkPolicy
   1329                 Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
   1330             }
   1331         }
   1332     }
   1333 
   1334     /**
   1335      * Write an int in BigEndian into the byte array.
   1336      * @param out byte array
   1337      * @param pos current pos in array
   1338      * @param value integer to write
   1339      * @return the index after adding the size of an int (4) in bytes.
   1340      */
   1341     private int writeInt(byte[] out, int pos, int value) {
   1342         out[pos + 0] = (byte) ((value >> 24) & 0xFF);
   1343         out[pos + 1] = (byte) ((value >> 16) & 0xFF);
   1344         out[pos + 2] = (byte) ((value >>  8) & 0xFF);
   1345         out[pos + 3] = (byte) ((value >>  0) & 0xFF);
   1346         return pos + INTEGER_BYTE_COUNT;
   1347     }
   1348 
   1349     private int writeBytes(byte[] out, int pos, byte[] value) {
   1350         System.arraycopy(value, 0, out, pos, value.length);
   1351         return pos + value.length;
   1352     }
   1353 
   1354     private int readInt(byte[] in, int pos) {
   1355         int result = ((in[pos] & 0xFF) << 24)
   1356                 | ((in[pos + 1] & 0xFF) << 16)
   1357                 | ((in[pos + 2] & 0xFF) <<  8)
   1358                 | ((in[pos + 3] & 0xFF) <<  0);
   1359         return result;
   1360     }
   1361 
   1362     private int enableWifi(boolean enable) {
   1363         if (mWfm == null) {
   1364             mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
   1365         }
   1366         if (mWfm != null) {
   1367             int state = mWfm.getWifiState();
   1368             mWfm.setWifiEnabled(enable);
   1369             return state;
   1370         } else {
   1371             Log.e(TAG, "Failed to fetch WifiManager instance");
   1372         }
   1373         return WifiManager.WIFI_STATE_UNKNOWN;
   1374     }
   1375 }
   1376