am 59c73b92: Merge "Convert soft ap config store to state machine" into ics-mr1

* commit '59c73b92a9ef8df5d4873bc36f05b776c3a476bc':
  Convert soft ap config store to state machine
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 01eade1..3c65255 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -619,12 +619,7 @@
      */
     public WifiConfiguration getWifiApConfiguration() {
         enforceAccessPermission();
-        if (mWifiStateMachineChannel != null) {
-            return mWifiStateMachine.syncGetWifiApConfiguration(mWifiStateMachineChannel);
-        } else {
-            Slog.e(TAG, "mWifiStateMachineChannel is not initialized");
-            return null;
-        }
+        return mWifiStateMachine.syncGetWifiApConfiguration();
     }
 
     /**
diff --git a/wifi/java/android/net/wifi/WifiApConfigStore.java b/wifi/java/android/net/wifi/WifiApConfigStore.java
index bb5427d..0531ca3 100644
--- a/wifi/java/android/net/wifi/WifiApConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiApConfigStore.java
@@ -19,11 +19,16 @@
 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.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,131 +53,160 @@
 
     private static final int AP_CONFIG_FILE_VERSION = 1;
 
-    private static WifiConfiguration sApConfig = new WifiConfiguration();
-    private static final Object sApConfigLock = new Object();
+    private State mDefaultState = new DefaultState();
+    private State mInactiveState = new InactiveState();
+    private State mActiveState = new ActiveState();
 
-    private static FileReadWriteHandler sFileReadWriteHandler;
-    private static final int READ_AP_CONFIG               = 1;
-    private static final int WRITE_AP_CONFIG              = 2;
+    private WifiConfiguration mWifiApConfig = null;
+    private AsyncChannel mReplyChannel = new AsyncChannel();
 
-    static void initialize(Context context) {
-        sContext = context;
+    WifiApConfigStore(Context context, Handler target) {
+        super(TAG, target.getLooper());
 
-        /* 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();
+        mContext = context;
+        addState(mDefaultState);
+            addState(mInactiveState, mDefaultState);
+            addState(mActiveState, mDefaultState);
+
+        setInitialState(mInactiveState);
     }
 
-
-    static void setApConfiguration(WifiConfiguration config) {
-        synchronized (sApConfigLock) {
-            sApConfig = config;
-        }
-        Message.obtain(sFileReadWriteHandler, WRITE_AP_CONFIG, new WifiConfiguration(config))
-            .sendToTarget();
+    public static WifiApConfigStore makeWifiApConfigStore(Context context, Handler target) {
+        WifiApConfigStore s = new WifiApConfigStore(context, target);
+        s.start();
+        return s;
     }
 
-    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);
+    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)));
-
-                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) {}
-                }
+    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;
+        }
+    }
+
+    class ActiveState extends State {
+        public void enter() {
+            new Thread(new Runnable() {
+                public void run() {
+                    writeApConfiguration(mWifiApConfig);
+                    sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG_COMPLETED);
+                }
+            }).start();
         }
 
-        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) {}
-                }
+        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;
         }
+    }
 
-        /* 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() {
+    void loadApConfiguration() {
+        DataInputStream in = null;
+        try {
             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);
+            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();
+            }
+            mWifiApConfig = config;
+        } catch (IOException ignore) {
+            setDefaultApConfiguration();
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException e) {}
+            }
         }
     }
+
+    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 void setDefaultApConfiguration() {
+        WifiConfiguration config = new WifiConfiguration();
+        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);
+        sendMessage(WifiStateMachine.CMD_SET_AP_CONFIG, config);
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 00fae2e..aadcaad 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -184,6 +184,7 @@
     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 @@
     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 @@
         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 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,25 +1724,27 @@
      * 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);
-        }
-        try {
-            mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
-        } catch (Exception e) {
-            loge("Exception in softap start " + e);
-            try {
-                mNwService.stopAccessPoint(mInterfaceName);
-                mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
-            } catch (Exception e1) {
-                loge("Exception in softap re-start " + e1);
-                return false;
+    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) {
+                    loge("Exception in softap start " + e);
+                    try {
+                        mNwService.stopAccessPoint(mInterfaceName);
+                        mNwService.startAccessPoint(config, mInterfaceName, SOFTAP_IFACE);
+                    } catch (Exception e1) {
+                        loge("Exception in softap re-start " + e1);
+                        sendMessage(CMD_START_AP_FAILURE);
+                        return;
+                    }
+                }
+                if (DBG) log("Soft AP start successful");
+                sendMessage(CMD_START_AP_SUCCESS);
             }
-        }
-        return true;
+        }).start();
     }
 
     /********************************************************
@@ -1775,13 +1787,6 @@
                 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 @@
                 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 @@
             // 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 @@
             if (DBG) log(getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
 
-            final Message message = Message.obtain(getCurrentMessage());
-            final WifiConfiguration config = (WifiConfiguration) message.obj;
+            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);
-                    } else {
-                        loge("Soft AP start failed");
-                        sendMessage(CMD_START_AP_FAILURE);
-                    }
+                if (config == null) {
+                    mWifiApConfigChannel.sendMessage(CMD_REQUEST_AP_CONFIG);
+                } else {
+                    mWifiApConfigChannel.sendMessage(CMD_SET_AP_CONFIG, config);
+                    startSoftApWithConfig(config);
                 }
-            }).start();
+            } else {
+                throw new RuntimeException("Illegal transition to SoftApStartingState: " + message);
+            }
         }
         @Override
         public boolean processMessage(Message message) {
@@ -3282,6 +3288,15 @@
                 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);