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

Commit 59c73b92 authored by Irfan Sheriff's avatar Irfan Sheriff Committed by Android (Google) Code Review
Browse files

Merge "Convert soft ap config store to state machine" into ics-mr1

parents b78ae752 9575a1be
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -619,12 +619,7 @@ public class WifiService extends IWifiManager.Stub {
     */
    public WifiConfiguration getWifiApConfiguration() {
        enforceAccessPermission();
        if (mWifiStateMachineChannel != null) {
            return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
        } else {
            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
            return null;
        }
        return mWifiStateMachine.syncGetWifiApConfiguration();
    }

    /**
+138 −107
Original line number Diff line number Diff line
@@ -19,11 +19,16 @@ 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.os.Message;
import android.os.Messenger;
import android.util.Log;

import com.android.internal.util.AsyncChannel;
import com.android.internal.R;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
@@ -34,16 +39,13 @@ 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 {
class WifiApConfigStore extends StateMachine {

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

    private static final String AP_CONFIG_FILE = Environment.getDataDirectory() +
@@ -51,87 +53,91 @@ class WifiApConfigStore {

    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;
    private State mDefaultState = new DefaultState();
    private State mInactiveState = new InactiveState();
    private State mActiveState = new ActiveState();

        /* 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();
    }
    private WifiConfiguration mWifiApConfig = null;
    private AsyncChannel mReplyChannel = new AsyncChannel();

    WifiApConfigStore(Context context, Handler target) {
        super(TAG, target.getLooper());

    static void setApConfiguration(WifiConfiguration config) {
        synchronized (sApConfigLock) {
            sApConfig = config;
        }
        Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config))
            .sendToTarget();
    }
        mContext = context;
        addState(mDefaultState);
            addState(mInactiveState, mDefaultState);
            addState(mActiveState, mDefaultState);

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

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

        public FileReadWriteHandler(android.os.Looper looper) {
            super(looper);
    public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
        WifiApConfigStore s = new WifiApConfigStore(context, target);
        s.start();
        return s;
    }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case WRITE_AP_CONFIG:
                    writeApConfiguration((WifiConfiguration) msg.obj);
    class DefaultState extends State {
        public boolean processMessage(Message message) {
            switch (message.what) {
                case WifiStateMachine.CMD_SET_AP_CONFIG:
                case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
                    Log.e(TAG, "Unexpected message: " + message);
                    break;
                case READ_AP_CONFIG:
                    readApConfiguration();
                case WifiStateMachine.CMD_REQUEST_AP_CONFIG:
                    mReplyChannel.replyToMessage(message,
                            WifiStateMachine.CMD_RESPONSE_AP_CONFIG, mWifiApConfig);
                    break;
                default:
                    Log.e(TAG, "Unknown command in FileReadWriteHandler: " + msg);
                    Log.e(TAG, "Failed to handle " + message);
                    break;
            }
            return HANDLED;
        }
    }

        private static void writeApConfiguration(final WifiConfiguration config) {
            DataOutputStream out = null;
            try {
                out = new DataOutputStream(new BufferedOutputStream(
                            new FileOutputStream(AP_CONFIG_FILE)));
    class InactiveState extends State {
        public boolean processMessage(Message message) {
            switch (message.what) {
                case WifiStateMachine.CMD_SET_AP_CONFIG:
                    mWifiApConfig = (WifiConfiguration) message.obj;
                    transitionTo(mActiveState);
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }
    }

                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);
    class ActiveState extends State {
        public void enter() {
            new Thread(new Runnable() {
                public void run() {
                    writeApConfiguration(mWifiApConfig);
                    sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
                }
            } catch (IOException e) {
                Log.e(TAG, "Error writing hotspot configuration" + e);
            } finally {
                if (out != null) {
                    try {
                        out.close();
                    } catch (IOException e) {}
            }).start();
        }

        public boolean processMessage(Message message) {
            switch (message.what) {
                //TODO: have feedback to the user when we do this
                //to indicate the write is currently in progress
                case WifiStateMachine.CMD_SET_AP_CONFIG:
                    deferMessage(message);
                    break;
                case WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED:
                    transitionTo(mInactiveState);
                    break;
                default:
                    return NOT_HANDLED;
            }
            return HANDLED;
        }
    }

        private static void readApConfiguration() {
    void loadApConfiguration() {
        DataInputStream in = null;
        try {
            WifiConfiguration config = new WifiConfiguration();
@@ -150,9 +156,7 @@ class WifiApConfigStore {
            if (authType != KeyMgmt.NONE) {
                config.preSharedKey = in.readUTF();
            }
                synchronized (sApConfigLock) {
                    sApConfig = config;
                }
            mWifiApConfig = config;
        } catch (IOException ignore) {
            setDefaultApConfiguration();
        } finally {
@@ -164,18 +168,45 @@ class WifiApConfigStore {
        }
    }

    Messenger getMessenger() {
        return new Messenger(getHandler());
    }

    private 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) {}
            }
        }
    }

    /* 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() {
    private void setDefaultApConfiguration() {
        WifiConfiguration config = new WifiConfiguration();
            config.SSID = sContext.getString(R.string.wifi_tether_configure_ssid_default);
        config.SSID = mContext.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);
        }
        sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
    }
}
+62 −47
Original line number Diff line number Diff line
@@ -184,6 +184,7 @@ public class WifiStateMachine extends StateMachine {
    private WifiP2pManager mWifiP2pManager;
    //Used to initiate a connection with WifiP2pService
    private AsyncChannel mWifiP2pChannel = new AsyncChannel();
    private AsyncChannel mWifiApConfigChannel = new AsyncChannel();

    // Event log tags (must be in sync with event-log-tags)
    private static final int EVENTLOG_WIFI_STATE_CHANGED        = 50021;
@@ -233,12 +234,16 @@ public class WifiStateMachine extends StateMachine {
    static final int CMD_STOP_AP                          = BASE + 24;
    /* Set the soft access point configuration */
    static final int CMD_SET_AP_CONFIG                    = BASE + 25;
    /* Get the soft access point configuration */
    static final int CMD_GET_AP_CONFIG                    = BASE + 26;
    /* Soft access point configuration set completed */
    static final int CMD_SET_AP_CONFIG_COMPLETED          = BASE + 26;
    /* Request the soft access point configuration */
    static final int CMD_REQUEST_AP_CONFIG                = BASE + 27;
    /* Response to access point configuration request */
    static final int CMD_RESPONSE_AP_CONFIG               = BASE + 28;
    /* Set configuration on tether interface */
    static final int CMD_TETHER_INTERFACE                 = BASE + 27;
    static final int CMD_TETHER_INTERFACE                 = BASE + 29;

    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 28;
    static final int CMD_BLUETOOTH_ADAPTER_STATE_CHANGE   = BASE + 30;

    /* Supplicant commands */
    /* Is supplicant alive ? */
@@ -530,6 +535,11 @@ public class WifiStateMachine extends StateMachine {
        mWpsStateMachine = new WpsStateMachine(context, this, getHandler());
        mLinkProperties = new LinkProperties();

        WifiApConfigStore wifiApConfigStore = WifiApConfigStore.makeWifiApConfigStore(
                context, getHandler());
        wifiApConfigStore.loadApConfiguration();
        mWifiApConfigChannel.connectSync(mContext, getHandler(), wifiApConfigStore.getMessenger());

        mNetworkInfo.setIsAvailable(false);
        mLinkProperties.clear();
        mLastBssid = null;
@@ -659,11 +669,11 @@ public class WifiStateMachine extends StateMachine {
    }

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

    public WifiConfiguration syncGetWifiApConfiguration(AsyncChannel channel) {
        Message resultMsg = channel.sendMessageSynchronously(CMD_GET_AP_CONFIG);
    public WifiConfiguration syncGetWifiApConfiguration() {
        Message resultMsg = mWifiApConfigChannel.sendMessageSynchronously(CMD_REQUEST_AP_CONFIG);
        WifiConfiguration ret = (WifiConfiguration) resultMsg.obj;
        resultMsg.recycle();
        return ret;
@@ -1714,12 +1724,10 @@ public class WifiStateMachine extends StateMachine {
     * TODO: Add control channel setup through hostapd that allows changing config
     * on a running daemon
     */
    private boolean startSoftApWithConfig(WifiConfiguration config) {
        if (config == null) {
            config = WifiApConfigStore.getApConfiguration();
        } else {
            WifiApConfigStore.setApConfiguration(config);
        }
    private void startSoftApWithConfig(final WifiConfiguration config) {
        // start hostapd on a seperate thread
        new Thread(new Runnable() {
            public void run() {
                try {
                    mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
                } catch (Exception e) {
@@ -1729,10 +1737,14 @@ public class WifiStateMachine extends StateMachine {
                        mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
                    } catch (Exception e1) {
                        loge("Exception in softap re-start " + e1);
                return false;
                        sendMessage(CMD_START_AP_FAILURE);
                        return;
                    }
                }
        return true;
                if (DBG) log("Soft AP start successful");
                sendMessage(CMD_START_AP_SUCCESS);
            }
        }).start();
    }

    /********************************************************
@@ -1775,13 +1787,6 @@ public class WifiStateMachine extends StateMachine {
                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:
@@ -1823,6 +1828,11 @@ public class WifiStateMachine extends StateMachine {
                case CMD_ENABLE_ALL_NETWORKS:
                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
                /* Handled by WifiApConfigStore */
                case CMD_SET_AP_CONFIG:
                case CMD_SET_AP_CONFIG_COMPLETED:
                case CMD_REQUEST_AP_CONFIG:
                case CMD_RESPONSE_AP_CONFIG:
                    break;
                case WifiMonitor.DRIVER_HUNG_EVENT:
                    setWifiEnabled(false);
@@ -1856,8 +1866,6 @@ public class WifiStateMachine extends StateMachine {
            // 50021 wifi_state_changed (custom|1|5)
            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

            WifiApConfigStore.initialize(mContext);

            if (WifiNative.isDriverLoaded()) {
                transitionTo(mDriverLoadedState);
            }
@@ -3243,21 +3251,19 @@ public class WifiStateMachine extends StateMachine {
            if (DBG) log(getName() + "\n");
            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());

            final Message message = Message.obtain(getCurrentMessage());
            final Message message = getCurrentMessage();
            if (message.what == CMD_START_AP) {
                final WifiConfiguration config = (WifiConfiguration) message.obj;

            // start hostapd on a seperate thread
            new Thread(new Runnable() {
                public void run() {
                    if (startSoftApWithConfig(config)) {
                        if (DBG) log("Soft AP start successful");
                        sendMessage(CMD_START_AP_SUCCESS);
                if (config == null) {
                    mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
                } else {
                        loge("Soft AP start failed");
                        sendMessage(CMD_START_AP_FAILURE);
                    mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
                    startSoftApWithConfig(config);
                }
            } else {
                throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
            }
            }).start();
        }
        @Override
        public boolean processMessage(Message message) {
@@ -3282,6 +3288,15 @@ public class WifiStateMachine extends StateMachine {
                case WifiP2pService.P2P_ENABLE_PENDING:
                    deferMessage(message);
                    break;
                case WifiStateMachine.CMD_RESPONSE_AP_CONFIG:
                    WifiConfiguration config = (WifiConfiguration) message.obj;
                    if (config != null) {
                        startSoftApWithConfig(config);
                    } else {
                        loge("Softap config is null!");
                        sendMessage(CMD_START_AP_FAILURE);
                    }
                    break;
                case CMD_START_AP_SUCCESS:
                    setWifiApState(WIFI_AP_STATE_ENABLED);
                    transitionTo(mSoftApStartedState);