OSDN Git Service

Use a single socket to communicate with supplicant
authorVinit Deshapnde <vinitd@google.com>
Thu, 8 Aug 2013 17:38:53 +0000 (10:38 -0700)
committerRobert Greenwalt <rgreenwalt@google.com>
Thu, 8 Aug 2013 18:38:53 +0000 (18:38 +0000)
This helps to prepare for future updates from external sources.

Bug: 9298955

Change-Id: I4c63ad5fc1ea3564aab38cfce955de19bad75c0c
(cherry picked from commit fb40801ed8c217ae01082fb1cbd0c30bbf5532ac)

core/jni/android_net_NetUtils.cpp
core/jni/android_net_wifi_Wifi.cpp
wifi/java/android/net/wifi/WifiMonitor.java
wifi/java/android/net/wifi/WifiNative.java
wifi/java/android/net/wifi/WifiStateMachine.java
wifi/java/android/net/wifi/p2p/WifiP2pService.java

index 7e70c7c..6d23c32 100644 (file)
@@ -141,7 +141,7 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr
                 dns, server, &lease, vendorInfo, domains, mtu);
     }
     if (result != 0) {
-        ALOGD("dhcp_do_request failed");
+        ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
     }
 
     env->ReleaseStringUTFChars(ifname, nameStr);
index 08962e2..aa6dbf3 100644 (file)
@@ -33,11 +33,11 @@ namespace android {
 
 static jint DBG = false;
 
-static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuflen)
+static int doCommand(char *cmd, char *replybuf, int replybuflen)
 {
     size_t reply_len = replybuflen - 1;
 
-    if (::wifi_command(ifname, cmd, BUF_SIZE, replybuf, &reply_len) != 0)
+    if (::wifi_command(cmd, replybuf, &reply_len) != 0)
         return -1;
     else {
         // Strip off trailing newline
@@ -49,7 +49,7 @@ static int doCommand(const char *ifname, char *cmd, char *replybuf, int replybuf
     }
 }
 
-static jint doIntCommand(const char *ifname, const char* fmt, ...)
+static jint doIntCommand(const char* fmt, ...)
 {
     char buf[BUF_SIZE];
     va_list args;
@@ -60,13 +60,13 @@ static jint doIntCommand(const char *ifname, const char* fmt, ...)
         return -1;
     }
     char reply[BUF_SIZE];
-    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
+    if (doCommand(buf, reply, sizeof(reply)) != 0) {
         return -1;
     }
     return static_cast<jint>(atoi(reply));
 }
 
-static jboolean doBooleanCommand(const char *ifname, const char* expect, const char* fmt, ...)
+static jboolean doBooleanCommand(const char* expect, const char* fmt, ...)
 {
     char buf[BUF_SIZE];
     va_list args;
@@ -77,14 +77,14 @@ static jboolean doBooleanCommand(const char *ifname, const char* expect, const c
         return JNI_FALSE;
     }
     char reply[BUF_SIZE];
-    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
+    if (doCommand(buf, reply, sizeof(reply)) != 0) {
         return JNI_FALSE;
     }
     return (strcmp(reply, expect) == 0);
 }
 
 // Send a command to the supplicant, and return the reply as a String
-static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt, ...) {
+static jstring doStringCommand(JNIEnv* env, const char* fmt, ...) {
     char buf[BUF_SIZE];
     va_list args;
     va_start(args, fmt);
@@ -94,7 +94,7 @@ static jstring doStringCommand(JNIEnv* env, const char *ifname, const char* fmt,
         return NULL;
     }
     char reply[4096];
-    if (doCommand(ifname, buf, reply, sizeof(reply)) != 0) {
+    if (doCommand(buf, reply, sizeof(reply)) != 0) {
         return NULL;
     }
     // TODO: why not just NewStringUTF?
@@ -127,23 +127,20 @@ static jboolean android_net_wifi_killSupplicant(JNIEnv* env, jobject, jboolean p
     return (jboolean)(::wifi_stop_supplicant(p2pSupported) == 0);
 }
 
-static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject, jstring jIface)
+static jboolean android_net_wifi_connectToSupplicant(JNIEnv* env, jobject)
 {
-    ScopedUtfChars ifname(env, jIface);
-    return (jboolean)(::wifi_connect_to_supplicant(ifname.c_str()) == 0);
+    return (jboolean)(::wifi_connect_to_supplicant() == 0);
 }
 
-static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject, jstring jIface)
+static void android_net_wifi_closeSupplicantConnection(JNIEnv* env, jobject)
 {
-    ScopedUtfChars ifname(env, jIface);
-    ::wifi_close_supplicant_connection(ifname.c_str());
+    ::wifi_close_supplicant_connection();
 }
 
-static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIface)
+static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject)
 {
     char buf[EVENT_BUF_SIZE];
-    ScopedUtfChars ifname(env, jIface);
-    int nread = ::wifi_wait_for_event(ifname.c_str(), buf, sizeof buf);
+    int nread = ::wifi_wait_for_event(buf, sizeof buf);
     if (nread > 0) {
         return env->NewStringUTF(buf);
     } else {
@@ -151,43 +148,36 @@ static jstring android_net_wifi_waitForEvent(JNIEnv* env, jobject, jstring jIfac
     }
 }
 
-static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jIface,
-        jstring jCommand)
+static jboolean android_net_wifi_doBooleanCommand(JNIEnv* env, jobject, jstring jCommand)
 {
-    ScopedUtfChars ifname(env, jIface);
     ScopedUtfChars command(env, jCommand);
 
     if (command.c_str() == NULL) {
         return JNI_FALSE;
     }
     if (DBG) ALOGD("doBoolean: %s", command.c_str());
-    return doBooleanCommand(ifname.c_str(), "OK", "%s", command.c_str());
+    return doBooleanCommand("OK", "%s", command.c_str());
 }
 
-static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jIface,
-        jstring jCommand)
+static jint android_net_wifi_doIntCommand(JNIEnv* env, jobject, jstring jCommand)
 {
-    ScopedUtfChars ifname(env, jIface);
     ScopedUtfChars command(env, jCommand);
 
     if (command.c_str() == NULL) {
         return -1;
     }
     if (DBG) ALOGD("doInt: %s", command.c_str());
-    return doIntCommand(ifname.c_str(), "%s", command.c_str());
+    return doIntCommand("%s", command.c_str());
 }
 
-static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jIface,
-        jstring jCommand)
+static jstring android_net_wifi_doStringCommand(JNIEnv* env, jobject, jstring jCommand)
 {
-    ScopedUtfChars ifname(env, jIface);
-
     ScopedUtfChars command(env, jCommand);
     if (command.c_str() == NULL) {
         return NULL;
     }
     if (DBG) ALOGD("doString: %s", command.c_str());
-    return doStringCommand(env, ifname.c_str(), "%s", command.c_str());
+    return doStringCommand(env, "%s", command.c_str());
 }
 
 
@@ -205,17 +195,13 @@ static JNINativeMethod gWifiMethods[] = {
     { "unloadDriver", "()Z",  (void *)android_net_wifi_unloadDriver },
     { "startSupplicant", "(Z)Z",  (void *)android_net_wifi_startSupplicant },
     { "killSupplicant", "(Z)Z",  (void *)android_net_wifi_killSupplicant },
-    { "connectToSupplicant", "(Ljava/lang/String;)Z",
-            (void *)android_net_wifi_connectToSupplicant },
-    { "closeSupplicantConnection", "(Ljava/lang/String;)V",
+    { "connectToSupplicantNative", "()Z", (void *)android_net_wifi_connectToSupplicant },
+    { "closeSupplicantConnectionNative", "()V",
             (void *)android_net_wifi_closeSupplicantConnection },
-    { "waitForEvent", "(Ljava/lang/String;)Ljava/lang/String;",
-            (void*) android_net_wifi_waitForEvent },
-    { "doBooleanCommand", "(Ljava/lang/String;Ljava/lang/String;)Z",
-            (void*) android_net_wifi_doBooleanCommand },
-    { "doIntCommand", "(Ljava/lang/String;Ljava/lang/String;)I",
-            (void*) android_net_wifi_doIntCommand },
-    { "doStringCommand", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
+    { "waitForEventNative", "()Ljava/lang/String;", (void*)android_net_wifi_waitForEvent },
+    { "doBooleanCommandNative", "(Ljava/lang/String;)Z", (void*)android_net_wifi_doBooleanCommand },
+    { "doIntCommandNative", "(Ljava/lang/String;)I", (void*)android_net_wifi_doIntCommand },
+    { "doStringCommandNative", "(Ljava/lang/String;)Ljava/lang/String;",
             (void*) android_net_wifi_doStringCommand },
 };
 
index fe3c709..92b8e46 100644 (file)
@@ -32,7 +32,10 @@ import android.util.Log;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.StateMachine;
 
+import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 
@@ -44,6 +47,7 @@ import java.util.regex.Matcher;
  */
 public class WifiMonitor {
 
+    private static final boolean DBG = false;
     private static final String TAG = "WifiMonitor";
 
     /** Events we receive from the supplicant daemon */
@@ -279,9 +283,6 @@ public class WifiMonitor {
     /* AP-STA-DISCONNECTED 42:fc:89:a8:96:09 */
     private static final String AP_STA_DISCONNECTED_STR = "AP-STA-DISCONNECTED";
 
-    private final StateMachine mStateMachine;
-    private final WifiNative mWifiNative;
-
     /* Supplicant events reported to a state machine */
     private static final int BASE = Protocol.BASE_WIFI_MONITOR;
 
@@ -347,164 +348,324 @@ public class WifiMonitor {
     private static final String WPA_RECV_ERROR_STR = "recv error";
 
     /**
-     * Tracks consecutive receive errors
-     */
-    private int mRecvErrors = 0;
-
-    /**
      * Max errors before we close supplicant connection
      */
     private static final int MAX_RECV_ERRORS    = 10;
 
+    private final String mInterfaceName;
+    private final WifiNative mWifiNative;
+    private final StateMachine mWifiStateMachine;
+    private boolean mMonitoring;
+
     public WifiMonitor(StateMachine wifiStateMachine, WifiNative wifiNative) {
-        mStateMachine = wifiStateMachine;
+        if (DBG) Log.d(TAG, "Creating WifiMonitor");
         mWifiNative = wifiNative;
+        mInterfaceName = wifiNative.mInterfaceName;
+        mWifiStateMachine = wifiStateMachine;
+        mMonitoring = false;
+
+        WifiMonitorSingleton.getMonitor().registerInterfaceMonitor(mInterfaceName, this);
     }
 
     public void startMonitoring() {
-        new MonitorThread().start();
+        WifiMonitorSingleton.getMonitor().startMonitoring(mInterfaceName);
     }
 
-    class MonitorThread extends Thread {
-        public MonitorThread() {
-            super("WifiMonitor");
+    public void stopMonitoring() {
+        WifiMonitorSingleton.getMonitor().stopMonitoring(mInterfaceName);
+    }
+
+    public void stopSupplicant() {
+        WifiMonitorSingleton.getMonitor().stopSupplicant();
+    }
+
+    public void killSupplicant(boolean p2pSupported) {
+        WifiMonitorSingleton.getMonitor().killSupplicant(p2pSupported);
+    }
+
+    private static class WifiMonitorSingleton {
+        private static Object sSingletonLock = new Object();
+        private static WifiMonitorSingleton sWifiMonitorSingleton = null;
+        private HashMap<String, WifiMonitor> mIfaceMap = new HashMap<String, WifiMonitor>();
+        private boolean mConnected = false;
+        private WifiNative mWifiNative;
+
+        private WifiMonitorSingleton() {
         }
 
-        public void run() {
+        static WifiMonitorSingleton getMonitor() {
+            if (DBG) Log.d(TAG, "WifiMonitorSingleton gotten");
+            synchronized (sSingletonLock) {
+                if (sWifiMonitorSingleton == null) {
+                    if (DBG) Log.d(TAG, "WifiMonitorSingleton created");
+                    sWifiMonitorSingleton = new WifiMonitorSingleton();
+                }
+            }
+            return sWifiMonitorSingleton;
+        }
 
-            if (connectToSupplicant()) {
-                // Send a message indicating that it is now possible to send commands
-                // to the supplicant
-                mStateMachine.sendMessage(SUP_CONNECTION_EVENT);
-            } else {
-                mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+        public synchronized void startMonitoring(String iface) {
+            WifiMonitor m = mIfaceMap.get(iface);
+            if (m == null) {
+                Log.e(TAG, "startMonitor called with unknown iface=" + iface);
                 return;
             }
 
+            Log.d(TAG, "startMonitoring(" + iface + ") with mConnected = " + mConnected);
+
+            if (mConnected) {
+                m.mMonitoring = true;
+                m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
+            } else {
+                if (DBG) Log.d(TAG, "connecting to supplicant");
+                int connectTries = 0;
+                while (true) {
+                    if (mWifiNative.connectToSupplicant()) {
+                        m.mMonitoring = true;
+                        m.mWifiStateMachine.sendMessage(SUP_CONNECTION_EVENT);
+                        new MonitorThread(mWifiNative, this).start();
+                        mConnected = true;
+                        break;
+                    }
+                    if (connectTries++ < 5) {
+                        try {
+                            Thread.sleep(1000);
+                        } catch (InterruptedException ignore) {
+                        }
+                    } else {
+                        mIfaceMap.remove(iface);
+                        m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+                        break;
+                    }
+                }
+            }
+        }
+
+        public synchronized void stopMonitoring(String iface) {
+            WifiMonitor m = mIfaceMap.get(iface);
+            if (DBG) Log.d(TAG, "stopMonitoring(" + iface + ") = " + m.mWifiStateMachine);
+            m.mMonitoring = false;
+            m.mWifiStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+        }
+
+        public synchronized void registerInterfaceMonitor(String iface, WifiMonitor m) {
+            if (DBG) Log.d(TAG, "registerInterface(" + iface + "+" + m.mWifiStateMachine + ")");
+            mIfaceMap.put(iface, m);
+            if (mWifiNative == null) {
+                mWifiNative = m.mWifiNative;
+            }
+        }
+
+        public synchronized void unregisterInterfaceMonitor(String iface) {
+            // REVIEW: When should we call this? If this isn't called, then WifiMonitor
+            // objects will remain in the mIfaceMap; and won't ever get deleted
+
+            WifiMonitor m = mIfaceMap.remove(iface);
+            if (DBG) Log.d(TAG, "unregisterInterface(" + iface + "+" + m.mWifiStateMachine + ")");
+        }
+
+        public synchronized void stopSupplicant() {
+            mWifiNative.stopSupplicant();
+        }
+
+        public synchronized void killSupplicant(boolean p2pSupported) {
+            mWifiNative.killSupplicant(p2pSupported);
+            mConnected = false;
+            Iterator<Map.Entry<String, WifiMonitor>> it = mIfaceMap.entrySet().iterator();
+            while (it.hasNext()) {
+                Map.Entry<String, WifiMonitor> e = it.next();
+                WifiMonitor m = e.getValue();
+                m.mMonitoring = false;
+            }
+        }
+
+        private synchronized WifiMonitor getMonitor(String iface) {
+            return mIfaceMap.get(iface);
+        }
+    }
+
+    private static class MonitorThread extends Thread {
+        private final WifiNative mWifiNative;
+        private final WifiMonitorSingleton mWifiMonitorSingleton;
+        private int mRecvErrors = 0;
+        private StateMachine mStateMachine = null;
+
+        public MonitorThread(WifiNative wifiNative, WifiMonitorSingleton wifiMonitorSingleton) {
+            super("WifiMonitor");
+            mWifiNative = wifiNative;
+            mWifiMonitorSingleton = wifiMonitorSingleton;
+        }
+
+        public void run() {
             //noinspection InfiniteLoopStatement
             for (;;) {
                 String eventStr = mWifiNative.waitForEvent();
 
                 // Skip logging the common but mostly uninteresting scan-results event
-                if (false && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
+                if (DBG && eventStr.indexOf(SCAN_RESULTS_STR) == -1) {
                     Log.d(TAG, "Event [" + eventStr + "]");
                 }
-                if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
-                    if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
-                            0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
-                        mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
-                    } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
-                        mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
-                    } else if (eventStr.startsWith(WPS_FAIL_STR)) {
-                        handleWpsFailEvent(eventStr);
-                    } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
-                        mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
-                    } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
-                        mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
-                    } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
-                        handleP2pEvents(eventStr);
-                    } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
-                        handleHostApEvents(eventStr);
+
+                WifiMonitor m = null;
+                mStateMachine = null;
+
+                if (eventStr.startsWith("IFNAME=")) {
+                    int space = eventStr.indexOf(' ');
+                    if (space != -1) {
+                        String iface = eventStr.substring(7,space);
+                        m = mWifiMonitorSingleton.getMonitor(iface);
+                        if (m != null) {
+                            if (m.mMonitoring) {
+                                mStateMachine = m.mWifiStateMachine;
+                                eventStr = eventStr.substring(space + 1);
+                            }
+                            else {
+                                if (DBG) Log.d(TAG, "Dropping event because monitor (" + iface +
+                                        ") is stopped");
+                                continue;
+                            }
+                        }
+                        else {
+                            eventStr = eventStr.substring(space + 1);
+                        }
                     }
-                    continue;
                 }
 
-                String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
-                int nameEnd = eventName.indexOf(' ');
-                if (nameEnd != -1)
-                    eventName = eventName.substring(0, nameEnd);
-                if (eventName.length() == 0) {
-                    if (false) Log.i(TAG, "Received wpa_supplicant event with empty event name");
-                    continue;
-                }
-                /*
-                 * Map event name into event enum
-                 */
-                int event;
-                if (eventName.equals(CONNECTED_STR))
-                    event = CONNECTED;
-                else if (eventName.equals(DISCONNECTED_STR))
-                    event = DISCONNECTED;
-                else if (eventName.equals(STATE_CHANGE_STR))
-                    event = STATE_CHANGE;
-                else if (eventName.equals(SCAN_RESULTS_STR))
-                    event = SCAN_RESULTS;
-                else if (eventName.equals(LINK_SPEED_STR))
-                    event = LINK_SPEED;
-                else if (eventName.equals(TERMINATING_STR))
-                    event = TERMINATING;
-                else if (eventName.equals(DRIVER_STATE_STR))
-                    event = DRIVER_STATE;
-                else if (eventName.equals(EAP_FAILURE_STR))
-                    event = EAP_FAILURE;
-                else if (eventName.equals(ASSOC_REJECT_STR))
-                    event = ASSOC_REJECT;
-                else
-                    event = UNKNOWN;
-
-                String eventData = eventStr;
-                if (event == DRIVER_STATE || event == LINK_SPEED)
-                    eventData = eventData.split(" ")[1];
-                else if (event == STATE_CHANGE || event == EAP_FAILURE) {
-                    int ind = eventStr.indexOf(" ");
-                    if (ind != -1) {
-                        eventData = eventStr.substring(ind + 1);
+                if (mStateMachine != null) {
+                    if (dispatchEvent(eventStr)) {
+                        break;
                     }
                 } else {
-                    int ind = eventStr.indexOf(" - ");
-                    if (ind != -1) {
-                        eventData = eventStr.substring(ind + 3);
-                    }
-                }
-
-                if (event == STATE_CHANGE) {
-                    handleSupplicantStateChange(eventData);
-                } else if (event == DRIVER_STATE) {
-                    handleDriverEvent(eventData);
-                } else if (event == TERMINATING) {
-                    /**
-                     * Close the supplicant connection if we see
-                     * too many recv errors
-                     */
-                    if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
-                        if (++mRecvErrors > MAX_RECV_ERRORS) {
-                            if (false) {
-                                Log.d(TAG, "too many recv errors, closing connection");
-                            }
-                        } else {
-                            continue;
+                    if (DBG) Log.d(TAG, "Sending to all monitors because there's no interface id");
+                    boolean done = false;
+                    Iterator<Map.Entry<String, WifiMonitor>> it =
+                            mWifiMonitorSingleton.mIfaceMap.entrySet().iterator();
+                    while (it.hasNext()) {
+                        Map.Entry<String, WifiMonitor> e = it.next();
+                        m = e.getValue();
+                        mStateMachine = m.mWifiStateMachine;
+                        if (dispatchEvent(eventStr)) {
+                            done = true;
                         }
                     }
 
-                    // notify and exit
-                    mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
-                    break;
-                } else if (event == EAP_FAILURE) {
-                    if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
-                        mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+                    if (done) {
+                        // After this thread terminates, we'll no longer
+                        // be connected to the supplicant
+                        if (DBG) Log.d(TAG, "Disconnecting from the supplicant, no more events");
+                        mWifiMonitorSingleton.mConnected = false;
+                        break;
                     }
-                } else if (event == ASSOC_REJECT) {
-                        mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
-                } else {
-                    handleEvent(event, eventData);
                 }
-                mRecvErrors = 0;
             }
         }
 
-        private boolean connectToSupplicant() {
-            int connectTries = 0;
+        /* @return true if the event was supplicant disconnection */
+        private boolean dispatchEvent(String eventStr) {
+
+            if (!eventStr.startsWith(EVENT_PREFIX_STR)) {
+                if (eventStr.startsWith(WPA_EVENT_PREFIX_STR) &&
+                        0 < eventStr.indexOf(PASSWORD_MAY_BE_INCORRECT_STR)) {
+                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
+                } else if (eventStr.startsWith(WPS_SUCCESS_STR)) {
+                    mStateMachine.sendMessage(WPS_SUCCESS_EVENT);
+                } else if (eventStr.startsWith(WPS_FAIL_STR)) {
+                    handleWpsFailEvent(eventStr);
+                } else if (eventStr.startsWith(WPS_OVERLAP_STR)) {
+                    mStateMachine.sendMessage(WPS_OVERLAP_EVENT);
+                } else if (eventStr.startsWith(WPS_TIMEOUT_STR)) {
+                    mStateMachine.sendMessage(WPS_TIMEOUT_EVENT);
+                } else if (eventStr.startsWith(P2P_EVENT_PREFIX_STR)) {
+                    handleP2pEvents(eventStr);
+                } else if (eventStr.startsWith(HOST_AP_EVENT_PREFIX_STR)) {
+                    handleHostApEvents(eventStr);
+                }
+                else {
+                    if (DBG) Log.w(TAG, "couldn't identify event type - " + eventStr);
+                }
+                return false;
+            }
 
-            while (true) {
-                if (mWifiNative.connectToSupplicant()) {
-                    return true;
+            String eventName = eventStr.substring(EVENT_PREFIX_LEN_STR);
+            int nameEnd = eventName.indexOf(' ');
+            if (nameEnd != -1)
+                eventName = eventName.substring(0, nameEnd);
+            if (eventName.length() == 0) {
+                if (DBG) Log.i(TAG, "Received wpa_supplicant event with empty event name");
+                return false;
+            }
+            /*
+             * Map event name into event enum
+             */
+            int event;
+            if (eventName.equals(CONNECTED_STR))
+                event = CONNECTED;
+            else if (eventName.equals(DISCONNECTED_STR))
+                event = DISCONNECTED;
+            else if (eventName.equals(STATE_CHANGE_STR))
+                event = STATE_CHANGE;
+            else if (eventName.equals(SCAN_RESULTS_STR))
+                event = SCAN_RESULTS;
+            else if (eventName.equals(LINK_SPEED_STR))
+                event = LINK_SPEED;
+            else if (eventName.equals(TERMINATING_STR))
+                event = TERMINATING;
+            else if (eventName.equals(DRIVER_STATE_STR))
+                event = DRIVER_STATE;
+            else if (eventName.equals(EAP_FAILURE_STR))
+                event = EAP_FAILURE;
+            else if (eventName.equals(ASSOC_REJECT_STR))
+                event = ASSOC_REJECT;
+            else
+                event = UNKNOWN;
+
+            String eventData = eventStr;
+            if (event == DRIVER_STATE || event == LINK_SPEED)
+                eventData = eventData.split(" ")[1];
+            else if (event == STATE_CHANGE || event == EAP_FAILURE) {
+                int ind = eventStr.indexOf(" ");
+                if (ind != -1) {
+                    eventData = eventStr.substring(ind + 1);
                 }
-                if (connectTries++ < 5) {
-                    nap(1);
-                } else {
-                    break;
+            } else {
+                int ind = eventStr.indexOf(" - ");
+                if (ind != -1) {
+                    eventData = eventStr.substring(ind + 3);
+                }
+            }
+
+            if (event == STATE_CHANGE) {
+                handleSupplicantStateChange(eventData);
+            } else if (event == DRIVER_STATE) {
+                handleDriverEvent(eventData);
+            } else if (event == TERMINATING) {
+                /**
+                 * Close the supplicant connection if we see
+                 * too many recv errors
+                 */
+                if (eventData.startsWith(WPA_RECV_ERROR_STR)) {
+                    if (++mRecvErrors > MAX_RECV_ERRORS) {
+                        if (DBG) {
+                            Log.d(TAG, "too many recv errors, closing connection");
+                        }
+                    } else {
+                        return false;
+                    }
+                }
+
+                // notify and exit
+                mStateMachine.sendMessage(SUP_DISCONNECTION_EVENT);
+                return true;
+            } else if (event == EAP_FAILURE) {
+                if (eventData.startsWith(EAP_AUTH_FAILURE_STR)) {
+                    mStateMachine.sendMessage(AUTHENTICATION_FAILURE_EVENT);
                 }
+            } else if (event == ASSOC_REJECT) {
+                mStateMachine.sendMessage(ASSOCIATION_REJECTION_EVENT);
+            } else {
+                handleEvent(event, eventData);
             }
+            mRecvErrors = 0;
             return false;
         }
 
@@ -723,71 +884,60 @@ public class WifiMonitor {
             }
             notifySupplicantStateChange(networkId, wifiSsid, BSSID, newSupplicantState);
         }
-    }
 
-    private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
-        String BSSID = null;
-        int networkId = -1;
-        if (newState == NetworkInfo.DetailedState.CONNECTED) {
-            Matcher match = mConnectedEventPattern.matcher(data);
-            if (!match.find()) {
-                if (false) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
-            } else {
-                BSSID = match.group(1);
-                try {
-                    networkId = Integer.parseInt(match.group(2));
-                } catch (NumberFormatException e) {
-                    networkId = -1;
+        private void handleNetworkStateChange(NetworkInfo.DetailedState newState, String data) {
+            String BSSID = null;
+            int networkId = -1;
+            if (newState == NetworkInfo.DetailedState.CONNECTED) {
+                Matcher match = mConnectedEventPattern.matcher(data);
+                if (!match.find()) {
+                    if (DBG) Log.d(TAG, "Could not find BSSID in CONNECTED event string");
+                } else {
+                    BSSID = match.group(1);
+                    try {
+                        networkId = Integer.parseInt(match.group(2));
+                    } catch (NumberFormatException e) {
+                        networkId = -1;
+                    }
                 }
+                notifyNetworkStateChange(newState, BSSID, networkId);
             }
         }
-        notifyNetworkStateChange(newState, BSSID, networkId);
-    }
 
-    /**
-     * Send the state machine a notification that the state of Wifi connectivity
-     * has changed.
-     * @param networkId the configured network on which the state change occurred
-     * @param newState the new network state
-     * @param BSSID when the new state is {@link DetailedState#CONNECTED
-     * NetworkInfo.DetailedState.CONNECTED},
-     * this is the MAC address of the access point. Otherwise, it
-     * is {@code null}.
-     */
-    void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
-        if (newState == NetworkInfo.DetailedState.CONNECTED) {
-            Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
-                    netId, 0, BSSID);
-            mStateMachine.sendMessage(m);
-        } else {
-            Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
-                    netId, 0, BSSID);
-            mStateMachine.sendMessage(m);
+        /**
+         * Send the state machine a notification that the state of Wifi connectivity
+         * has changed.
+         * @param networkId the configured network on which the state change occurred
+         * @param newState the new network state
+         * @param BSSID when the new state is {@link DetailedState#CONNECTED
+         * NetworkInfo.DetailedState.CONNECTED},
+         * this is the MAC address of the access point. Otherwise, it
+         * is {@code null}.
+         */
+        void notifyNetworkStateChange(NetworkInfo.DetailedState newState, String BSSID, int netId) {
+            if (newState == NetworkInfo.DetailedState.CONNECTED) {
+                Message m = mStateMachine.obtainMessage(NETWORK_CONNECTION_EVENT,
+                        netId, 0, BSSID);
+                mStateMachine.sendMessage(m);
+            } else {
+                Message m = mStateMachine.obtainMessage(NETWORK_DISCONNECTION_EVENT,
+                        netId, 0, BSSID);
+                mStateMachine.sendMessage(m);
+            }
         }
-    }
 
-    /**
-     * Send the state machine a notification that the state of the supplicant
-     * has changed.
-     * @param networkId the configured network on which the state change occurred
-     * @param wifiSsid network name
-     * @param BSSID network address
-     * @param newState the new {@code SupplicantState}
-     */
-    void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
-            SupplicantState newState) {
-        mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
-                new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
-    }
-
-    /**
-     * Sleep for a period of time.
-     * @param secs the number of seconds to sleep
-     */
-    private static void nap(int secs) {
-        try {
-            Thread.sleep(secs * 1000);
-        } catch (InterruptedException ignore) {
+        /**
+         * Send the state machine a notification that the state of the supplicant
+         * has changed.
+         * @param networkId the configured network on which the state change occurred
+         * @param wifiSsid network name
+         * @param BSSID network address
+         * @param newState the new {@code SupplicantState}
+         */
+        void notifySupplicantStateChange(int networkId, WifiSsid wifiSsid, String BSSID,
+                SupplicantState newState) {
+            mStateMachine.sendMessage(mStateMachine.obtainMessage(SUPPLICANT_STATE_CHANGE_EVENT,
+                    new StateChangeResult(networkId, wifiSsid, BSSID, newState)));
         }
     }
 }
index b1dd2ce..d30c7cf 100644 (file)
@@ -47,7 +47,9 @@ public class WifiNative {
     static final int SCAN_WITHOUT_CONNECTION_SETUP          = 1;
     static final int SCAN_WITH_CONNECTION_SETUP             = 2;
 
-    String mInterface = "";
+    public final String mInterfaceName;
+    public final String mInterfacePrefix;
+
     private boolean mSuspendOptEnabled = false;
 
     public native static boolean loadDriver();
@@ -62,52 +64,53 @@ public class WifiNative {
        or when the supplicant is hung */
     public native static boolean killSupplicant(boolean p2pSupported);
 
-    private native boolean connectToSupplicant(String iface);
+    private native boolean connectToSupplicantNative();
 
-    private native void closeSupplicantConnection(String iface);
+    private native void closeSupplicantConnectionNative();
 
     /**
      * Wait for the supplicant to send an event, returning the event string.
      * @return the event string sent by the supplicant.
      */
-    private native String waitForEvent(String iface);
+    private native String waitForEventNative();
 
-    private native boolean doBooleanCommand(String iface, String command);
+    private native boolean doBooleanCommandNative(String command);
 
-    private native int doIntCommand(String iface, String command);
+    private native int doIntCommandNative(String command);
 
-    private native String doStringCommand(String iface, String command);
+    private native String doStringCommandNative(String command);
 
-    public WifiNative(String iface) {
-        mInterface = iface;
-        mTAG = "WifiNative-" + iface;
+    public WifiNative(String interfaceName) {
+        mInterfaceName = interfaceName;
+        mInterfacePrefix = "IFNAME=" + interfaceName + " ";
+        mTAG = "WifiNative-" + interfaceName;
     }
 
     public boolean connectToSupplicant() {
-        return connectToSupplicant(mInterface);
+        return connectToSupplicantNative();
     }
 
     public void closeSupplicantConnection() {
-        closeSupplicantConnection(mInterface);
+        closeSupplicantConnectionNative();
     }
 
     public String waitForEvent() {
-        return waitForEvent(mInterface);
+        return waitForEventNative();
     }
 
     private boolean doBooleanCommand(String command) {
         if (DBG) Log.d(mTAG, "doBoolean: " + command);
-        return doBooleanCommand(mInterface, command);
+        return doBooleanCommandNative(mInterfacePrefix + command);
     }
 
     private int doIntCommand(String command) {
         if (DBG) Log.d(mTAG, "doInt: " + command);
-        return doIntCommand(mInterface, command);
+        return doIntCommandNative(mInterfacePrefix + command);
     }
 
     private String doStringCommand(String command) {
         if (DBG) Log.d(mTAG, "doString: " + command);
-        return doStringCommand(mInterface, command);
+        return doStringCommandNative(mInterfacePrefix + command);
     }
 
     public boolean ping() {
@@ -411,9 +414,9 @@ public class WifiNative {
 
     public boolean startWpsPbc(String iface, String bssid) {
         if (TextUtils.isEmpty(bssid)) {
-            return doBooleanCommand("IFNAME=" + iface + " WPS_PBC");
+            return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC");
         } else {
-            return doBooleanCommand("IFNAME=" + iface + " WPS_PBC " + bssid);
+            return doBooleanCommandNative("IFNAME=" + iface + " WPS_PBC " + bssid);
         }
     }
 
@@ -424,7 +427,7 @@ public class WifiNative {
 
     public boolean startWpsPinKeypad(String iface, String pin) {
         if (TextUtils.isEmpty(pin)) return false;
-        return doBooleanCommand("IFNAME=" + iface + " WPS_PIN any " + pin);
+        return doBooleanCommandNative("IFNAME=" + iface + " WPS_PIN any " + pin);
     }
 
 
@@ -438,9 +441,9 @@ public class WifiNative {
 
     public String startWpsPinDisplay(String iface, String bssid) {
         if (TextUtils.isEmpty(bssid)) {
-            return doStringCommand("IFNAME=" + iface + " WPS_PIN any");
+            return doStringCommandNative("IFNAME=" + iface + " WPS_PIN any");
         } else {
-            return doStringCommand("IFNAME=" + iface + " WPS_PIN " + bssid);
+            return doStringCommandNative("IFNAME=" + iface + " WPS_PIN " + bssid);
         }
     }
 
@@ -492,7 +495,7 @@ public class WifiNative {
     }
 
     public boolean setP2pGroupIdle(String iface, int time) {
-        return doBooleanCommand("IFNAME=" + iface + " SET p2p_group_idle " + time);
+        return doBooleanCommandNative("IFNAME=" + iface + " SET p2p_group_idle " + time);
     }
 
     public void setPowerSave(boolean enabled) {
@@ -505,9 +508,9 @@ public class WifiNative {
 
     public boolean setP2pPowerSave(String iface, boolean enabled) {
         if (enabled) {
-            return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 1");
+            return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 1");
         } else {
-            return doBooleanCommand("IFNAME=" + iface + " P2P_SET ps 0");
+            return doBooleanCommandNative("IFNAME=" + iface + " P2P_SET ps 0");
         }
     }
 
@@ -645,7 +648,7 @@ public class WifiNative {
 
     public boolean p2pGroupRemove(String iface) {
         if (TextUtils.isEmpty(iface)) return false;
-        return doBooleanCommand("P2P_GROUP_REMOVE " + iface);
+        return doBooleanCommandNative("IFNAME=" + iface + " P2P_GROUP_REMOVE " + iface);
     }
 
     public boolean p2pReject(String deviceAddress) {
index 4628c91..91702f9 100644 (file)
@@ -68,6 +68,7 @@ import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.WorkSource;
 import android.provider.Settings;
+import android.util.Log;
 import android.util.LruCache;
 import android.text.TextUtils;
 
@@ -543,7 +544,6 @@ public class WifiStateMachine extends StateMachine {
 
     public WifiStateMachine(Context context, String wlanInterface) {
         super("WifiStateMachine");
-
         mContext = context;
         mInterfaceName = wlanInterface;
 
@@ -888,6 +888,7 @@ public class WifiStateMachine extends StateMachine {
      * TODO: doc
      */
     public void setOperationalMode(int mode) {
+        if (DBG) log("setting operational mode to " + String.valueOf(mode));
         sendMessage(CMD_SET_OPERATIONAL_MODE, mode, 0);
     }
 
@@ -1756,8 +1757,7 @@ public class WifiStateMachine extends StateMachine {
         /* Socket connection can be lost when we do a graceful shutdown
         * or when the driver is hung. Ensure supplicant is stopped here.
         */
-        mWifiNative.killSupplicant(mP2pSupported);
-        mWifiNative.closeSupplicantConnection();
+        mWifiMonitor.killSupplicant(mP2pSupported);
         sendSupplicantConnectionChangedBroadcast(false);
         setWifiState(WIFI_STATE_DISABLED);
     }
@@ -2139,7 +2139,7 @@ public class WifiStateMachine extends StateMachine {
                         * Avoids issues with drivers that do not handle interface down
                         * on a running supplicant properly.
                         */
-                        mWifiNative.killSupplicant(mP2pSupported);
+                        mWifiMonitor.killSupplicant(mP2pSupported);
                         if(mWifiNative.startSupplicant(mP2pSupported)) {
                             setWifiState(WIFI_STATE_ENABLING);
                             if (DBG) log("Supplicant start successful");
@@ -2222,7 +2222,7 @@ public class WifiStateMachine extends StateMachine {
                 case WifiMonitor.SUP_DISCONNECTION_EVENT:
                     if (++mSupplicantRestartCount <= SUPPLICANT_RESTART_TRIES) {
                         loge("Failed to setup control channel, restart supplicant");
-                        mWifiNative.killSupplicant(mP2pSupported);
+                        mWifiMonitor.killSupplicant(mP2pSupported);
                         transitionTo(mInitialState);
                         sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
                     } else {
@@ -2329,9 +2329,7 @@ public class WifiStateMachine extends StateMachine {
             }
 
             if (DBG) log("stopping supplicant");
-            if (!mWifiNative.stopSupplicant()) {
-                loge("Failed to stop supplicant");
-            }
+            mWifiMonitor.stopSupplicant();
 
             /* Send ourselves a delayed message to indicate failure after a wait time */
             sendMessageDelayed(obtainMessage(CMD_STOP_SUPPLICANT_FAILED,
index 68a082a..63b94a2 100644 (file)
@@ -858,7 +858,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub {
                     }
                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
 
-                    mWifiNative.closeSupplicantConnection();
+                    mWifiMonitor.stopMonitoring();
                     transitionTo(mP2pDisablingState);
                     break;
                 case WifiP2pManager.SET_DEVICE_NAME: