OSDN Git Service

Enabled SoftAP Configuration Backup
authorRitesh Reddy <riteshr@google.com>
Tue, 24 Nov 2015 17:57:13 +0000 (17:57 +0000)
committerRitesh Reddy <riteshr@google.com>
Tue, 8 Dec 2015 10:21:53 +0000 (10:21 +0000)
Backing up SoftAP Configuration through WifiManager API.

Bug: 5343116
Change-Id: If17effb98c3489246d817fa3612f3f11b9ead9ab

packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java [new file with mode: 0644]

index 2e96f18..8910af4 100644 (file)
@@ -81,10 +81,11 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
     private static final String KEY_LOCK_SETTINGS = "lock_settings";
+    private static final String KEY_SOFTAP_CONFIG = "softap_config";
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 4;
+    private static final int STATE_VERSION = 5;
 
     // Slots in the checksum array.  Never insert new items in the middle
     // of this array; new slots must be appended.
@@ -95,22 +96,25 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     private static final int STATE_WIFI_CONFIG     = 4;
     private static final int STATE_GLOBAL          = 5;
     private static final int STATE_LOCK_SETTINGS   = 6;
+    private static final int STATE_SOFTAP_CONFIG   = 7;
 
-    private static final int STATE_SIZE            = 7; // The current number of state items
+    private static final int STATE_SIZE            = 8; // The current number of state items
 
     // Number of entries in the checksum array at various version numbers
     private static final int STATE_SIZES[] = {
-        0,
-        4,              // version 1
-        5,              // version 2 added STATE_WIFI_CONFIG
-        6,              // version 3 added STATE_GLOBAL
-        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
+            0,
+            4,              // version 1
+            5,              // version 2 added STATE_WIFI_CONFIG
+            6,              // version 3 added STATE_GLOBAL
+            7,              // version 4 added STATE_LOCK_SETTINGS
+            STATE_SIZE      // version 5 added STATE_SOFTAP_CONFIG
     };
 
     // Versioning of the 'full backup' format
     private static final int FULL_BACKUP_VERSION = 3;
     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
     private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
+    private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -119,8 +123,8 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     private static final String TAG = "SettingsBackupAgent";
 
     private static final String[] PROJECTION = {
-        Settings.NameValueTable.NAME,
-        Settings.NameValueTable.VALUE
+            Settings.NameValueTable.NAME,
+            Settings.NameValueTable.VALUE
     };
 
     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
@@ -396,7 +400,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
 
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
-            ParcelFileDescriptor newState) throws IOException {
+                         ParcelFileDescriptor newState) throws IOException {
 
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
@@ -405,26 +409,30 @@ public class SettingsBackupAgent extends BackupAgentHelper {
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
+        byte[] softApConfigData = getSoftAPConfiguration();
 
         long[] stateChecksums = readOldChecksums(oldState);
 
         stateChecksums[STATE_SYSTEM] =
-            writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
         stateChecksums[STATE_SECURE] =
-            writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
         stateChecksums[STATE_GLOBAL] =
-            writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
         stateChecksums[STATE_LOCALE] =
-            writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
+                writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI_SUPPLICANT] =
-            writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
-                    wifiSupplicantData, data);
+                writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+                        wifiSupplicantData, data);
         stateChecksums[STATE_WIFI_CONFIG] =
-            writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
-                    data);
+                writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+                        data);
         stateChecksums[STATE_LOCK_SETTINGS] =
-            writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
-                    lockSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+                        lockSettingsData, data);
+        stateChecksums[STATE_SOFTAP_CONFIG] =
+                writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
+                        softApConfigData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -504,7 +512,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
                             restoredSupplicantData, restoredSupplicantData.length);
                     FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                             FileUtils.S_IRUSR | FileUtils.S_IWUSR |
-                            FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                                    FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                             Process.myUid(), Process.WIFI_UID);
                 }
                 if (restoredWifiConfigFile != null) {
@@ -533,7 +541,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode,
-            ParcelFileDescriptor newState) throws IOException {
+                          ParcelFileDescriptor newState) throws IOException {
 
         HashSet<String> movedToGlobal = new HashSet<String>();
         Settings.System.getMovedToGlobalSettings(movedToGlobal);
@@ -561,7 +569,11 @@ public class SettingsBackupAgent extends BackupAgentHelper {
                 mWifiRestore.incorporateWifiConfigFile(data);
             } else if (KEY_LOCK_SETTINGS.equals(key)) {
                 restoreLockSettings(data);
-             } else {
+            } else if (KEY_SOFTAP_CONFIG.equals(key)){
+                byte[] softapData = new byte[size];
+                data.readEntityData(softapData, 0, size);
+                restoreSoftApConfiguration(softapData);
+            } else {
                 data.skipEntityData();
             }
         }
@@ -589,6 +601,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
+        byte[] softApConfigData = getSoftAPConfiguration();
 
         // Write the data to the staging file, then emit that as our tarfile
         // representation of the backed-up settings.
@@ -623,6 +636,9 @@ public class SettingsBackupAgent extends BackupAgentHelper {
             if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
             out.writeInt(lockSettingsData.length);
             out.write(lockSettingsData);
+            if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
+            out.writeInt(softApConfigData.length);
+            out.write(softApConfigData);
 
             out.flush();    // also flushes downstream
 
@@ -635,7 +651,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
 
     @Override
     public void onRestoreFile(ParcelFileDescriptor data, long size,
-            int type, String domain, String relpath, long mode, long mtime)
+                              int type, String domain, String relpath, long mode, long mtime)
             throws IOException {
         if (DEBUG_BACKUP) Log.d(TAG, "onRestoreFile() invoked");
         // Our data is actually a blob of flattened settings data identical to that
@@ -692,7 +708,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
             restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
             FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
                     FileUtils.S_IRUSR | FileUtils.S_IWUSR |
-                    FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                            FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                     Process.myUid(), Process.WIFI_UID);
             // retain the previous WIFI state.
             enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
@@ -715,6 +731,16 @@ public class SettingsBackupAgent extends BackupAgentHelper {
                 }
             }
 
+            if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF){
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreSoftApConfiguration(buffer);
+                }
+            }
+
             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
         } else {
             data.close();
@@ -754,7 +780,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     }
 
     private long writeIfChanged(long oldChecksum, String key, byte[] data,
-            BackupDataOutput output) {
+                                BackupDataOutput output) {
         CRC32 checkSummer = new CRC32();
         checkSummer.update(data);
         long newChecksum = checkSummer.getValue();
@@ -829,7 +855,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     }
 
     private void restoreSettings(BackupDataInput data, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+                                 HashSet<String> movedToGlobal) {
         byte[] settings = new byte[data.getDataSize()];
         try {
             data.readEntityData(settings, 0, settings.length);
@@ -841,7 +867,7 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     }
 
     private void restoreSettings(byte[] settings, int bytes, Uri contentUri,
-            HashSet<String> movedToGlobal) {
+                                 HashSet<String> movedToGlobal) {
         if (DEBUG) {
             Log.i(TAG, "restoreSettings: " + contentUri);
         }
@@ -1160,6 +1186,16 @@ public class SettingsBackupAgent extends BackupAgentHelper {
         }
     }
 
+    private byte[] getSoftAPConfiguration(){
+        WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
+        return WiFiConfigurationSerializer.marshalWifiConfig(wifiManager.getWifiApConfiguration());
+    }
+
+    private void restoreSoftApConfiguration(byte[] data){
+        WifiManager wifiManager = (WifiManager)getSystemService(Context.WIFI_SERVICE);
+        wifiManager.setWifiApConfiguration(WiFiConfigurationSerializer.unmarshalWifiConfig(data));
+    }
+
     /**
      * Write an int in BigEndian into the byte array.
      * @param out byte array
@@ -1183,9 +1219,9 @@ public class SettingsBackupAgent extends BackupAgentHelper {
     private int readInt(byte[] in, int pos) {
         int result =
                 ((in[pos    ] & 0xFF) << 24) |
-                ((in[pos + 1] & 0xFF) << 16) |
-                ((in[pos + 2] & 0xFF) <<  8) |
-                ((in[pos + 3] & 0xFF) <<  0);
+                        ((in[pos + 1] & 0xFF) << 16) |
+                        ((in[pos + 2] & 0xFF) <<  8) |
+                        ((in[pos + 3] & 0xFF) <<  0);
         return result;
     }
 
@@ -1202,4 +1238,4 @@ public class SettingsBackupAgent extends BackupAgentHelper {
         }
         return WifiManager.WIFI_STATE_UNKNOWN;
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java b/packages/SettingsProvider/src/com/android/providers/settings/WiFiConfigurationSerializer.java
new file mode 100644 (file)
index 0000000..f9f1d3f
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.providers.settings;
+
+import android.net.IpConfiguration;
+import android.net.LinkAddress;
+import android.net.ProxyInfo;
+import android.net.StaticIpConfiguration;
+import android.net.wifi.WifiConfiguration;
+import android.util.Log;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.BitSet;
+
+
+/**
+ * Backup/Restore Serializer Class for com.android.net.wifi.WifiConfiguration
+ */
+public class WiFiConfigurationSerializer {
+    private static final boolean DEBUG = false;
+    private static final String TAG = "WiFiConfigSerializer";
+
+    private static final int NULL = 0;
+    private static final int NOT_NULL = 1;
+    /**
+     * Current Version of the Serializer.
+     */
+    private static int STATE_VERSION = 1;
+
+
+    /**
+     * Marshals a WifiConfig object into a byte-array.
+     *
+     * @param wifiConfig - WifiConfiguration to be Marshalled
+     * @return byte array
+     */
+
+    public static byte[] marshalWifiConfig(WifiConfiguration wifiConfig) {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if(wifiConfig != null) {
+            DataOutputStream out = new DataOutputStream(baos);
+            try {
+                out.writeInt(STATE_VERSION);
+                out.writeInt(wifiConfig.networkId);
+                out.writeInt(wifiConfig.status);
+                out.writeInt(wifiConfig.disableReason);
+                writeString(out, wifiConfig.SSID);
+                writeString(out, wifiConfig.BSSID);
+                out.writeInt(wifiConfig.apBand);
+                out.writeInt(wifiConfig.apChannel);
+                writeString(out, wifiConfig.autoJoinBSSID);
+                writeString(out, wifiConfig.FQDN);
+                writeString(out, wifiConfig.providerFriendlyName);
+                out.writeInt(wifiConfig.roamingConsortiumIds.length);
+                for (long id : wifiConfig.roamingConsortiumIds) {
+                    out.writeLong(id);
+                }
+                writeString(out, wifiConfig.preSharedKey);
+                for (String wepKey : wifiConfig.wepKeys) {
+                    writeString(out, wepKey);
+                }
+                out.writeInt(wifiConfig.wepTxKeyIndex);
+                out.writeInt(wifiConfig.priority);
+                out.writeInt(wifiConfig.hiddenSSID ? 1 : 0);
+                out.writeInt(wifiConfig.requirePMF ? 1 : 0);
+                writeString(out, wifiConfig.updateIdentifier);
+
+                writeBitSet(out, wifiConfig.allowedKeyManagement);
+                writeBitSet(out, wifiConfig.allowedProtocols);
+                writeBitSet(out, wifiConfig.allowedAuthAlgorithms);
+                writeBitSet(out, wifiConfig.allowedPairwiseCiphers);
+                writeBitSet(out, wifiConfig.allowedGroupCiphers);
+
+
+                //IpConfiguration
+                writeIpConfiguration(out, wifiConfig.getIpConfiguration());
+
+                writeString(out, wifiConfig.dhcpServer);
+                writeString(out, wifiConfig.defaultGwMacAddress);
+                out.writeInt(wifiConfig.autoJoinStatus);
+                out.writeInt(wifiConfig.selfAdded ? 1 : 0);
+                out.writeInt(wifiConfig.didSelfAdd ? 1 : 0);
+                out.writeInt(wifiConfig.validatedInternetAccess ? 1 : 0);
+                out.writeInt(wifiConfig.ephemeral ? 1 : 0);
+                out.writeInt(wifiConfig.creatorUid);
+                out.writeInt(wifiConfig.lastConnectUid);
+                out.writeInt(wifiConfig.lastUpdateUid);
+                writeString(out, wifiConfig.creatorName);
+                writeString(out, wifiConfig.lastUpdateName);
+                out.writeLong(wifiConfig.blackListTimestamp);
+                out.writeLong(wifiConfig.lastConnectionFailure);
+                out.writeLong(wifiConfig.lastRoamingFailure);
+                out.writeInt(wifiConfig.lastRoamingFailureReason);
+                out.writeLong(wifiConfig.roamingFailureBlackListTimeMilli);
+                out.writeLong(wifiConfig.numConnectionFailures);
+                out.writeLong(wifiConfig.numIpConfigFailures);
+                out.writeInt(wifiConfig.numAuthFailures);
+                out.writeInt(wifiConfig.numScorerOverride);
+                out.writeInt(wifiConfig.numScorerOverrideAndSwitchedNetwork);
+                out.writeInt(wifiConfig.numAssociation);
+                out.writeInt(wifiConfig.numUserTriggeredWifiDisableLowRSSI);
+                out.writeInt(wifiConfig.numUserTriggeredWifiDisableBadRSSI);
+                out.writeInt(wifiConfig.numUserTriggeredWifiDisableNotHighRSSI);
+                out.writeInt(wifiConfig.numTicksAtLowRSSI);
+                out.writeInt(wifiConfig.numTicksAtBadRSSI);
+                out.writeInt(wifiConfig.numTicksAtNotHighRSSI);
+                out.writeInt(wifiConfig.numUserTriggeredJoinAttempts);
+                out.writeInt(wifiConfig.autoJoinUseAggressiveJoinAttemptThreshold);
+                out.writeInt(wifiConfig.autoJoinBailedDueToLowRssi ? 1 : 0);
+                out.writeInt(wifiConfig.userApproved);
+                out.writeInt(wifiConfig.numNoInternetAccessReports);
+                out.writeInt(wifiConfig.noInternetAccessExpected ? 1 : 0);
+            } catch (IOException ioe) {
+                Log.e(TAG, "Failed to Convert WifiConfiguration to byte array", ioe);
+                baos.reset();
+            }
+        }
+        return baos.toByteArray();
+    }
+
+    /**
+     * Unmarshals a byte array into a WifiConfig Object
+     *
+     * @param data - marshalled WifiConfig Object
+     * @return WifiConfiguration Object
+     */
+
+    public static WifiConfiguration unmarshalWifiConfig(byte[] data) {
+        if (data == null ||  data.length == 0) {
+            return null;
+        }
+        DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+        WifiConfiguration config = new WifiConfiguration();
+        try {
+            int version = in.readInt();
+
+            config.networkId = in.readInt();
+            config.status = in.readInt();
+            config.disableReason = in.readInt();
+            config.SSID = readString(in, version);
+            config.BSSID = readString(in, version);
+            config.apBand = in.readInt();
+            config.apChannel = in.readInt();
+            config.autoJoinBSSID = readString(in, version);
+            config.FQDN = readString(in, version);
+            config.providerFriendlyName = readString(in, version);
+            int numRoamingConsortiumIds = in.readInt();
+            config.roamingConsortiumIds = new long[numRoamingConsortiumIds];
+            for (int i = 0; i < numRoamingConsortiumIds; i++) {
+                config.roamingConsortiumIds[i] = in.readLong();
+            }
+            config.preSharedKey = readString(in, version);
+            for (int i = 0; i < config.wepKeys.length; i++) {
+                config.wepKeys[i] = readString(in, version);
+            }
+            config.wepTxKeyIndex = in.readInt();
+            config.priority = in.readInt();
+            config.hiddenSSID = in.readInt() != 0;
+            config.requirePMF = in.readInt() != 0;
+            config.updateIdentifier = readString(in, version);
+
+            config.allowedKeyManagement = readBitSet(in, version);
+            config.allowedProtocols = readBitSet(in, version);
+            config.allowedAuthAlgorithms = readBitSet(in, version);
+            config.allowedPairwiseCiphers = readBitSet(in, version);
+            config.allowedGroupCiphers = readBitSet(in, version);
+
+            //Not backed-up because EnterpriseConfig involves
+            //Certificates which are device specific.
+            //config.enterpriseConfig = new WifiEnterpriseConfig();
+
+            config.setIpConfiguration(readIpConfiguration(in, version));
+
+
+            config.dhcpServer = readString(in, version);
+            config.defaultGwMacAddress = readString(in, version);
+            config.autoJoinStatus = in.readInt();
+            config.selfAdded = in.readInt() != 0;
+            config.didSelfAdd = in.readInt() != 0;
+            config.validatedInternetAccess = in.readInt() != 0;
+            config.ephemeral = in.readInt() != 0;
+            config.creatorUid = in.readInt();
+            config.lastConnectUid = in.readInt();
+            config.lastUpdateUid = in.readInt();
+            config.creatorName = readString(in, version);
+            config.lastUpdateName = readString(in, version);
+            config.blackListTimestamp = in.readLong();
+            config.lastConnectionFailure = in.readLong();
+            config.lastRoamingFailure = in.readLong();
+            config.lastRoamingFailureReason = in.readInt();
+            config.roamingFailureBlackListTimeMilli = in.readLong();
+            config.numConnectionFailures = in.readInt();
+            config.numIpConfigFailures = in.readInt();
+            config.numAuthFailures = in.readInt();
+            config.numScorerOverride = in.readInt();
+            config.numScorerOverrideAndSwitchedNetwork = in.readInt();
+            config.numAssociation = in.readInt();
+            config.numUserTriggeredWifiDisableLowRSSI = in.readInt();
+            config.numUserTriggeredWifiDisableBadRSSI = in.readInt();
+            config.numUserTriggeredWifiDisableNotHighRSSI = in.readInt();
+            config.numTicksAtLowRSSI = in.readInt();
+            config.numTicksAtBadRSSI = in.readInt();
+            config.numTicksAtNotHighRSSI = in.readInt();
+            config.numUserTriggeredJoinAttempts = in.readInt();
+            config.autoJoinUseAggressiveJoinAttemptThreshold = in.readInt();
+            config.autoJoinBailedDueToLowRssi = in.readInt() != 0;
+            config.userApproved = in.readInt();
+            config.numNoInternetAccessReports = in.readInt();
+            config.noInternetAccessExpected = in.readInt() != 0;
+        } catch (IOException ioe) {
+            Log.e(TAG, "Failed to convert byte array to WifiConfiguration object", ioe);
+            return null;
+        }
+        return config;
+    }
+
+    private static ProxyInfo readProxyInfo(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        String host = readString(in, version);
+        int port = in.readInt();
+        String exclusionList = readString(in, version);
+        return new ProxyInfo(host, port, exclusionList);
+    }
+
+    private static void writeProxyInfo(DataOutputStream out, ProxyInfo proxyInfo) throws IOException {
+        if (proxyInfo != null) {
+            out.writeByte(NOT_NULL);
+            writeString(out, proxyInfo.getHost());
+            out.writeInt(proxyInfo.getPort());
+            writeString(out, proxyInfo.getExclusionListAsString());
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static InetAddress readInetAddress(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        InetAddress address = null;
+        int addressLength = in.readInt();
+        if (addressLength < 1) return address;
+        byte[] addressBytes = new byte[addressLength];
+        in.read(addressBytes, 0, addressLength);
+        try {
+            address = InetAddress.getByAddress(addressBytes);
+        } catch (UnknownHostException unknownHostException) {
+            return null;
+        }
+        return address;
+    }
+
+    private static void writeInetAddress(DataOutputStream out, InetAddress address) throws IOException {
+        if (address.getAddress() != null) {
+            out.writeByte(NOT_NULL);
+            out.writeInt(address.getAddress().length);
+            out.write(address.getAddress(), 0, address.getAddress().length);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static LinkAddress readLinkAddress(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        InetAddress address = readInetAddress(in, version);
+        int prefixLength = in.readInt();
+        int flags = in.readInt();
+        int scope = in.readInt();
+        return new LinkAddress(address, prefixLength, flags, scope);
+    }
+
+    private static void writeLinkAddress(DataOutputStream out, LinkAddress address) throws IOException {
+        if (address != null) {
+            out.writeByte(NOT_NULL);
+            writeInetAddress(out, address.getAddress());
+            out.writeInt(address.getPrefixLength());
+            out.writeInt(address.getFlags());
+            out.writeInt(address.getScope());
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static StaticIpConfiguration readStaticIpConfiguration(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        StaticIpConfiguration staticIpConfiguration = new StaticIpConfiguration();
+        staticIpConfiguration.ipAddress = readLinkAddress(in, version);
+        staticIpConfiguration.gateway = readInetAddress(in, version);
+        int dnsServersLength = in.readInt();
+        for (int i = 0; i < dnsServersLength; i++) {
+            staticIpConfiguration.dnsServers.add(readInetAddress(in, version));
+        }
+        staticIpConfiguration.domains = readString(in, version);
+        return staticIpConfiguration;
+    }
+
+    private static void writeStaticIpConfiguration(DataOutputStream out, StaticIpConfiguration staticIpConfiguration) throws IOException {
+        if (staticIpConfiguration != null) {
+            out.writeByte(NOT_NULL);
+            writeLinkAddress(out, staticIpConfiguration.ipAddress);
+            writeInetAddress(out, staticIpConfiguration.gateway);
+            out.writeInt(staticIpConfiguration.dnsServers.size());
+            for (InetAddress inetAddress : staticIpConfiguration.dnsServers) {
+                writeInetAddress(out, inetAddress);
+            }
+            writeString(out, staticIpConfiguration.domains);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static IpConfiguration readIpConfiguration(DataInputStream in, int version) throws IOException {
+        int isNull = in.readByte();
+        if (isNull == NULL) return null;
+        IpConfiguration ipConfiguration = new IpConfiguration();
+        String tmp = readString(in, version);
+        ipConfiguration.ipAssignment = tmp == null ? null : IpConfiguration.IpAssignment.valueOf(tmp);
+        tmp = readString(in, version);
+        ipConfiguration.proxySettings = tmp == null ? null : IpConfiguration.ProxySettings.valueOf(tmp);
+        ipConfiguration.staticIpConfiguration = readStaticIpConfiguration(in, version);
+        ipConfiguration.httpProxy = readProxyInfo(in, version);
+        return ipConfiguration;
+    }
+
+
+    private static void writeIpConfiguration(DataOutputStream out, IpConfiguration ipConfiguration) throws IOException {
+        if (ipConfiguration != null) {
+            out.writeByte(NOT_NULL);
+            writeString(out, ipConfiguration.ipAssignment != null ? ipConfiguration.ipAssignment.name() : null);
+            writeString(out, ipConfiguration.proxySettings != null ? ipConfiguration.proxySettings.name() : null);
+            writeStaticIpConfiguration(out, ipConfiguration.staticIpConfiguration);
+            writeProxyInfo(out, ipConfiguration.httpProxy);
+        } else {
+            out.writeByte(NULL);
+        }
+
+    }
+
+    private static String readString(DataInputStream in, int version) throws IOException {
+        byte isNull = in.readByte();
+        if (isNull == NOT_NULL) {
+            return in.readUTF();
+        }
+        return null;
+    }
+
+    private static void writeString(DataOutputStream out, String val) throws IOException {
+        if (val != null) {
+            out.writeByte(NOT_NULL);
+            out.writeUTF(val);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+
+    private static BitSet readBitSet(DataInputStream in, int version) throws IOException {
+        byte isNull = in.readByte();
+        if (isNull == NOT_NULL) {
+            int length = in.readInt();
+            byte[] bytes = new byte[length];
+            in.read(bytes, 0, length);
+            return BitSet.valueOf(bytes);
+        }
+        return new BitSet();
+    }
+
+    private static void writeBitSet(DataOutputStream out, BitSet val) throws IOException {
+        if (val != null) {
+            out.writeByte(NOT_NULL);
+            byte[] byteArray = val.toByteArray();
+            out.writeInt(byteArray.length);
+            out.write(byteArray);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+}