Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 188ae9dc authored by Ritesh Reddy's avatar Ritesh Reddy
Browse files

Enabled SoftAP Configuration Backup

Backing up SoftAP Configuration through WifiManager API.

Bug: 5343116
Change-Id: If17effb98c3489246d817fa3612f3f11b9ead9ab
parent 1a3c1650
Loading
Loading
Loading
Loading
+68 −32
Original line number Diff line number Diff line
@@ -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,8 +96,9 @@ 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[] = {
@@ -104,13 +106,15 @@ public class SettingsBackupAgent extends BackupAgentHelper {
            4,              // version 1
            5,              // version 2 added STATE_WIFI_CONFIG
            6,              // version 3 added STATE_GLOBAL
        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
            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;

@@ -405,6 +409,7 @@ 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);

@@ -425,6 +430,9 @@ public class SettingsBackupAgent extends BackupAgentHelper {
        stateChecksums[STATE_LOCK_SETTINGS] =
                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);
    }
@@ -561,6 +569,10 @@ public class SettingsBackupAgent extends BackupAgentHelper {
                mWifiRestore.incorporateWifiConfigFile(data);
            } else if (KEY_LOCK_SETTINGS.equals(key)) {
                restoreLockSettings(data);
            } 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

@@ -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();
@@ -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
+400 −0
Original line number Diff line number Diff line
/*
 * 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);
        }
    }
}