Fix WiFiNetworkAgent#unwanted

1) No longer blacklist a network when it's unwanted by NetworkAgent.
2) Deprecate the network disable reason BAD_LINK.
3) Stop WiFi Auto_Connect attempt if neither saved Wifi network nor
   untrusted WiFi network is requested.

Bug: 28558417
Tests: Unit Tests and manual tests
Change-Id: I2b245cfb357b92ed925d89603e0fefded9d6865a
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index c1a334a..dbe67e8 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -190,7 +190,7 @@
      */
     private static final int[] NETWORK_SELECTION_DISABLE_THRESHOLD = {
             -1, //  threshold for NETWORK_SELECTION_ENABLE
-            1,  //  threshold for DISABLED_BAD_LINK
+            1,  //  threshold for DISABLED_BAD_LINK (deprecated)
             5,  //  threshold for DISABLED_ASSOCIATION_REJECTION
             5,  //  threshold for DISABLED_AUTHENTICATION_FAILURE
             5,  //  threshold for DISABLED_DHCP_FAILURE
@@ -206,7 +206,7 @@
      */
     private static final int[] NETWORK_SELECTION_DISABLE_TIMEOUT = {
             Integer.MAX_VALUE,  // threshold for NETWORK_SELECTION_ENABLE
-            15,                 // threshold for DISABLED_BAD_LINK
+            15,                 // threshold for DISABLED_BAD_LINK (deprecated)
             5,                  // threshold for DISABLED_ASSOCIATION_REJECTION
             5,                  // threshold for DISABLED_AUTHENTICATION_FAILURE
             5,                  // threshold for DISABLED_DHCP_FAILURE
@@ -243,11 +243,6 @@
     public AtomicInteger mBandAward5Ghz = new AtomicInteger();
 
     /**
-     * If Connectivity Service has triggered an unwanted network disconnect
-     */
-    public long mLastUnwantedNetworkDisconnectTimestamp = 0;
-
-    /**
      * Framework keeps a list of ephemeral SSIDs that where deleted by user,
      * so as, framework knows not to autojoin again those SSIDs based on scorer input.
      * The list is never cleared up.
@@ -3222,29 +3217,6 @@
         }
     }
 
-    /** called when CS ask WiFistateMachine to disconnect the current network
-     * because the score is bad.
-     */
-    void handleBadNetworkDisconnectReport(int netId, WifiInfo info) {
-        /* TODO verify the bad network is current */
-        WifiConfiguration config = mConfiguredNetworks.getForCurrentUser(netId);
-        if (config != null) {
-            if ((info.is24GHz() && info.getRssi()
-                    <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_24G_BAND)
-                    || (info.is5GHz() && info.getRssi()
-                    <= WifiQualifiedNetworkSelector.QUALIFIED_RSSI_5G_BAND)) {
-                // We do not block due to bad RSSI since network selection should not select bad
-                // RSSI candidate
-            } else {
-                // We got disabled but RSSI is good, so disable hard
-                updateNetworkSelectionStatus(config,
-                        WifiConfiguration.NetworkSelectionStatus.DISABLED_BAD_LINK);
-            }
-        }
-        // Record last time Connectivity Service switched us away from WiFi and onto Cell
-        mLastUnwantedNetworkDisconnectTimestamp = mClock.currentTimeMillis();
-    }
-
     int getMaxDhcpRetries() {
         return mFacade.getIntegerSetting(mContext,
                 Settings.Global.WIFI_MAX_DHCP_RETRY_COUNT,
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 7f3d5d7..1c388c1 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -510,7 +510,7 @@
     public WifiConnectivityManager(Context context, WifiStateMachine stateMachine,
                 WifiScanner scanner, WifiConfigManager configManager, WifiInfo wifiInfo,
                 WifiQualifiedNetworkSelector qualifiedNetworkSelector,
-                WifiInjector wifiInjector, Looper looper) {
+                WifiInjector wifiInjector, Looper looper, boolean enable) {
         mStateMachine = stateMachine;
         mScanner = scanner;
         mConfigManager = configManager;
@@ -545,7 +545,10 @@
         // Register for all single scan results
         mScanner.registerScanListener(mAllSingleScanListener);
 
-        Log.i(TAG, "ConnectivityScanManager initialized ");
+        mWifiConnectivityManagerEnabled = enable;
+
+        Log.i(TAG, "ConnectivityScanManager initialized and "
+                + (enable ? "enabled" : "disabled"));
     }
 
     /**
@@ -1118,6 +1121,8 @@
             stopConnectivityScan();
             resetLastPeriodicSingleScanTimeStamp();
             mLastConnectionAttemptBssid = null;
+        } else if (mWifiConnectivityManagerEnabled) {
+           startConnectivityScan(SCAN_IMMEDIATELY);
         }
     }
 
@@ -1133,6 +1138,8 @@
             stopConnectivityScan();
             resetLastPeriodicSingleScanTimeStamp();
             mLastConnectionAttemptBssid = null;
+        } else if (mWifiEnabled) {
+           startConnectivityScan(SCAN_IMMEDIATELY);
         }
     }
 
diff --git a/service/java/com/android/server/wifi/WifiStateMachine.java b/service/java/com/android/server/wifi/WifiStateMachine.java
index ab91420..a1bf1f1 100644
--- a/service/java/com/android/server/wifi/WifiStateMachine.java
+++ b/service/java/com/android/server/wifi/WifiStateMachine.java
@@ -96,6 +96,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.util.AsyncChannel;
@@ -544,10 +545,14 @@
 
     private WifiScanner mWifiScanner;
 
-    private int mConnectionRequests = 0;
+    @GuardedBy("mWifiReqCountLock")
+    private int mConnectionReqCount = 0;
     private WifiNetworkFactory mNetworkFactory;
+    @GuardedBy("mWifiReqCountLock")
+    private int mUntrustedReqCount = 0;
     private UntrustedWifiNetworkFactory mUntrustedNetworkFactory;
     private WifiNetworkAgent mNetworkAgent;
+    private final Object mWifiReqCountLock = new Object();
 
     private String[] mWhiteListedSsids = null;
 
@@ -2535,7 +2540,8 @@
                 sb.append(" known=").append(mNumScanResultsKnown);
                 sb.append(" got=").append(mNumScanResultsReturned);
                 sb.append(String.format(" bcn=%d", mRunningBeaconCount));
-                sb.append(String.format(" con=%d", mConnectionRequests));
+                sb.append(String.format(" con=%d", mConnectionReqCount));
+                sb.append(String.format(" untrustedcn=%d", mUntrustedReqCount));
                 key = mWifiConfigManager.getLastSelectedConfiguration();
                 if (key != null) {
                     sb.append(" last=").append(key);
@@ -3906,23 +3912,33 @@
 
         @Override
         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
-            ++mConnectionRequests;
+            synchronized (mWifiReqCountLock) {
+                if (++mConnectionReqCount == 1) {
+                    if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) {
+                        mWifiConnectivityManager.enable(true);
+                    }
+                }
+            }
         }
 
         @Override
         protected void releaseNetworkFor(NetworkRequest networkRequest) {
-            --mConnectionRequests;
+            synchronized (mWifiReqCountLock) {
+                if (--mConnectionReqCount == 0) {
+                    if (mWifiConnectivityManager != null && mUntrustedReqCount == 0) {
+                        mWifiConnectivityManager.enable(false);
+                    }
+                }
+            }
         }
 
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            pw.println("mConnectionRequests " + mConnectionRequests);
+            pw.println("mConnectionReqCount " + mConnectionReqCount);
         }
 
     }
 
     private class UntrustedWifiNetworkFactory extends NetworkFactory {
-        private int mUntrustedReqCount;
-
         public UntrustedWifiNetworkFactory(Looper l, Context c, String tag, NetworkCapabilities f) {
             super(l, c, tag, f);
         }
@@ -3931,9 +3947,14 @@
         protected void needNetworkFor(NetworkRequest networkRequest, int score) {
             if (!networkRequest.networkCapabilities.hasCapability(
                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
-                if (++mUntrustedReqCount == 1) {
-                    if (mWifiConnectivityManager != null) {
-                        mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
+                synchronized (mWifiReqCountLock) {
+                    if (++mUntrustedReqCount == 1) {
+                        if (mWifiConnectivityManager != null) {
+                            if (mConnectionReqCount == 0) {
+                                mWifiConnectivityManager.enable(true);
+                            }
+                            mWifiConnectivityManager.setUntrustedConnectionAllowed(true);
+                        }
                     }
                 }
             }
@@ -3943,9 +3964,14 @@
         protected void releaseNetworkFor(NetworkRequest networkRequest) {
             if (!networkRequest.networkCapabilities.hasCapability(
                     NetworkCapabilities.NET_CAPABILITY_TRUSTED)) {
-                if (--mUntrustedReqCount == 0) {
-                    if (mWifiConnectivityManager != null) {
-                        mWifiConnectivityManager.setUntrustedConnectionAllowed(false);
+                synchronized (mWifiReqCountLock) {
+                    if (--mUntrustedReqCount == 0) {
+                        if (mWifiConnectivityManager != null) {
+                            mWifiConnectivityManager.setUntrustedConnectionAllowed(false);
+                            if (mConnectionReqCount == 0) {
+                                mWifiConnectivityManager.enable(false);
+                            }
+                        }
                     }
                 }
             }
@@ -4682,10 +4708,12 @@
             if (mWifiScanner == null) {
                 mWifiScanner = mFacade.makeWifiScanner(mContext, getHandler().getLooper());
 
-                mWifiConnectivityManager = new WifiConnectivityManager(mContext,
-                    WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo,
-                    mWifiQualifiedNetworkSelector, mWifiInjector,
-                    getHandler().getLooper());
+                synchronized (mWifiReqCountLock) {
+                    mWifiConnectivityManager = new WifiConnectivityManager(mContext,
+                        WifiStateMachine.this, mWifiScanner, mWifiConfigManager, mWifiInfo,
+                        mWifiQualifiedNetworkSelector, mWifiInjector,
+                        getHandler().getLooper(), hasConnectionRequests());
+                }
             }
 
             mWifiLogger.startLogging(DBG);
@@ -7069,8 +7097,6 @@
                     break;
                 case CMD_UNWANTED_NETWORK:
                     if (message.arg1 == NETWORK_STATUS_UNWANTED_DISCONNECT) {
-                        mWifiConfigManager.handleBadNetworkDisconnectReport(
-                                mLastNetworkId, mWifiInfo);
                         mWifiNative.disconnect();
                         transitionTo(mDisconnectingState);
                     } else if (message.arg1 == NETWORK_STATUS_UNWANTED_DISABLE_AUTOJOIN ||
@@ -8064,7 +8090,11 @@
      * @param bssid BSSID of the network
      */
     public void autoConnectToNetwork(int networkId, String bssid) {
-        sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid);
+        synchronized (mWifiReqCountLock) {
+            if (hasConnectionRequests()) {
+                sendMessage(CMD_AUTO_CONNECT, networkId, 0, bssid);
+            }
+        }
     }
 
     /**
@@ -8207,4 +8237,12 @@
         }
         return null;
     }
+
+    /**
+     * Check if there is any connection request for WiFi network.
+     * Note, caller of this helper function must acquire mWifiReqCountLock.
+     */
+    private boolean hasConnectionRequests() {
+        return mConnectionReqCount > 0 || mUntrustedReqCount > 0;
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index 022997d..b1f88ec 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -75,7 +75,7 @@
         mWifiQNS = mockWifiQualifiedNetworkSelector();
         mWifiConnectivityManager = new WifiConnectivityManager(mContext, mWifiStateMachine,
                 mWifiScanner, mWifiConfigManager, mWifiInfo, mWifiQNS, mWifiInjector,
-                mLooper.getLooper());
+                mLooper.getLooper(), true);
         mWifiConnectivityManager.setWifiEnabled(true);
         when(mClock.elapsedRealtime()).thenReturn(SystemClock.elapsedRealtime());
     }