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.ContentValues;
     24 import android.content.Context;
     25 import android.database.Cursor;
     26 import android.net.Uri;
     27 import android.net.wifi.WifiManager;
     28 import android.os.FileUtils;
     29 import android.os.ParcelFileDescriptor;
     30 import android.os.Process;
     31 import android.provider.Settings;
     32 import android.util.Log;
     33 
     34 import java.io.BufferedOutputStream;
     35 import java.io.BufferedReader;
     36 import java.io.BufferedWriter;
     37 import java.io.DataInputStream;
     38 import java.io.DataOutputStream;
     39 import java.io.EOFException;
     40 import java.io.File;
     41 import java.io.FileInputStream;
     42 import java.io.FileOutputStream;
     43 import java.io.FileReader;
     44 import java.io.FileWriter;
     45 import java.io.IOException;
     46 import java.io.InputStream;
     47 import java.io.OutputStream;
     48 import java.util.HashMap;
     49 import java.util.Map;
     50 import java.util.zip.CRC32;
     51 
     52 /**
     53  * Performs backup and restore of the System and Secure settings.
     54  * List of settings that are backed up are stored in the Settings.java file
     55  */
     56 public class SettingsBackupAgent extends BackupAgentHelper {
     57     private static final boolean DEBUG = false;
     58     private static final boolean DEBUG_BACKUP = DEBUG || true;
     59 
     60     private static final String KEY_SYSTEM = "system";
     61     private static final String KEY_SECURE = "secure";
     62     private static final String KEY_LOCALE = "locale";
     63 
     64     //Version 2 adds STATE_WIFI_CONFIG
     65     private static final int STATE_VERSION_1       = 1;
     66     private static final int STATE_VERSION_1_SIZE  = 4;
     67 
     68     // Versioning of the state file.  Increment this version
     69     // number any time the set of state items is altered.
     70     private static final int STATE_VERSION = 2;
     71 
     72     private static final int STATE_SYSTEM          = 0;
     73     private static final int STATE_SECURE          = 1;
     74     private static final int STATE_LOCALE          = 2;
     75     private static final int STATE_WIFI_SUPPLICANT = 3;
     76     private static final int STATE_WIFI_CONFIG     = 4;
     77     private static final int STATE_SIZE            = 5; // The number of state items
     78 
     79     // Versioning of the 'full backup' format
     80     private static final int FULL_BACKUP_VERSION = 1;
     81 
     82     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
     83 
     84     private static final byte[] EMPTY_DATA = new byte[0];
     85 
     86     private static final String TAG = "SettingsBackupAgent";
     87 
     88     private static final int COLUMN_NAME = 1;
     89     private static final int COLUMN_VALUE = 2;
     90 
     91     private static final String[] PROJECTION = {
     92         Settings.NameValueTable._ID,
     93         Settings.NameValueTable.NAME,
     94         Settings.NameValueTable.VALUE
     95     };
     96 
     97     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
     98     private static final String FILE_WIFI_SUPPLICANT_TEMPLATE =
     99             "/system/etc/wifi/wpa_supplicant.conf";
    100 
    101     // the key to store the WIFI data under, should be sorted as last, so restore happens last.
    102     // use very late unicode character to quasi-guarantee last sort position.
    103     private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
    104     private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
    105 
    106     // Name of the temporary file we use during full backup/restore.  This is
    107     // stored in the full-backup tarfile as well, so should not be changed.
    108     private static final String STAGE_FILE = "flattened-data";
    109 
    110     private SettingsHelper mSettingsHelper;
    111     private WifiManager mWfm;
    112     private static String mWifiConfigFile;
    113 
    114     @Override
    115     public void onCreate() {
    116         if (DEBUG_BACKUP) Log.d(TAG, "onCreate() invoked");
    117 
    118         mSettingsHelper = new SettingsHelper(this);
    119         super.onCreate();
    120 
    121         WifiManager mWfm = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    122         if (mWfm != null) mWifiConfigFile = mWfm.getConfigFile();
    123     }
    124 
    125     @Override
    126     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
    127             ParcelFileDescriptor newState) throws IOException {
    128 
    129         byte[] systemSettingsData = getSystemSettings();
    130         byte[] secureSettingsData = getSecureSettings();
    131         byte[] locale = mSettingsHelper.getLocaleData();
    132         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
    133         byte[] wifiConfigData = getFileData(mWifiConfigFile);
    134 
    135         long[] stateChecksums = readOldChecksums(oldState);
    136 
    137         stateChecksums[STATE_SYSTEM] =
    138             writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
    139         stateChecksums[STATE_SECURE] =
    140             writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
    141         stateChecksums[STATE_LOCALE] =
    142             writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
    143         stateChecksums[STATE_WIFI_SUPPLICANT] =
    144             writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
    145                     wifiSupplicantData, data);
    146         stateChecksums[STATE_WIFI_CONFIG] =
    147             writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
    148                     data);
    149 
    150         writeNewChecksums(stateChecksums, newState);
    151     }
    152 
    153     @Override
    154     public void onRestore(BackupDataInput data, int appVersionCode,
    155             ParcelFileDescriptor newState) throws IOException {
    156 
    157         while (data.readNextHeader()) {
    158             final String key = data.getKey();
    159             final int size = data.getDataSize();
    160             if (KEY_SYSTEM.equals(key)) {
    161                 restoreSettings(data, Settings.System.CONTENT_URI);
    162                 mSettingsHelper.applyAudioSettings();
    163             } else if (KEY_SECURE.equals(key)) {
    164                 restoreSettings(data, Settings.Secure.CONTENT_URI);
    165             } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
    166                 int retainedWifiState = enableWifi(false);
    167                 restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, data);
    168                 FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
    169                         FileUtils.S_IRUSR | FileUtils.S_IWUSR |
    170                         FileUtils.S_IRGRP | FileUtils.S_IWGRP,
    171                         Process.myUid(), Process.WIFI_UID);
    172                 // retain the previous WIFI state.
    173                 enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
    174                         retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
    175             } else if (KEY_LOCALE.equals(key)) {
    176                 byte[] localeData = new byte[size];
    177                 data.readEntityData(localeData, 0, size);
    178                 mSettingsHelper.setLocaleData(localeData, size);
    179             } else if (KEY_WIFI_CONFIG.equals(key)) {
    180                 restoreFileData(mWifiConfigFile, data);
    181              } else {
    182                 data.skipEntityData();
    183             }
    184         }
    185     }
    186 
    187     @Override
    188     public void onFullBackup(FullBackupDataOutput data)  throws IOException {
    189         byte[] systemSettingsData = getSystemSettings();
    190         byte[] secureSettingsData = getSecureSettings();
    191         byte[] locale = mSettingsHelper.getLocaleData();
    192         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
    193         byte[] wifiConfigData = getFileData(mWifiConfigFile);
    194 
    195         // Write the data to the staging file, then emit that as our tarfile
    196         // representation of the backed-up settings.
    197         String root = getFilesDir().getAbsolutePath();
    198         File stage = new File(root, STAGE_FILE);
    199         try {
    200             FileOutputStream filestream = new FileOutputStream(stage);
    201             BufferedOutputStream bufstream = new BufferedOutputStream(filestream);
    202             DataOutputStream out = new DataOutputStream(bufstream);
    203 
    204             if (DEBUG_BACKUP) Log.d(TAG, "Writing flattened data version " + FULL_BACKUP_VERSION);
    205             out.writeInt(FULL_BACKUP_VERSION);
    206 
    207             if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
    208             out.writeInt(systemSettingsData.length);
    209             out.write(systemSettingsData);
    210             if (DEBUG_BACKUP) Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
    211             out.writeInt(secureSettingsData.length);
    212             out.write(secureSettingsData);
    213             if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
    214             out.writeInt(locale.length);
    215             out.write(locale);
    216             if (DEBUG_BACKUP) Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
    217             out.writeInt(wifiSupplicantData.length);
    218             out.write(wifiSupplicantData);
    219             if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
    220             out.writeInt(wifiConfigData.length);
    221             out.write(wifiConfigData);
    222 
    223             out.flush();    // also flushes downstream
    224 
    225             // now we're set to emit the tar stream
    226             fullBackupFile(stage, data);
    227         } finally {
    228             stage.delete();
    229         }
    230     }
    231 
    232     @Override
    233     public void onRestoreFile(ParcelFileDescriptor data, long size,
    234             int type, String domain, String relpath, long mode, long mtime)
    235             throws IOException {
    236         if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
    237         // Our data is actually a blob of flattened settings data identical to that
    238         // produced during incremental backups.  Just unpack and apply it all in
    239         // turn.
    240         FileInputStream instream = new FileInputStream(data.getFileDescriptor());
    241         DataInputStream in = new DataInputStream(instream);
    242 
    243         int version = in.readInt();
    244         if (DEBUG_BACKUP) Log.d(TAG, "Flattened data version " + version);
    245         if (version == FULL_BACKUP_VERSION) {
    246             // system settings data first
    247             int nBytes = in.readInt();
    248             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of settings data");
    249             byte[] buffer = new byte[nBytes];
    250             in.readFully(buffer, 0, nBytes);
    251             restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI);
    252 
    253             // secure settings
    254             nBytes = in.readInt();
    255             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of secure settings data");
    256             if (nBytes > buffer.length) buffer = new byte[nBytes];
    257             in.readFully(buffer, 0, nBytes);
    258             restoreSettings(buffer, nBytes, Settings.Secure.CONTENT_URI);
    259 
    260             // locale
    261             nBytes = in.readInt();
    262             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of locale data");
    263             if (nBytes > buffer.length) buffer = new byte[nBytes];
    264             in.readFully(buffer, 0, nBytes);
    265             mSettingsHelper.setLocaleData(buffer, nBytes);
    266 
    267             // wifi supplicant
    268             nBytes = in.readInt();
    269             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi supplicant data");
    270             if (nBytes > buffer.length) buffer = new byte[nBytes];
    271             in.readFully(buffer, 0, nBytes);
    272             int retainedWifiState = enableWifi(false);
    273             restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
    274             FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
    275                     FileUtils.S_IRUSR | FileUtils.S_IWUSR |
    276                     FileUtils.S_IRGRP | FileUtils.S_IWGRP,
    277                     Process.myUid(), Process.WIFI_UID);
    278             // retain the previous WIFI state.
    279             enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
    280                     retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
    281 
    282             // wifi config
    283             nBytes = in.readInt();
    284             if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of wifi config data");
    285             if (nBytes > buffer.length) buffer = new byte[nBytes];
    286             in.readFully(buffer, 0, nBytes);
    287             restoreFileData(mWifiConfigFile, buffer, nBytes);
    288 
    289             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
    290         } else {
    291             data.close();
    292             throw new IOException("Invalid file schema");
    293         }
    294     }
    295 
    296     private long[] readOldChecksums(ParcelFileDescriptor oldState) throws IOException {
    297         long[] stateChecksums = new long[STATE_SIZE];
    298 
    299         DataInputStream dataInput = new DataInputStream(
    300                 new FileInputStream(oldState.getFileDescriptor()));
    301 
    302         try {
    303             int stateVersion = dataInput.readInt();
    304             if (stateVersion == STATE_VERSION_1) {
    305                 for (int i = 0; i < STATE_VERSION_1_SIZE; i++) {
    306                     stateChecksums[i] = dataInput.readLong();
    307                 }
    308             } else if (stateVersion == STATE_VERSION) {
    309                 for (int i = 0; i < STATE_SIZE; i++) {
    310                     stateChecksums[i] = dataInput.readLong();
    311                 }
    312             }
    313         } catch (EOFException eof) {
    314             // With the default 0 checksum we'll wind up forcing a backup of
    315             // any unhandled data sets, which is appropriate.
    316         }
    317         dataInput.close();
    318         return stateChecksums;
    319     }
    320 
    321     private void writeNewChecksums(long[] checksums, ParcelFileDescriptor newState)
    322             throws IOException {
    323         DataOutputStream dataOutput = new DataOutputStream(
    324                 new FileOutputStream(newState.getFileDescriptor()));
    325 
    326         dataOutput.writeInt(STATE_VERSION);
    327         for (int i = 0; i < STATE_SIZE; i++) {
    328             dataOutput.writeLong(checksums[i]);
    329         }
    330         dataOutput.close();
    331     }
    332 
    333     private long writeIfChanged(long oldChecksum, String key, byte[] data,
    334             BackupDataOutput output) {
    335         CRC32 checkSummer = new CRC32();
    336         checkSummer.update(data);
    337         long newChecksum = checkSummer.getValue();
    338         if (oldChecksum == newChecksum) {
    339             return oldChecksum;
    340         }
    341         try {
    342             output.writeEntityHeader(key, data.length);
    343             output.writeEntityData(data, data.length);
    344         } catch (IOException ioe) {
    345             // Bail
    346         }
    347         return newChecksum;
    348     }
    349 
    350     private byte[] getSystemSettings() {
    351         Cursor cursor = getContentResolver().query(Settings.System.CONTENT_URI, PROJECTION, null,
    352                 null, null);
    353         try {
    354             return extractRelevantValues(cursor, Settings.System.SETTINGS_TO_BACKUP);
    355         } finally {
    356             cursor.close();
    357         }
    358     }
    359 
    360     private byte[] getSecureSettings() {
    361         Cursor cursor = getContentResolver().query(Settings.Secure.CONTENT_URI, PROJECTION, null,
    362                 null, null);
    363         try {
    364             return extractRelevantValues(cursor, Settings.Secure.SETTINGS_TO_BACKUP);
    365         } finally {
    366             cursor.close();
    367         }
    368     }
    369 
    370     private void restoreSettings(BackupDataInput data, Uri contentUri) {
    371         byte[] settings = new byte[data.getDataSize()];
    372         try {
    373             data.readEntityData(settings, 0, settings.length);
    374         } catch (IOException ioe) {
    375             Log.e(TAG, "Couldn't read entity data");
    376             return;
    377         }
    378         restoreSettings(settings, settings.length, contentUri);
    379     }
    380 
    381     private void restoreSettings(byte[] settings, int bytes, Uri contentUri) {
    382         if (DEBUG) {
    383             Log.i(TAG, "restoreSettings: " + contentUri);
    384         }
    385 
    386         // Figure out the white list.
    387         String[] whitelist = null;
    388         if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
    389             whitelist = Settings.Secure.SETTINGS_TO_BACKUP;
    390         } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
    391             whitelist = Settings.System.SETTINGS_TO_BACKUP;
    392         } else {
    393             throw new IllegalArgumentException("Unknown URI: " + contentUri);
    394         }
    395 
    396         // Restore only the white list data.
    397         int pos = 0;
    398         Map<String, String> cachedEntries = new HashMap<String, String>();
    399         ContentValues contentValues = new ContentValues(2);
    400         SettingsHelper settingsHelper = mSettingsHelper;
    401 
    402         final int whiteListSize = whitelist.length;
    403         for (int i = 0; i < whiteListSize; i++) {
    404             String key = whitelist[i];
    405             String value = cachedEntries.remove(key);
    406 
    407             // If the value not cached, let us look it up.
    408             if (value == null) {
    409                 while (pos < bytes) {
    410                     int length = readInt(settings, pos);
    411                     pos += INTEGER_BYTE_COUNT;
    412                     String dataKey = length > 0 ? new String(settings, pos, length) : null;
    413                     pos += length;
    414                     length = readInt(settings, pos);
    415                     pos += INTEGER_BYTE_COUNT;
    416                     String dataValue = length > 0 ? new String(settings, pos, length) : null;
    417                     pos += length;
    418                     if (key.equals(dataKey)) {
    419                         value = dataValue;
    420                         break;
    421                     }
    422                     cachedEntries.put(dataKey, dataValue);
    423                 }
    424             }
    425 
    426             if (value == null) {
    427                 continue;
    428             }
    429 
    430             if (settingsHelper.restoreValue(key, value)) {
    431                 contentValues.clear();
    432                 contentValues.put(Settings.NameValueTable.NAME, key);
    433                 contentValues.put(Settings.NameValueTable.VALUE, value);
    434                 getContentResolver().insert(contentUri, contentValues);
    435             }
    436 
    437             if (DEBUG) {
    438                 Log.d(TAG, "Restored setting: " + key + "=" + value);
    439             }
    440         }
    441     }
    442 
    443     /**
    444      * Given a cursor and a set of keys, extract the required keys and
    445      * values and write them to a byte array.
    446      *
    447      * @param cursor A cursor with settings data.
    448      * @param settings The settings to extract.
    449      * @return The byte array of extracted values.
    450      */
    451     private byte[] extractRelevantValues(Cursor cursor, String[] settings) {
    452         final int settingsCount = settings.length;
    453         byte[][] values = new byte[settingsCount * 2][]; // keys and values
    454         if (!cursor.moveToFirst()) {
    455             Log.e(TAG, "Couldn't read from the cursor");
    456             return new byte[0];
    457         }
    458 
    459         // Obtain the relevant data in a temporary array.
    460         int totalSize = 0;
    461         int backedUpSettingIndex = 0;
    462         Map<String, String> cachedEntries = new HashMap<String, String>();
    463         for (int i = 0; i < settingsCount; i++) {
    464             String key = settings[i];
    465             String value = cachedEntries.remove(key);
    466 
    467             // If the value not cached, let us look it up.
    468             if (value == null) {
    469                 while (!cursor.isAfterLast()) {
    470                     String cursorKey = cursor.getString(COLUMN_NAME);
    471                     String cursorValue = cursor.getString(COLUMN_VALUE);
    472                     cursor.moveToNext();
    473                     if (key.equals(cursorKey)) {
    474                         value = cursorValue;
    475                         break;
    476                     }
    477                     cachedEntries.put(cursorKey, cursorValue);
    478                 }
    479             }
    480 
    481             if (value == null) {
    482                 continue;
    483             }
    484 
    485             // Write the key and value in the intermediary array.
    486             byte[] keyBytes = key.getBytes();
    487             totalSize += INTEGER_BYTE_COUNT + keyBytes.length;
    488             values[backedUpSettingIndex * 2] = keyBytes;
    489 
    490             byte[] valueBytes = value.getBytes();
    491             totalSize += INTEGER_BYTE_COUNT + valueBytes.length;
    492             values[backedUpSettingIndex * 2 + 1] = valueBytes;
    493 
    494             backedUpSettingIndex++;
    495 
    496             if (DEBUG) {
    497                 Log.d(TAG, "Backed up setting: " + key + "=" + value);
    498             }
    499         }
    500 
    501         // Aggregate the result.
    502         byte[] result = new byte[totalSize];
    503         int pos = 0;
    504         final int keyValuePairCount = backedUpSettingIndex * 2;
    505         for (int i = 0; i < keyValuePairCount; i++) {
    506             pos = writeInt(result, pos, values[i].length);
    507             pos = writeBytes(result, pos, values[i]);
    508         }
    509         return result;
    510     }
    511 
    512     private byte[] getFileData(String filename) {
    513         InputStream is = null;
    514         try {
    515             File file = new File(filename);
    516             is = new FileInputStream(file);
    517 
    518             //Will truncate read on a very long file,
    519             //should not happen for a config file
    520             byte[] bytes = new byte[(int)file.length()];
    521 
    522             int offset = 0;
    523             int numRead = 0;
    524             while (offset < bytes.length
    525                     && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
    526                 offset += numRead;
    527             }
    528 
    529             //read failure
    530             if (offset < bytes.length) {
    531                 Log.w(TAG, "Couldn't backup " + filename);
    532                 return EMPTY_DATA;
    533             }
    534             return bytes;
    535         } catch (IOException ioe) {
    536             Log.w(TAG, "Couldn't backup " + filename);
    537             return EMPTY_DATA;
    538         } finally {
    539             if (is != null) {
    540                 try {
    541                     is.close();
    542                 } catch (IOException e) {
    543                 }
    544             }
    545         }
    546 
    547     }
    548 
    549     private void restoreFileData(String filename, BackupDataInput data) {
    550         byte[] bytes = new byte[data.getDataSize()];
    551         if (bytes.length <= 0) return;
    552         try {
    553             data.readEntityData(bytes, 0, data.getDataSize());
    554             restoreFileData(filename, bytes, bytes.length);
    555         } catch (IOException e) {
    556             Log.w(TAG, "Unable to read file data for " + filename);
    557         }
    558     }
    559 
    560     private void restoreFileData(String filename, byte[] bytes, int size) {
    561         try {
    562             File file = new File(filename);
    563             if (file.exists()) file.delete();
    564 
    565             OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
    566             os.write(bytes, 0, size);
    567             os.close();
    568         } catch (IOException ioe) {
    569             Log.w(TAG, "Couldn't restore " + filename);
    570         }
    571     }
    572 
    573 
    574     private byte[] getWifiSupplicant(String filename) {
    575         BufferedReader br = null;
    576         try {
    577             File file = new File(filename);
    578             if (file.exists()) {
    579                 br = new BufferedReader(new FileReader(file));
    580                 StringBuffer relevantLines = new StringBuffer();
    581                 boolean started = false;
    582                 String line;
    583                 while ((line = br.readLine()) != null) {
    584                     if (!started && line.startsWith("network")) {
    585                         started = true;
    586                     }
    587                     if (started) {
    588                         relevantLines.append(line).append("\n");
    589                     }
    590                 }
    591                 if (relevantLines.length() > 0) {
    592                     return relevantLines.toString().getBytes();
    593                 } else {
    594                     return EMPTY_DATA;
    595                 }
    596             } else {
    597                 return EMPTY_DATA;
    598             }
    599         } catch (IOException ioe) {
    600             Log.w(TAG, "Couldn't backup " + filename);
    601             return EMPTY_DATA;
    602         } finally {
    603             if (br != null) {
    604                 try {
    605                     br.close();
    606                 } catch (IOException e) {
    607                 }
    608             }
    609         }
    610     }
    611 
    612     private void restoreWifiSupplicant(String filename, BackupDataInput data) {
    613         byte[] bytes = new byte[data.getDataSize()];
    614         if (bytes.length <= 0) return;
    615         try {
    616             data.readEntityData(bytes, 0, data.getDataSize());
    617             restoreWifiSupplicant(filename, bytes, bytes.length);
    618         } catch (IOException e) {
    619             Log.w(TAG, "Unable to read supplicant data");
    620         }
    621     }
    622 
    623     private void restoreWifiSupplicant(String filename, byte[] bytes, int size) {
    624         try {
    625             File supplicantFile = new File(FILE_WIFI_SUPPLICANT);
    626             if (supplicantFile.exists()) supplicantFile.delete();
    627             copyWifiSupplicantTemplate();
    628 
    629             OutputStream os = new BufferedOutputStream(new FileOutputStream(filename, true));
    630             os.write("\n".getBytes());
    631             os.write(bytes, 0, size);
    632             os.close();
    633         } catch (IOException ioe) {
    634             Log.w(TAG, "Couldn't restore " + filename);
    635         }
    636     }
    637 
    638     private void copyWifiSupplicantTemplate() {
    639         try {
    640             BufferedReader br = new BufferedReader(new FileReader(FILE_WIFI_SUPPLICANT_TEMPLATE));
    641             BufferedWriter bw = new BufferedWriter(new FileWriter(FILE_WIFI_SUPPLICANT));
    642             char[] temp = new char[1024];
    643             int size;
    644             while ((size = br.read(temp)) > 0) {
    645                 bw.write(temp, 0, size);
    646             }
    647             bw.close();
    648             br.close();
    649         } catch (IOException ioe) {
    650             Log.w(TAG, "Couldn't copy wpa_supplicant file");
    651         }
    652     }
    653 
    654     /**
    655      * Write an int in BigEndian into the byte array.
    656      * @param out byte array
    657      * @param pos current pos in array
    658      * @param value integer to write
    659      * @return the index after adding the size of an int (4) in bytes.
    660      */
    661     private int writeInt(byte[] out, int pos, int value) {
    662         out[pos + 0] = (byte) ((value >> 24) & 0xFF);
    663         out[pos + 1] = (byte) ((value >> 16) & 0xFF);
    664         out[pos + 2] = (byte) ((value >>  8) & 0xFF);
    665         out[pos + 3] = (byte) ((value >>  0) & 0xFF);
    666         return pos + INTEGER_BYTE_COUNT;
    667     }
    668 
    669     private int writeBytes(byte[] out, int pos, byte[] value) {
    670         System.arraycopy(value, 0, out, pos, value.length);
    671         return pos + value.length;
    672     }
    673 
    674     private int readInt(byte[] in, int pos) {
    675         int result =
    676                 ((in[pos    ] & 0xFF) << 24) |
    677                 ((in[pos + 1] & 0xFF) << 16) |
    678                 ((in[pos + 2] & 0xFF) <<  8) |
    679                 ((in[pos + 3] & 0xFF) <<  0);
    680         return result;
    681     }
    682 
    683     private int enableWifi(boolean enable) {
    684         if (mWfm != null) {
    685             int state = mWfm.getWifiState();
    686             mWfm.setWifiEnabled(enable);
    687             return state;
    688         }
    689         return WifiManager.WIFI_STATE_UNKNOWN;
    690     }
    691 }
    692