am 1ec92c57: - detect that firmware cant stay connected to 5GHz AP and tune down 5GHz preference accordingly - use a long random string so as to obfuscate PSK of WiFiConfiguration we have deleted but keep around in the autojoin database - if autojoin doesn\'t find a kn

* commit '1ec92c57244311c7fca3ab6b244a06c2b2b58902':
  - detect that firmware cant stay connected to 5GHz AP and tune down 5GHz preference accordingly - use a long random string so as to obfuscate PSK of WiFiConfiguration we have deleted but keep around in the autojoin database - if autojoin doesn't find a known network to join, and sees a known network that ConnectivityService never marked as UNWANTED due to bad signal, then add a boost of up to +8dB to this network's autojoin threshold, also includes the boost in the network's score that is sent to connectivity service
diff --git a/service/java/com/android/server/wifi/WifiAutoJoinController.java b/service/java/com/android/server/wifi/WifiAutoJoinController.java
index b7aa06a..f6741b4 100644
--- a/service/java/com/android/server/wifi/WifiAutoJoinController.java
+++ b/service/java/com/android/server/wifi/WifiAutoJoinController.java
@@ -17,12 +17,11 @@
 package com.android.server.wifi;
 
 import android.content.Context;
-
 import android.net.NetworkKey;
 import android.net.NetworkScoreManager;
 import android.net.WifiKey;
 import android.net.wifi.*;
-
+import android.net.wifi.WifiConfiguration.KeyMgmt;
 import android.os.SystemClock;
 import android.os.Process;
 import android.text.TextUtils;
@@ -64,6 +63,9 @@
 
     private WifiConnectionStatistics mWifiConnectionStatistics;
 
+    /** Whether to allow connections to untrusted networks. */
+    private boolean mAllowUntrustedConnections = false;
+
     /* for debug purpose only : the untrusted SSID we would be connected to if we had VPN */
     String lastUntrustedBSSID = null;
 
@@ -1100,6 +1102,23 @@
     }
 
     /**
+     * Set whether connections to untrusted connections are allowed.
+     */
+    void setAllowUntrustedConnections(boolean allow) {
+        boolean changed = mAllowUntrustedConnections != allow;
+        mAllowUntrustedConnections = allow;
+        if (changed) {
+            attemptAutoJoin();
+        }
+    }
+
+    private boolean isOpenNetwork(ScanResult result) {
+        return !result.capabilities.contains("WEP") &&
+                !result.capabilities.contains("PSK") &&
+                !result.capabilities.contains("EAP");
+    }
+
+    /**
      * attemptAutoJoin() function implements the core of the a network switching algorithm
      */
     void attemptAutoJoin() {
@@ -1201,6 +1220,14 @@
                         + Integer.toString(currentConfiguration.networkId));
                 mWifiStateMachine.disconnectCommand();
                 return;
+            } else if (currentConfiguration.ephemeral && (!mAllowUntrustedConnections ||
+                    !mNetworkScoreCache.isScoredNetwork(currentConfiguration.lastSeen()))) {
+                // The current connection is untrusted (the framework added it), but we're either
+                // no longer allowed to connect to such networks, or the score has been nullified
+                // since we connected. Drop the current connection and perform the rest of autojoin.
+                logDbg("attemptAutoJoin() disconnecting from unwanted ephemeral network");
+                mWifiStateMachine.disconnectCommand();
+                return;
             } else {
                 mCurrentConfigurationKey = currentConfiguration.configKey();
             }
@@ -1431,8 +1458,9 @@
             }
         }
 
-        // Wait for VPN to be available on the system to make use of this code
         // Now, go thru scan result to try finding a better untrusted network
+        // TODO: Consider only running this when we can actually connect to these networks. For now,
+        // this is useful for debugging.
         if (mNetworkScoreCache != null) {
             int rssi5 = WifiConfiguration.INVALID_RSSI;
             int rssi24 = WifiConfiguration.INVALID_RSSI;
@@ -1453,7 +1481,8 @@
                     int rssiBoost = 0;
                     // We look only at untrusted networks with a valid SSID
                     // A trusted result would have been looked at thru it's Wificonfiguration
-                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted) {
+                    if (TextUtils.isEmpty(result.SSID) || !result.untrusted ||
+                            !isOpenNetwork(result)) {
                         continue;
                     }
                     if ((nowMs - result.seen) < 3000) {
@@ -1492,9 +1521,16 @@
                     // Remember which SSID we are connecting to
                     lastUntrustedBSSID = untrustedCandidate.SSID;
                 }
+
+                // At this point, we have an untrusted network candidate.
+                // Create the new ephemeral configuration and see if we should switch over
+                if (mAllowUntrustedConnections) {
+                    candidate =
+                            mWifiConfigStore.wifiConfigurationFromScanResult(untrustedCandidate);
+                    candidate.allowedKeyManagement.set(KeyMgmt.NONE);
+                    candidate.ephemeral = true;
+                }
             }
-            // Now we don't have VPN, and thus don't actually connect to the untrusted candidate
-            untrustedCandidate = null;
         }
 
         long lastUnwanted =
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java
index b9e6c80..41d27be 100644
--- a/service/java/com/android/server/wifi/WifiConfigStore.java
+++ b/service/java/com/android/server/wifi/WifiConfigStore.java
@@ -564,7 +564,7 @@
         List<WifiConfiguration> networks = new ArrayList<>();
         for(WifiConfiguration config : mConfiguredNetworks.values()) {
             WifiConfiguration newConfig = new WifiConfiguration(config);
-            if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) {
+            if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || config.ephemeral) {
                 // Do not enumerate and return this configuration to any one,
                 // for instance WiFi Picker.
                 // instead treat it as unknown. the configuration can still be retrieved
@@ -619,10 +619,10 @@
      * @return List of networks
      */
     List<WifiConfiguration> getRecentConfiguredNetworks(int milli, boolean copy) {
-        List<WifiConfiguration> networks = null;
+        List<WifiConfiguration> networks = new ArrayList<WifiConfiguration>();
 
         for (WifiConfiguration config : mConfiguredNetworks.values()) {
-            if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) {
+            if (config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || config.ephemeral) {
                 // Do not enumerate and return this configuration to any one,
                 // instead treat it as unknown. the configuration can still be retrieved
                 // directly by the key or networkId
@@ -638,8 +638,6 @@
                     config.visibility.rssi24 == WifiConfiguration.INVALID_RSSI) {
                 continue;
             }
-            if (networks == null)
-                networks = new ArrayList<WifiConfiguration>();
             if (copy) {
                 networks.add(new WifiConfiguration(config));
             } else {
@@ -2483,7 +2481,8 @@
             WifiConfiguration config = mConfiguredNetworks.get(mNetworkIds.get(id));
 
 
-            if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) {
+            if (config == null || config.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED ||
+                    config.ephemeral) {
                 loge("configuration found for missing network, nid=" + id
                         +", ignored, networks.size=" + Integer.toString(networks.size()));
             } else {
@@ -2828,6 +2827,14 @@
             currentConfig.setAutoJoinStatus(WifiConfiguration.AUTO_JOIN_ENABLED);
         }
 
+        if (currentConfig.configKey().equals(getLastSelectedConfiguration()) &&
+                currentConfig.ephemeral) {
+            // Make the config non-ephemeral since the user just explicitly clicked it.
+            currentConfig.ephemeral = false;
+            if (DBG) loge("remove ephemeral status netId=" + Integer.toString(netId)
+                    + " " + currentConfig.configKey());
+        }
+
         if (DBG) loge("will read network variables netId=" + Integer.toString(netId));
 
         readNetworkVariables(currentConfig);
@@ -2866,7 +2873,7 @@
                 continue;
             }
 
-            if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED) {
+            if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.ephemeral) {
                 continue;
             }
 
@@ -2999,7 +3006,8 @@
         for (WifiConfiguration link : mConfiguredNetworks.values()) {
             boolean doLink = false;
 
-            if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.selfAdded) {
+            if (link.autoJoinStatus == WifiConfiguration.AUTO_JOIN_DELETED || link.selfAdded ||
+                    link.ephemeral) {
                 if (VVDBG) loge("associateWithConfiguration(): skip selfadd " + link.configKey() );
                 // Make sure we dont associate the scan result to a deleted config
                 continue;
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index 9003706..9eb7ef4 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -16,21 +16,20 @@
 
 package com.android.server.wifi;
 
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
-import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
-import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
-
-/**
- * TODO:
- * Deprecate WIFI_STATE_UNKNOWN
- */
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLING;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLED;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_ENABLING;
 import static android.net.wifi.WifiManager.WIFI_AP_STATE_FAILED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+/**
+ * TODO:
+ * Deprecate WIFI_STATE_UNKNOWN
+ */
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
 
 import android.app.AlarmManager;
 import android.app.PendingIntent;
@@ -53,12 +52,27 @@
 import android.net.NetworkFactory;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkRequest;
 import android.net.NetworkUtils;
 import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.TrafficStats;
-import android.net.wifi.*;
+import android.net.wifi.BatchedScanResult;
+import android.net.wifi.BatchedScanSettings;
+import android.net.wifi.RssiPacketCountInfo;
+import android.net.wifi.ScanResult;
+import android.net.wifi.ScanSettings;
 import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiChannel;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConnectionStatistics;
+import android.net.wifi.WifiEnterpriseConfig;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiLinkLayerStats;
+import android.net.wifi.WifiManager;
+import android.net.wifi.WifiSsid;
+import android.net.wifi.WpsInfo;
+import android.net.wifi.WpsResult;
 import android.net.wifi.WpsResult.Status;
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.os.BatteryStats;
@@ -78,9 +92,9 @@
 import android.os.WorkSource;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
-import android.util.LruCache;
 import android.text.TextUtils;
 import android.util.Log;
+import android.util.LruCache;
 
 import com.android.internal.R;
 import com.android.internal.app.IBatteryStats;
@@ -88,23 +102,26 @@
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
-import com.android.server.net.BaseNetworkObserver;
 import com.android.server.net.NetlinkTracker;
-
 import com.android.server.wifi.p2p.WifiP2pServiceImpl;
 
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.InetAddress;
-import java.util.*;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.regex.Pattern;
-import java.io.FileReader;
 import java.io.BufferedReader;
+import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
+import java.io.FileReader;
 import java.io.IOException;
+import java.io.PrintWriter;
 import java.net.Inet4Address;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Queue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.regex.Pattern;
 
 /**
  * Track the state of Wifi connectivity. All event handling is done here,
@@ -4325,9 +4342,17 @@
     private void handleSuccessfulIpConfiguration() {
         mLastSignalLevel = -1; // Force update of signal strength
         WifiConfiguration c = getCurrentWifiConfiguration();
-        // Reset IP failure tracking
         if (c != null) {
+            // Reset IP failure tracking
             c.numConnectionFailures = 0;
+
+            // Tell the framework whether the newly connected network is trusted or untrusted.
+            if (c.ephemeral) {
+                mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
+            } else {
+                mNetworkCapabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED);
+            }
+            mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
         }
         if (c != null) {
             ScanResult result = getCurrentScanResult();
@@ -4454,16 +4479,31 @@
     }
 
     private class WifiNetworkFactory extends NetworkFactory {
+        /** Number of outstanding NetworkRequests for untrusted networks. */
+        private int mUntrustedReqCount = 0;
+
         public WifiNetworkFactory(Looper l, Context c, String TAG, NetworkCapabilities f) {
             super(l, c, TAG, f);
         }
-        protected void startNetwork() {
-            // TODO
-            // Enter association mode.
+
+        @Override
+        protected void needNetworkFor(NetworkRequest networkRequest, int score) {
+            if (!networkRequest.networkCapabilities.hasCapability(
+                    NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
+                if (++mUntrustedReqCount == 1) {
+                    mWifiAutoJoinController.setAllowUntrustedConnections(true);
+                }
+            }
         }
-        protected void stopNetwork() {
-            // TODO
-            // Stop associating.
+
+        @Override
+        protected void releaseNetworkFor(NetworkRequest networkRequest) {
+            if (!networkRequest.networkCapabilities.hasCapability(
+                    NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
+                if (--mUntrustedReqCount == 0) {
+                    mWifiAutoJoinController.setAllowUntrustedConnections(false);
+                }
+            }
         }
     }
     /********************************************************