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

Commit ffcea7ae authored by Irfan Sheriff's avatar Irfan Sheriff
Browse files

Move softap config handling to WifiConfigStore

Move softap config to flat file and read/write on a seperate handler thread

Bug: 4391796

Change-Id: Iafe43200d7f829df7ced20a4e7b0ed451ad22a05
parent da480945
Loading
Loading
Loading
Loading
+6 −45
Original line number Diff line number Diff line
@@ -559,31 +559,10 @@ public class WifiService extends IWifiManager.Stub {
     * @param wifiConfig SSID, security and channel details as
     *        part of WifiConfiguration
     * @param enabled true to enable and false to disable
     * @return {@code true} if the start operation was
     *         started or is already in the queue.
     */
    public synchronized boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
    public void setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
        enforceChangePermission();

        if (enabled) {
            /* Use default config if there is no existing config */
            if (wifiConfig == null && ((wifiConfig = getWifiApConfiguration()) == null)) {
                wifiConfig = new WifiConfiguration();
                wifiConfig.SSID = mContext.getString(R.string.wifi_tether_configure_ssid_default);
                wifiConfig.allowedKeyManagement.set(KeyMgmt.NONE);
            }
            /*
             * Caller might not have WRITE_SECURE_SETTINGS,
             * only CHANGE_WIFI_STATE is enforced
             */
            long ident = Binder.clearCallingIdentity();
            setWifiApConfiguration(wifiConfig);
            Binder.restoreCallingIdentity(ident);
        }

        mWifiStateMachine.setWifiApEnabled(wifiConfig, enabled);

        return true;
    }

    /**
@@ -603,38 +582,20 @@ public class WifiService extends IWifiManager.Stub {
     * see {@link WifiManager#getWifiApConfiguration()}
     * @return soft access point configuration
     */
    public synchronized WifiConfiguration getWifiApConfiguration() {
        final ContentResolver cr = mContext.getContentResolver();
        WifiConfiguration wifiConfig = new WifiConfiguration();
        int authType;
        try {
            wifiConfig.SSID = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_SSID);
            if (wifiConfig.SSID == null)
                return null;
            authType = Settings.Secure.getInt(cr, Settings.Secure.WIFI_AP_SECURITY);
            wifiConfig.allowedKeyManagement.set(authType);
            wifiConfig.preSharedKey = Settings.Secure.getString(cr, Settings.Secure.WIFI_AP_PASSWD);
            return wifiConfig;
        } catch (Settings.SettingNotFoundException e) {
            Slog.e(TAG,"AP settings not found, returning");
            return null;
        }
    public WifiConfiguration getWifiApConfiguration() {
        enforceAccessPermission();
        return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
    }

    /**
     * see {@link WifiManager#setWifiApConfiguration(WifiConfiguration)}
     * @param wifiConfig WifiConfiguration details for soft access point
     */
    public synchronized void setWifiApConfiguration(WifiConfiguration wifiConfig) {
    public void setWifiApConfiguration(WifiConfiguration wifiConfig) {
        enforceChangePermission();
        final ContentResolver cr = mContext.getContentResolver();
        if (wifiConfig == null)
            return;
        int authType = wifiConfig.getAuthType();
        Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_SSID, wifiConfig.SSID);
        Settings.Secure.putInt(cr, Settings.Secure.WIFI_AP_SECURITY, authType);
        if (authType != KeyMgmt.NONE)
            Settings.Secure.putString(cr, Settings.Secure.WIFI_AP_PASSWD, wifiConfig.preSharedKey);
        mWifiStateMachine.setWifiApConfiguration(wifiConfig);
    }

    /**
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ interface IWifiManager

    void releaseMulticastLock();

    boolean setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
    void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);

    int getWifiApEnabledState();

+181 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2010 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 android.net.wifi;

import android.content.Context;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.os.Environment;
import android.os.Message;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.util.UUID;

import com.android.internal.R;


/**
 * Provides API to the WifiStateMachine for doing read/write access
 * to soft access point configuration
 */
class WifiApConfigStore {

    private static Context sContext;
    private static final String TAG = "WifiApConfigStore";

    private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
        "/misc/wifi/softap.conf";

    private static final int AP_CONFIG_FILE_VERSION = 1;

    private static WifiConfiguration sApConfig = new WifiConfiguration();
    private static final Object sApConfigLock = new Object();

    private static FileReadWriteHandler sFileReadWriteHandler;
    private static final int READ_AP_CONFIG               = 1;
    private static final int WRITE_AP_CONFIG              = 2;

    static void initialize(Context context) {
        sContext = context;

        /* File operations happen on a seperate thread */
        HandlerThread configThread = new HandlerThread("WifiApConfigStore");
        configThread.start();
        sFileReadWriteHandler = new FileReadWriteHandler(configThread.getLooper());
        Message.obtain(sFileReadWriteHandler, READ_AP_CONFIG).sendToTarget();
    }


    static void setApConfiguration(WifiConfiguration config) {
        synchronized (sApConfigLock) {
            sApConfig = config;
        }
        Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config))
            .sendToTarget();
    }

    static WifiConfiguration getApConfiguration() {
        synchronized (sApConfigLock) {
            return new WifiConfiguration(sApConfig);
        }
    }

    /**
     * File read/write handler
     */
    private static class FileReadWriteHandler extends Handler {

        public FileReadWriteHandler(android.os.Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case WRITE_AP_CONFIG:
                    writeApConfiguration((WifiConfiguration) msg.obj);
                    break;
                case READ_AP_CONFIG:
                    readApConfiguration();
                    break;
                default:
                    Log.e(TAG, "Unknown command in FileReadWriteHandler: " + msg);
                    break;
            }
        }

        private static void writeApConfiguration(final WifiConfiguration config) {
            DataOutputStream out = null;
            try {
                out = new DataOutputStream(new BufferedOutputStream(
                            new FileOutputStream(AP_CONFIG_FILE)));

                out.writeInt(AP_CONFIG_FILE_VERSION);
                out.writeUTF(config.SSID);
                int authType = config.getAuthType();
                out.writeInt(authType);
                if(authType != KeyMgmt.NONE) {
                    out.writeUTF(config.preSharedKey);
                }
            } catch (IOException e) {
                Log.e(TAG, "Error writing hotspot configuration" + e);
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {}
                }
            }
        }

        private static void readApConfiguration() {
            DataInputStream in = null;
            try {
                WifiConfiguration config = new WifiConfiguration();
                in = new DataInputStream(new BufferedInputStream(new FileInputStream(
                                AP_CONFIG_FILE)));

                int version = in.readInt();
                if (version != 1) {
                    Log.e(TAG, "Bad version on hotspot configuration file, set defaults");
                    setDefaultApConfiguration();
                    return;
                }
                config.SSID = in.readUTF();
                int authType = in.readInt();
                config.allowedKeyManagement.set(authType);
                if (authType != KeyMgmt.NONE) {
                    config.preSharedKey = in.readUTF();
                }
                synchronized (sApConfigLock) {
                    sApConfig = config;
                }
            } catch (IOException ignore) {
                setDefaultApConfiguration();
            } finally {
                if (in != null) {
                    try {
                        in.close();
                    } catch (IOException e) {}
                }
            }
        }

        /* Generate a default WPA2 based configuration with a random password.
           We are changing the Wifi Ap configuration storage from secure settings to a
           flat file accessible only by the system. A WPA2 based default configuration
           will keep the device secure after the update */
        private static void setDefaultApConfiguration() {
            WifiConfiguration config = new WifiConfiguration();
            config.SSID = sContext.getString(R.string.wifi_tether_configure_ssid_default);
            config.allowedKeyManagement.set(KeyMgmt.WPA2_PSK);
            String randomUUID = UUID.randomUUID().toString();
            //first 12 chars from xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
            config.preSharedKey = randomUUID.substring(0, 8) + randomUUID.substring(9,13);
            setApConfiguration(config);
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -898,7 +898,8 @@ public class WifiManager {
     */
    public boolean setWifiApEnabled(WifiConfiguration wifiConfig, boolean enabled) {
        try {
            return mService.setWifiApEnabled(wifiConfig, enabled);
            mService.setWifiApEnabled(wifiConfig, enabled);
            return true;
        } catch (RemoteException e) {
            return false;
        }
+67 −35
Original line number Diff line number Diff line
@@ -200,8 +200,12 @@ public class WifiStateMachine extends HierarchicalStateMachine {
    static final int CMD_START_AP                         = BASE + 21;
    /* Stop the soft access point */
    static final int CMD_STOP_AP                          = BASE + 22;
    /* Set the soft access point configuration */
    static final int CMD_SET_AP_CONFIG                    = BASE + 23;
    /* Get the soft access point configuration */
    static final int CMD_GET_AP_CONFIG                    = BASE + 24;

    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 23;
    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 25;

    /* Supplicant events */
    /* Connection to supplicant established */
@@ -355,6 +359,10 @@ public class WifiStateMachine extends HierarchicalStateMachine {
    private static final int MIN_RSSI = -200;
    private static final int MAX_RSSI = 256;

    /* Constants to indicate if soft ap is running or stopped */
    private static final int SOFT_AP_STOPPED = 0;
    private static final int SOFT_AP_RUNNING = 1;

    /* Default parent state */
    private HierarchicalState mDefaultState = new DefaultState();
    /* Temporary initial state */
@@ -593,6 +601,17 @@ public class WifiStateMachine extends HierarchicalStateMachine {
        }
    }

    public void setWifiApConfiguration(WifiConfiguration config) {
        sendMessage(obtainMessage(CMD_SET_AP_CONFIG, config));
    }

    public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
        WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
        resultMsg.recycle();
        return ret;
    }

    /**
     * TODO: doc
     */
@@ -1517,7 +1536,31 @@ public class WifiStateMachine extends HierarchicalStateMachine {
         */
        WifiNative.disconnectCommand();
        WifiNative.reconnectCommand();
    }

    private boolean startSoftApWithConfig(WifiConfiguration config, int currentStatus) {
        if (config == null) {
            config = WifiApConfigStore.getApConfiguration();
        } else {
            WifiApConfigStore.setApConfiguration(config);
        }
        try {
            if (currentStatus == SOFT_AP_STOPPED) {
                nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
            } else if (currentStatus == SOFT_AP_RUNNING) {
                nwService.setAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
            }
        } catch (Exception e) {
            Log.e(TAG, "Exception in softap start " + e);
            try {
                nwService.stopAccessPoint();
                nwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
            } catch (Exception ee) {
                Log.e(TAG, "Exception during softap restart : " + ee);
                return false;
            }
        }
        return true;
    }


@@ -1655,6 +1698,13 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                case CMD_ENABLE_BACKGROUND_SCAN:
                    mEnableBackgroundScan = (message.arg1 == 1);
                    break;
                case CMD_SET_AP_CONFIG:
                    WifiApConfigStore.setApConfiguration((WifiConfiguration) message.obj);
                    break;
                case CMD_GET_AP_CONFIG:
                    WifiConfiguration config = WifiApConfigStore.getApConfiguration();
                    mReplyChannel.replyToMessage(message, message.what, config);
                    break;
                    /* Discard */
                case CMD_LOAD_DRIVER:
                case CMD_UNLOAD_DRIVER:
@@ -1717,6 +1767,8 @@ public class WifiStateMachine extends HierarchicalStateMachine {
            // 50021 wifi_state_changed (custom|1|5)
            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

            WifiApConfigStore.initialize(mContext);

            if (WifiNative.isDriverLoaded()) {
                transitionTo(mDriverLoadedState);
            }
@@ -1829,26 +1881,14 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                    }
                    break;
                case CMD_START_AP:
                    try {
                        nwService.startAccessPoint((WifiConfiguration) message.obj,
                                    mInterfaceName,
                                    SOFTAP_IFACE);
                    } catch (Exception e) {
                        Log.e(TAG, "Exception in softap start " + e);
                        try {
                            nwService.stopAccessPoint();
                            nwService.startAccessPoint((WifiConfiguration) message.obj,
                                    mInterfaceName,
                                    SOFTAP_IFACE);
                        } catch (Exception ee) {
                            Log.e(TAG, "Exception during softap restart : " + ee);
                            sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
                            break;
                        }
                    }
                    if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_STOPPED)) {
                        Log.d(TAG, "Soft AP start successful");
                        setWifiApState(WIFI_AP_STATE_ENABLED);
                        transitionTo(mSoftApStartedState);
                    } else {
                        Log.d(TAG, "Soft AP start failed");
                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
                    }
                    break;
                default:
                    return NOT_HANDLED;
@@ -2999,22 +3039,14 @@ public class WifiStateMachine extends HierarchicalStateMachine {
                    break;
                case CMD_START_AP:
                    Log.d(TAG,"SoftAP set on a running access point");
                    try {
                        nwService.setAccessPoint((WifiConfiguration) message.obj,
                                    mInterfaceName,
                                    SOFTAP_IFACE);
                    } catch(Exception e) {
                        Log.e(TAG, "Exception in softap set " + e);
                        try {
                            nwService.stopAccessPoint();
                            nwService.startAccessPoint((WifiConfiguration) message.obj,
                                    mInterfaceName,
                                    SOFTAP_IFACE);
                        } catch (Exception ee) {
                            Log.e(TAG, "Could not restart softap after set failed " + ee);
                    if (startSoftApWithConfig((WifiConfiguration) message.obj, SOFT_AP_RUNNING)) {
                        Log.d(TAG, "Soft AP start successful");
                        setWifiApState(WIFI_AP_STATE_ENABLED);
                        transitionTo(mSoftApStartedState);
                    } else {
                        Log.d(TAG, "Soft AP start failed");
                        sendMessage(obtainMessage(CMD_UNLOAD_DRIVER, WIFI_AP_STATE_FAILED, 0));
                    }
                    }
                    break;
                /* Fail client mode operation when soft AP is enabled */
                case CMD_START_SUPPLICANT: