Snap for 8069721 from d7d443a8532dcaa703b8aa587472f1d31fdfe6f8 to mainline-extservices-release

Change-Id: I9b2d9624b87bae5c973cf385e5f92fd341854050
diff --git a/service/ServiceWifiResources/res/values-ta/strings.xml b/service/ServiceWifiResources/res/values-ta/strings.xml
index cc1ddc4..3445ea4 100644
--- a/service/ServiceWifiResources/res/values-ta/strings.xml
+++ b/service/ServiceWifiResources/res/values-ta/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="wifiResourcesAppLabel" product="default" msgid="3120115613525263696">"சிஸ்டம் வைஃபை ஆதாரங்கள்"</string>
+    <string name="wifiResourcesAppLabel" product="default" msgid="3120115613525263696">"சிஸ்டம் வைஃபை தொடர்பானவை"</string>
     <string name="wifi_available_title" msgid="3899472737467127635">"திறந்த வைஃபை நெட்வொர்க்குடன் இணைக்கவும்"</string>
     <string name="wifi_available_title_connecting" msgid="7233590022728579868">"வைஃபை நெட்வொர்க்குடன் இணைக்கிறது"</string>
     <string name="wifi_available_title_connected" msgid="6329493859989844201">"வைஃபை நெட்வொர்க்குடன் இணைக்கப்பட்டது"</string>
diff --git a/service/ServiceWifiResources/res/values/config.xml b/service/ServiceWifiResources/res/values/config.xml
index 063d4fc..b57b4cc 100644
--- a/service/ServiceWifiResources/res/values/config.xml
+++ b/service/ServiceWifiResources/res/values/config.xml
@@ -195,6 +195,14 @@
     <!-- Integer duration after connection that a user-selected network is considered sufficient (milliseconds) -->
     <integer translatable="false" name="config_wifiSufficientDurationAfterUserSelectionMilliseconds">60000</integer>
 
+    <!-- Trigger connectivity scan for MBB when the connected score is below the configured value.
+         This scan is only done when the external scorer is not being used. -->
+    <integer translatable="false" name="config_wifiLowConnectedScoreThresholdToTriggerScanForMbb">55</integer>
+
+    <!-- Defines the minimum period between scans triggered due to low score.
+    This is used together with config_wifiConnectedScoreThresholdToTriggerScanForMbb.-->
+    <integer translatable="false" name="config_wifiLowConnectedScoreScanPeriodSeconds">60</integer>
+
     <!-- Boolean indicating whether the wifi module should always scan the 6Ghz Preferred Scanning
          Channels when performing full connectivity scans.
          If set to true, the wifi module will scan 6Ghz PSC channels in addition to the 2.4Ghz,
diff --git a/service/ServiceWifiResources/res/values/overlayable.xml b/service/ServiceWifiResources/res/values/overlayable.xml
index 524bbb7..1e716a4 100644
--- a/service/ServiceWifiResources/res/values/overlayable.xml
+++ b/service/ServiceWifiResources/res/values/overlayable.xml
@@ -74,6 +74,8 @@
           <item type="integer" name="config_wifi_framework_recovery_timeout_delay" />
           <item type="bool" name="config_wifi_framework_enable_associated_network_selection" />
           <item type="integer" name="config_wifiSufficientDurationAfterUserSelectionMilliseconds" />
+          <item type="integer" name="config_wifiLowConnectedScoreThresholdToTriggerScanForMbb" />
+          <item type="integer" name="config_wifiLowConnectedScoreScanPeriodSeconds" />
           <item type="bool" name="config_wifiEnable6ghzPscScanning" />
           <item type="bool" name="config_wifiEnablePartialInitialScan" />
           <item type="integer" name="config_wifiInitialPartialScanChannelMaxCount" />
diff --git a/service/java/com/android/server/wifi/ActiveModeWarden.java b/service/java/com/android/server/wifi/ActiveModeWarden.java
index b882eb2..8b6e388 100644
--- a/service/java/com/android/server/wifi/ActiveModeWarden.java
+++ b/service/java/com/android/server/wifi/ActiveModeWarden.java
@@ -731,6 +731,14 @@
     }
 
     /**
+     * Checks if a CMM can be started for MBB.
+     */
+    public boolean canRequestSecondaryTransientClientModeManager() {
+        return canRequestMoreClientModeManagersInRole(INTERNAL_REQUESTOR_WS,
+                ROLE_CLIENT_SECONDARY_TRANSIENT);
+    }
+
+    /**
      * Remove the provided client manager.
      */
     public void removeClientModeManager(ClientModeManager clientModeManager) {
@@ -746,6 +754,15 @@
     }
 
     /**
+     * Checks whether there exists a primary or scan only mode manager.
+     * @return
+     */
+    private boolean hasPrimaryOrScanOnlyModeManager() {
+        return getClientModeManagerInRole(ROLE_CLIENT_PRIMARY) != null
+                || getClientModeManagerInRole(ROLE_CLIENT_SCAN_ONLY) != null;
+    }
+
+    /**
      * Returns primary client mode manager if any, else returns null
      * This mode manager can be the default route on the device & will handle all external API
      * calls.
@@ -1767,7 +1784,7 @@
 
         private void handleStaToggleChangeInEnabledState(WorkSource requestorWs) {
             if (shouldEnableSta()) {
-                if (hasAnyClientModeManager()) {
+                if (hasPrimaryOrScanOnlyModeManager()) {
                     if (!mSettingsStore.isWifiToggleEnabled()) {
                         // Wifi is turned off, so we should stop all the secondary CMMs which are
                         // currently all for connectivity purpose. It's important to stops the
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 0de2b74..f8db268 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -156,7 +156,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -1118,6 +1117,32 @@
     }
 
     /**
+     * If there is only SAE-only networks with this auto-upgrade type,
+     * this auto-upgrade SAE type is considered to be added explicitly.
+     *
+     * For R, Settings/WifiTrackerLib maps WPA3 SAE to WPA2, so there is
+     * no chance to add or update a WPA3 SAE configuration to update
+     * the auto-upgrade flag.
+     */
+    private void updateSaeAutoUpgradeFlagForUserSelectNetwork(int networkId) {
+        if (SdkLevel.isAtLeastS()) return;
+        if (mWifiGlobals.isWpa3SaeUpgradeEnabled()) return;
+
+        WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(networkId);
+        if (null == config) return;
+        SecurityParams params = config.getSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+        if (null == params || !params.isAddedByAutoUpgrade()) return;
+
+        if (!mScanRequestProxy.isWpa3PersonalOnlyNetworkInRange(config.SSID)) return;
+        if (mScanRequestProxy.isWpa2PersonalOnlyNetworkInRange(config.SSID)) return;
+        if (mScanRequestProxy.isWpa2Wpa3PersonalTransitionNetworkInRange(config.SSID)) return;
+
+        logd("update auto-upgrade flag for SAE");
+        mWifiConfigManager.updateIsAddedByAutoUpgradeFlag(
+                config.networkId, WifiConfiguration.SECURITY_TYPE_SAE, false);
+    }
+
+    /**
      * Initiates connection to a network specified by the user/app. This method checks if the
      * requesting app holds the NETWORK_SETTINGS permission.
      *
@@ -1129,6 +1154,7 @@
     private void connectToUserSelectNetwork(int netId, int uid, boolean forceReconnect) {
         logd("connectToUserSelectNetwork netId " + netId + ", uid " + uid
                 + ", forceReconnect = " + forceReconnect);
+        updateSaeAutoUpgradeFlagForUserSelectNetwork(netId);
         if (!forceReconnect && (mLastNetworkId == netId || mTargetNetworkId == netId)) {
             // We're already connecting/connected to the user specified network, don't trigger a
             // reconnection unless it was forced.
@@ -6204,18 +6230,12 @@
 
         // This comes from wifi picker directly so there is no candidate security params.
         // Run network selection against this SSID.
-        List<ScanDetail> scanDetailsList = scanResults.stream()
+        scanResults.stream()
                 .filter(scanResult -> config.SSID.equals(
                         ScanResultUtil.createQuotedSSID(scanResult.SSID)))
                 .map(ScanResultUtil::toScanDetail)
-                .collect(Collectors.toList());
-        List<WifiNetworkSelector.ClientModeManagerState> cmmState = new ArrayList<>();
-        cmmState.add(new WifiNetworkSelector.ClientModeManagerState(mClientModeManager));
-        // getCandidatesFromScan updates candidate security params to configurations
-        // match these scanDetails.
-        mWifiNetworkSelector.getCandidatesFromScan(
-                scanDetailsList, new HashSet<String>(), cmmState,
-                true, true, true);
+                .forEach(scanDetail -> mWifiNetworkSelector
+                        .updateNetworkCandidateSecurityParams(config, scanDetail));
         // Get the fresh copy again to retrieve the candidate security params.
         WifiConfiguration freshConfig = mWifiConfigManager.getConfiguredNetwork(config.networkId);
         if (null != freshConfig
@@ -6335,10 +6355,14 @@
                     new ProvisioningConfiguration.Builder()
                     .withPreDhcpAction()
                     .withPreconnection()
-                    .withApfCapabilities(
-                    mWifiNative.getApfCapabilities(mInterfaceName))
                     .withDisplayName(config.SSID)
                     .withLayer2Information(layer2Info);
+            if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta)
+                    || isPrimary()) {
+                // unclear if the native layer will return the correct non-capabilities if APF is
+                // not supported on secondary interfaces.
+                prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName));
+            }
             if (isUsingMacRandomization) {
                 // Use EUI64 address generation for link-local IPv6 addresses.
                 prov.withRandomMacAddress();
@@ -6394,7 +6418,6 @@
             if (!isUsingStaticIp) {
                 prov = new ProvisioningConfiguration.Builder()
                     .withPreDhcpAction()
-                    .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
                     .withNetwork(getCurrentNetwork())
                     .withDisplayName(config.SSID)
                     .withScanResultInfo(scanResultInfo)
@@ -6403,11 +6426,16 @@
                 StaticIpConfiguration staticIpConfig = config.getStaticIpConfiguration();
                 prov = new ProvisioningConfiguration.Builder()
                         .withStaticConfiguration(staticIpConfig)
-                        .withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName))
                         .withNetwork(getCurrentNetwork())
                         .withDisplayName(config.SSID)
                         .withLayer2Information(layer2Info);
             }
+            if (mContext.getResources().getBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta)
+                    || isPrimary()) {
+                // unclear if the native layer will return the correct non-capabilities if APF is
+                // not supported on secondary interfaces.
+                prov.withApfCapabilities(mWifiNative.getApfCapabilities(mInterfaceName));
+            }
             if (isUsingMacRandomization) {
                 // Use EUI64 address generation for link-local IPv6 addresses.
                 prov.withRandomMacAddress();
diff --git a/service/java/com/android/server/wifi/DppManager.java b/service/java/com/android/server/wifi/DppManager.java
index b0e1556..7cf6e73 100644
--- a/service/java/com/android/server/wifi/DppManager.java
+++ b/service/java/com/android/server/wifi/DppManager.java
@@ -593,10 +593,7 @@
                         mDppMetrics.updateDppEnrolleeResponderSuccess();
                     }
                     mDppRequestInfo.callback.onSuccessConfigReceived(
-                            WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                                    networkUpdateResult.getNetworkId(),
-                                    newWifiConfiguration.getDefaultSecurityParams()
-                                            .getSecurityType()));
+                            networkUpdateResult.getNetworkId());
                 } else {
                     Log.e(TAG, "DPP configuration received, but failed to update network");
                     mDppMetrics.updateDppFailure(EasyConnectStatusCallback
diff --git a/service/java/com/android/server/wifi/HalDeviceManager.java b/service/java/com/android/server/wifi/HalDeviceManager.java
index b664c1f..e87c38d 100644
--- a/service/java/com/android/server/wifi/HalDeviceManager.java
+++ b/service/java/com/android/server/wifi/HalDeviceManager.java
@@ -57,6 +57,7 @@
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -2367,6 +2368,11 @@
                 return false;
             }
 
+            // dispatch listeners on other threads to prevent race conditions in case the HAL is
+            // blocking and they get notification about destruction from HAL before cleaning up
+            // status.
+            dispatchDestroyedListeners(name, type, true);
+
             WifiStatus status = null;
             try {
                 switch (type) {
@@ -2391,7 +2397,7 @@
             }
 
             // dispatch listeners no matter what status
-            dispatchDestroyedListeners(name, type);
+            dispatchDestroyedListeners(name, type, false);
             if (validateRttController) {
                 // Try to update the RttController
                 updateRttControllerWhenInterfaceChanges();
@@ -2407,10 +2413,13 @@
     }
 
     // dispatch all destroyed listeners registered for the specified interface AND remove the
-    // cache entry
-    private void dispatchDestroyedListeners(String name, int type) {
+    // cache entries for the called listeners
+    // onlyOnOtherThreads = true: only call listeners on other threads
+    // onlyOnOtherThreads = false: call all listeners
+    private void dispatchDestroyedListeners(String name, int type, boolean onlyOnOtherThreads) {
         if (VDBG) Log.d(TAG, "dispatchDestroyedListeners: iface(name)=" + name);
 
+        List<InterfaceDestroyedListenerProxy> triggerList = new ArrayList<>();
         synchronized (mLock) {
             InterfaceCacheEntry entry = mInterfaceInfoCache.get(Pair.create(name, type));
             if (entry == null) {
@@ -2418,11 +2427,22 @@
                 return;
             }
 
-            for (InterfaceDestroyedListenerProxy listener : entry.destroyedListeners) {
-                listener.trigger();
+            Iterator<InterfaceDestroyedListenerProxy> iterator =
+                    entry.destroyedListeners.iterator();
+            while (iterator.hasNext()) {
+                InterfaceDestroyedListenerProxy listener = iterator.next();
+                if (!onlyOnOtherThreads || !listener.requestedToRunInCurrentThread()) {
+                    triggerList.add(listener);
+                    iterator.remove();
+                }
             }
-            entry.destroyedListeners.clear(); // for insurance (though cache entry is removed)
-            mInterfaceInfoCache.remove(Pair.create(name, type));
+            if (!onlyOnOtherThreads) { // leave entry until final call to *all* callbacks
+                mInterfaceInfoCache.remove(Pair.create(name, type));
+            }
+        }
+
+        for (InterfaceDestroyedListenerProxy listener : triggerList) {
+            listener.trigger();
         }
     }
 
@@ -2462,44 +2482,34 @@
             return mListener.hashCode();
         }
 
-        void trigger() {
-            if (mHandler != null) {
-                // TODO(b/199792691): The thread check is needed to preserve the existing
-                //  assumptions of synchronous execution of the "onDestroyed" callback as much as
-                //  possible. This is needed to prevent regressions caused by posting to the handler
-                //  thread changing the code execution order.
-                //  When all wifi services (ie. WifiAware, WifiP2p) get moved to the wifi handler
-                //  thread, remove this thread check and the Handler#post() and simply always
-                //  invoke the callback directly.
-                long currentTid = mWifiInjector.getCurrentThreadId();
-                long handlerTid = mHandler.getLooper().getThread().getId();
-                if (currentTid == handlerTid) {
-                    // Already running on the same handler thread. Trigger listener synchronously.
-                    action();
-                } else {
-                    // Current thread is not the thread the listener should be invoked on.
-                    // Post action to the intended thread.
-                    mHandler.post(() -> {
-                        action();
-                    });
-                }
-            } else {
-                action();
-            }
+        public boolean requestedToRunInCurrentThread() {
+            if (mHandler == null) return true;
+            long currentTid = mWifiInjector.getCurrentThreadId();
+            long handlerTid = mHandler.getLooper().getThread().getId();
+            return currentTid == handlerTid;
         }
 
-        void triggerWithArg(boolean arg) {
-            if (mHandler != null) {
-                mHandler.post(() -> {
-                    actionWithArg(arg);
-                });
+        void trigger() {
+            // TODO(b/199792691): The thread check is needed to preserve the existing
+            //  assumptions of synchronous execution of the "onDestroyed" callback as much as
+            //  possible. This is needed to prevent regressions caused by posting to the handler
+            //  thread changing the code execution order.
+            //  When all wifi services (ie. WifiAware, WifiP2p) get moved to the wifi handler
+            //  thread, remove this thread check and the Handler#post() and simply always
+            //  invoke the callback directly.
+            if (requestedToRunInCurrentThread()) {
+                // Already running on the same handler thread. Trigger listener synchronously.
+                action();
             } else {
-                actionWithArg(arg);
+                // Current thread is not the thread the listener should be invoked on.
+                // Post action to the intended thread.
+                mHandler.postAtFrontOfQueue(() -> {
+                    action();
+                });
             }
         }
 
         protected void action() {}
-        protected void actionWithArg(boolean arg) {}
 
         ListenerProxy(LISTENER listener, Handler handler, String tag) {
             mListener = listener;
diff --git a/service/java/com/android/server/wifi/ScanRequestProxy.java b/service/java/com/android/server/wifi/ScanRequestProxy.java
index 0d835ec..d047b40 100644
--- a/service/java/com/android/server/wifi/ScanRequestProxy.java
+++ b/service/java/com/android/server/wifi/ScanRequestProxy.java
@@ -607,6 +607,13 @@
                 && !ScanResultUtil.isScanResultForPskNetwork(r));
     }
 
+    /** Indicate whether there are WPA2/WPA3 transition mode networks. */
+    public boolean isWpa2Wpa3PersonalTransitionNetworkInRange(String ssid) {
+        return mLastScanResultsMap.values().stream().anyMatch(r ->
+                ssid.equals(ScanResultUtil.createQuotedSSID(r.SSID))
+                && ScanResultUtil.isScanResultForPskSaeTransitionNetwork(r));
+    }
+
     /** Indicate whether there are OPEN only networks. */
     public boolean isOpenOnlyNetworkInRange(String ssid) {
         return mLastScanResultsMap.values().stream().anyMatch(r ->
diff --git a/service/java/com/android/server/wifi/SoftApManager.java b/service/java/com/android/server/wifi/SoftApManager.java
index e648923..6bd81be 100644
--- a/service/java/com/android/server/wifi/SoftApManager.java
+++ b/service/java/com/android/server/wifi/SoftApManager.java
@@ -860,7 +860,9 @@
                             int newSingleApBand = 0;
                             final List<ClientModeManager> cmms =
                                     mActiveModeWarden.getClientModeManagers();
-                            if (cmms.size() != 0) {
+                            // Checking STA status only when device supports STA + AP concurrency
+                            // since STA would be dropped when device doesn't support it.
+                            if (cmms.size() != 0 && mWifiNative.isStaApConcurrencySupported()) {
                                 if (ApConfigUtil.isStaWithBridgedModeSupported(mContext)) {
                                     for (ClientModeManager cmm
                                             : mActiveModeWarden.getClientModeManagers()) {
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index bbc09a1..32baa8e 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -3774,4 +3774,22 @@
         }
         internalConfig.enableFils(isFilsSha256Supported, isFilsSha384Supported);
     }
+
+    /**
+     * This method updates auto-upgrade flag to the internal network.
+     *
+     * @param networkId networkId corresponding to the network to be updated.
+     * @param securityType the target security type
+     * @param isAddedByAutoUpgrade indicate whether the target security type is added
+     *        by auto-upgrade or not.
+     */
+    public void updateIsAddedByAutoUpgradeFlag(int networkId,
+            int securityType, boolean isAddedByAutoUpgrade) {
+        WifiConfiguration internalConfig = getInternalConfiguredNetwork(networkId);
+        if (internalConfig == null) {
+            return;
+        }
+        internalConfig.setSecurityParamsIsAddedByAutoUpgrade(securityType, isAddedByAutoUpgrade);
+        saveToStore(true);
+    }
 }
diff --git a/service/java/com/android/server/wifi/WifiConfigurationUtil.java b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
index 5419298..20625a1 100644
--- a/service/java/com/android/server/wifi/WifiConfigurationUtil.java
+++ b/service/java/com/android/server/wifi/WifiConfigurationUtil.java
@@ -16,9 +16,6 @@
 
 package com.android.server.wifi;
 
-import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
-import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP;
-import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
 import static android.net.wifi.WifiManager.ALL_ZEROS_MAC_ADDRESS;
 
 import static com.android.server.wifi.util.NativeUtil.addEnclosingQuotes;
@@ -30,7 +27,6 @@
 import android.net.wifi.SecurityParams;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiEnterpriseConfig;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkSpecifier;
 import android.net.wifi.WifiScanner;
@@ -84,9 +80,6 @@
     private static final Pair<MacAddress, MacAddress> MATCH_ALL_BSSID_PATTERN =
             new Pair<>(ALL_ZEROS_MAC_ADDRESS, ALL_ZEROS_MAC_ADDRESS);
 
-    private static final int NETWORK_ID_SECURITY_MASK = 0xff;
-    private static final int NETWORK_ID_SECURITY_OFFSET = 23;
-
     /**
      * Checks if the provided |wepKeys| array contains any non-null value;
      */
@@ -1062,7 +1055,10 @@
     /**
      * Convert multi-type configurations to a list of configurations with a single security type,
      * where a configuration with multiple security configurations will be converted to multiple
-     * Wi-Fi configurations with a single security type..
+     * Wi-Fi configurations with a single security type.
+     * For R or older releases, Settings/WifiTrackerLib does not handle multiple configurations
+     * with the same SSID and will result in duplicate saved networks. As a result, just return
+     * the merged configs directly.
      *
      * @param configs the list of multi-type configurations.
      * @return a list of Wi-Fi configurations with a single security type,
@@ -1070,120 +1066,22 @@
      */
     public static List<WifiConfiguration> convertMultiTypeConfigsToLegacyConfigs(
             List<WifiConfiguration> configs) {
+        if (!SdkLevel.isAtLeastS()) {
+            return configs;
+        }
         List<WifiConfiguration> legacyConfigs = new ArrayList<>();
         for (WifiConfiguration config : configs) {
-            boolean wpa2EnterpriseAdded = false;
-            WifiConfiguration wpa3EnterpriseConfig = null;
             for (SecurityParams params: config.getSecurityParamsList()) {
                 if (!params.isEnabled()) continue;
                 if (shouldOmitAutoUpgradeParams(params)) continue;
                 WifiConfiguration legacyConfig = new WifiConfiguration(config);
                 legacyConfig.setSecurityParams(params);
-                legacyConfig.networkId = addSecurityTypeToNetworkId(
-                        legacyConfig.networkId,
-                        params.getSecurityType());
-                int securityType = params.getSecurityType();
-                if (securityType == SECURITY_TYPE_EAP) {
-                    wpa2EnterpriseAdded = true;
-                } else if (securityType == SECURITY_TYPE_EAP_WPA3_ENTERPRISE) {
-                    wpa3EnterpriseConfig = legacyConfig;
-                    continue;
-                }
                 legacyConfigs.add(legacyConfig);
             }
-            if (wpa3EnterpriseConfig != null && (SdkLevel.isAtLeastS() || !wpa2EnterpriseAdded)) {
-                // R Wifi settings maps WPA3-Enterprise to the same security type as
-                // WPA2-Enterprise, which causes a DuplicateKeyException. For R, we should only
-                // return the WPA2-Enterprise config if we have both.
-                legacyConfigs.add(wpa3EnterpriseConfig);
-            }
         }
         return legacyConfigs;
     }
 
-    /**
-     * Converts WifiInfo.SecurityType to WifiConfiguration.SecurityType
-     */
-    public static
-            @WifiConfiguration.SecurityType int convertWifiInfoSecurityTypeToWifiConfiguration(
-                    @WifiInfo.SecurityType int securityType) {
-        switch (securityType) {
-            case WifiInfo.SECURITY_TYPE_OPEN:
-                return WifiConfiguration.SECURITY_TYPE_OPEN;
-            case WifiInfo.SECURITY_TYPE_WEP:
-                return WifiConfiguration.SECURITY_TYPE_WEP;
-            case WifiInfo.SECURITY_TYPE_PSK:
-                return WifiConfiguration.SECURITY_TYPE_PSK;
-            case WifiInfo.SECURITY_TYPE_EAP:
-                return WifiConfiguration.SECURITY_TYPE_EAP;
-            case WifiInfo.SECURITY_TYPE_SAE:
-                return WifiConfiguration.SECURITY_TYPE_SAE;
-            case WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT:
-                return WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT;
-            case WifiInfo.SECURITY_TYPE_OWE:
-                return WifiConfiguration.SECURITY_TYPE_OWE;
-            case WifiInfo.SECURITY_TYPE_WAPI_PSK:
-                return WifiConfiguration.SECURITY_TYPE_WAPI_PSK;
-            case WifiInfo.SECURITY_TYPE_WAPI_CERT:
-                return WifiConfiguration.SECURITY_TYPE_WAPI_CERT;
-            case WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE:
-                return WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE;
-            case WifiInfo.SECURITY_TYPE_OSEN:
-                return WifiConfiguration.SECURITY_TYPE_OSEN;
-            case WifiInfo.SECURITY_TYPE_PASSPOINT_R1_R2:
-                return WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2;
-            case WifiInfo.SECURITY_TYPE_PASSPOINT_R3:
-                return WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3;
-            default:
-                return -1;
-        }
-    }
-
-    /**
-     * Adds a WifiConfiguration.SecurityType value to a network ID to differentiate the network IDs
-     * of legacy single-type configurations derived from the same multi-type configuration.
-     *
-     * This method only works for SDK levels less than S, since those callers may expect a unique
-     * network ID for each single-type configuration. For SDK level S and above, this method returns
-     * the network ID as-is.
-     *
-     * @param netId network id to add the security type to
-     * @param securityType WifiConfiguration security type to encode
-     * @return network id with security type encoded in it
-     */
-    public static int addSecurityTypeToNetworkId(
-            int netId, @WifiConfiguration.SecurityType int securityType) {
-        // Do not add Passpoint security types since R WifiTrackerLib will map both R1/R2 and R3 to
-        // EAP, which means one of the configs will clobber the other when WifiTrackerLib caches
-        // them by SSID + security type. This may cause a mismatch between a WifiInfo with an
-        // R1/R2-encoded networkId and a cached WifiConfiguration with an R3-encoded networkId,
-        // resulting in a connected Passpoint network not showing in the Wifi picker.
-        if (netId == INVALID_NETWORK_ID || SdkLevel.isAtLeastS()
-                || securityType == WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2
-                || securityType == WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3) {
-            return netId;
-        }
-        return removeSecurityTypeFromNetworkId(netId)
-                | ((securityType & NETWORK_ID_SECURITY_MASK) << NETWORK_ID_SECURITY_OFFSET);
-    }
-
-    /**
-     * Removes the security type value of a network ID to have it match with internal network IDs.
-     *
-     * This method only works for SDK levels less than S. It should be used on network ID passed in
-     * from external callers, since those callers are be exposed to network IDs with an embedded
-     * security type value. For SDK levels S and above, this method returns the network ID as-is.
-     *
-     * @param netId network id to remove the security type from
-     * @return network id with the security type removed
-     */
-    public static int removeSecurityTypeFromNetworkId(int netId) {
-        if (netId == INVALID_NETWORK_ID || SdkLevel.isAtLeastS()) {
-            return netId;
-        }
-        return netId & ~(NETWORK_ID_SECURITY_MASK << NETWORK_ID_SECURITY_OFFSET);
-    }
-
     private static boolean validateEnterpriseConfig(WifiConfiguration config, boolean isAdd) {
         if ((config.isSecurityType(WifiConfiguration.SECURITY_TYPE_EAP)
                 || config.isSecurityType(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE))
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 420e9d8..a609053 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -2354,6 +2354,14 @@
         }
     }
 
+    /**
+     * Clear all cached candidates.
+     */
+    public void clearCachedCandidates() {
+        mLatestCandidates = null;
+        mLatestCandidatesTimestampMs = 0;
+    }
+
     // Enable auto-join if WifiConnectivityManager is enabled & we have any pending generic network
     // request (trusted or untrusted) and no specific network request in progress.
     private void checkAllStatesAndEnableAutoJoin() {
diff --git a/service/java/com/android/server/wifi/WifiContext.java b/service/java/com/android/server/wifi/WifiContext.java
index ca06301..cac0bdc 100644
--- a/service/java/com/android/server/wifi/WifiContext.java
+++ b/service/java/com/android/server/wifi/WifiContext.java
@@ -146,4 +146,14 @@
     public String getServiceWifiPackageName() {
         return SERVICE_WIFI_PACKAGE_NAME;
     }
+
+    /**
+     * Reset the resource cache which will cause it to be reloaded next time it is accessed.
+     */
+    public void resetResourceCache() {
+        mWifiOverlayApkPkgName = null;
+        mWifiAssetsFromApk = null;
+        mWifiResourcesFromApk = null;
+        mWifiThemeFromApk = null;
+    }
 }
diff --git a/service/java/com/android/server/wifi/WifiGlobals.java b/service/java/com/android/server/wifi/WifiGlobals.java
index b1c699e..a503b68 100644
--- a/service/java/com/android/server/wifi/WifiGlobals.java
+++ b/service/java/com/android/server/wifi/WifiGlobals.java
@@ -18,6 +18,7 @@
 
 import android.content.Context;
 
+import com.android.modules.utils.build.SdkLevel;
 import com.android.wifi.resources.R;
 
 import java.io.FileDescriptor;
@@ -61,9 +62,12 @@
     private final int mP2pDeviceNamePostfixNumDigits;
     // This is read from the overlay, cache it after boot up.
     private final int mClientModeImplNumLogRecs;
+    private final int mWifiLowConnectedScoreThresholdToTriggerScanForMbb;
+    private final int mWifiLowConnectedScoreScanPeriodSeconds;
 
     // This is set by WifiManager#setVerboseLoggingEnabled(int).
     private boolean mIsShowKeyVerboseLoggingModeEnabled = false;
+    private boolean mIsUsingExternalScorer = false;
 
     public WifiGlobals(Context context) {
         mContext = context;
@@ -84,6 +88,10 @@
                 .getInteger(R.integer.config_wifiP2pDeviceNamePostfixNumDigits);
         mClientModeImplNumLogRecs = mContext.getResources()
                 .getInteger(R.integer.config_wifiClientModeImplNumLogRecs);
+        mWifiLowConnectedScoreThresholdToTriggerScanForMbb = mContext.getResources().getInteger(
+                R.integer.config_wifiLowConnectedScoreThresholdToTriggerScanForMbb);
+        mWifiLowConnectedScoreScanPeriodSeconds = mContext.getResources().getInteger(
+                R.integer.config_wifiLowConnectedScoreScanPeriodSeconds);
     }
 
     /** Get the interval between RSSI polls, in milliseconds. */
@@ -169,7 +177,8 @@
      * @return boolean true if auto-upgrade is enabled, false otherwise.
      */
     public boolean isOweUpgradeEnabled() {
-        return mIsOweUpgradeEnabled;
+        // OWE auto-upgrade is supported on S or newer releases.
+        return SdkLevel.isAtLeastS() && mIsOweUpgradeEnabled;
     }
 
     /**
@@ -200,6 +209,16 @@
         return mIsShowKeyVerboseLoggingModeEnabled;
     }
 
+    /** Set whether the external scorer is being used **/
+    public void setUsingExternalScorer(boolean isUsingExternalScorer) {
+        mIsUsingExternalScorer = isUsingExternalScorer;
+    }
+
+    /** Get whether the external scorer is being used **/
+    public boolean isUsingExternalScorer() {
+        return mIsUsingExternalScorer;
+    }
+
     /** Get the prefix of the default wifi p2p device name. */
     public String getWifiP2pDeviceNamePrefix() {
         return mP2pDeviceNamePrefix;
@@ -215,6 +234,16 @@
         return mClientModeImplNumLogRecs;
     }
 
+    /** Get the low score threshold to do scan for MBB when external scorer is not used. **/
+    public int getWifiLowConnectedScoreThresholdToTriggerScanForMbb() {
+        return mWifiLowConnectedScoreThresholdToTriggerScanForMbb;
+    }
+
+    /** Get the minimum period between the extra scans triggered for MBB when score is low **/
+    public int getWifiLowConnectedScoreScanPeriodSeconds() {
+        return mWifiLowConnectedScoreScanPeriodSeconds;
+    }
+
     /** Dump method for debugging */
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.println("Dump of WifiGlobals");
@@ -229,5 +258,11 @@
         pw.println("mP2pDeviceNamePrefix=" + mP2pDeviceNamePrefix);
         pw.println("mP2pDeviceNamePostfixNumDigits=" + mP2pDeviceNamePostfixNumDigits);
         pw.println("mClientModeImplNumLogRecs=" + mClientModeImplNumLogRecs);
+        pw.println("mWifiLowConnectedScoreThresholdToTriggerScanForMbb="
+                + mWifiLowConnectedScoreThresholdToTriggerScanForMbb);
+        pw.println("mWifiLowConnectedScoreScanPeriodSeconds="
+                + mWifiLowConnectedScoreScanPeriodSeconds);
+        pw.println("mIsUsingExternalScorer="
+                + mIsUsingExternalScorer);
     }
 }
diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java
index efbe219..63f194f 100644
--- a/service/java/com/android/server/wifi/WifiInjector.java
+++ b/service/java/com/android/server/wifi/WifiInjector.java
@@ -754,7 +754,8 @@
                 new WifiScoreReport(mScoringParams, mClock, mWifiMetrics, wifiInfo,
                         mWifiNative, mWifiBlocklistMonitor, mWifiThreadRunner, mWifiScoreCard,
                         mDeviceConfigFacade, mContext, mAdaptiveConnectivityEnabledSettingObserver,
-                        ifaceName, mExternalScoreUpdateObserverProxy, mSettingsStore),
+                        ifaceName, mExternalScoreUpdateObserverProxy, mSettingsStore, mWifiGlobals,
+                        mActiveModeWarden, mWifiConnectivityManager),
                 mWifiP2pConnection, mWifiGlobals, ifaceName, clientModeManager,
                 mCmiMonitor, mBroadcastQueue, mWifiNetworkSelector, makeTelephonyManager(),
                 this, mSettingsConfigStore, verboseLoggingEnabled);
diff --git a/service/java/com/android/server/wifi/WifiNative.java b/service/java/com/android/server/wifi/WifiNative.java
index b07101c..33746bc 100644
--- a/service/java/com/android/server/wifi/WifiNative.java
+++ b/service/java/com/android/server/wifi/WifiNative.java
@@ -133,6 +133,7 @@
         mSupplicantStaIfaceHal.enableVerboseLogging(mVerboseLoggingEnabled);
         mHostapdHal.enableVerboseLogging(mVerboseLoggingEnabled);
         mWifiVendorHal.enableVerboseLogging(mVerboseLoggingEnabled);
+        mIfaceMgr.enableVerboseLogging(mVerboseLoggingEnabled);
     }
 
     /**
@@ -300,9 +301,17 @@
         private int mNextId;
         /** Map of the id to the iface structure */
         private HashMap<Integer, Iface> mIfaces = new HashMap<>();
+        private boolean mVerboseLoggingEnabled = false;
+
+        public void enableVerboseLogging(boolean enable) {
+            mVerboseLoggingEnabled = enable;
+        }
 
         /** Allocate a new iface for the given type */
-        private Iface allocateIface(@Iface.IfaceType  int type) {
+        private Iface allocateIface(@Iface.IfaceType int type) {
+            if (mVerboseLoggingEnabled) {
+                Log.d(TAG, "IfaceManager#allocateIface: type=" + type + ", pre-map=" + mIfaces);
+            }
             Iface iface = new Iface(mNextId, type);
             mIfaces.put(mNextId, iface);
             mNextId++;
@@ -311,6 +320,9 @@
 
         /** Remove the iface using the provided id */
         private Iface removeIface(int id) {
+            if (mVerboseLoggingEnabled) {
+                Log.d(TAG, "IfaceManager#removeIface: id=" + id + ", pre-map=" + mIfaces);
+            }
             return mIfaces.remove(id);
         }
 
@@ -387,6 +399,10 @@
 
         /** Removes the existing iface that does not match the provided id. */
         public Iface removeExistingIface(int newIfaceId) {
+            if (mVerboseLoggingEnabled) {
+                Log.d(TAG, "IfaceManager#removeExistingIface: newIfaceId=" + newIfaceId
+                        + ", pre-map=" + mIfaces);
+            }
             Iface removedIface = null;
             // The number of ifaces in the database could be 1 existing & 1 new at the max.
             if (mIfaces.size() > 2) {
@@ -402,6 +418,11 @@
             }
             return removedIface;
         }
+
+        @Override
+        public String toString() {
+            return mIfaces.toString();
+        }
     }
 
     private class NormalScanEventCallback implements WifiNl80211Manager.ScanEventCallback {
@@ -829,6 +850,11 @@
             // This is invoked from the main system_server thread. Post to our handler.
             mHandler.post(() -> {
                 synchronized (mLock) {
+                    if (mVerboseLoggingEnabled) {
+                        Log.d(TAG, "interfaceLinkStateChanged: ifaceName=" + ifaceName
+                                + ", mInterfaceId = " + mInterfaceId
+                                + ", mIfaceMgr=" + mIfaceMgr.toString());
+                    }
                     final Iface ifaceWithId = mIfaceMgr.getIface(mInterfaceId);
                     if (ifaceWithId == null) {
                         if (mVerboseLoggingEnabled) {
@@ -1073,7 +1099,9 @@
      * @param listener StatusListener listener object.
      */
     public void registerStatusListener(@NonNull StatusListener listener) {
-        mStatusListeners.add(listener);
+        synchronized (mLock) {
+            mStatusListeners.add(listener);
+        }
     }
 
     /**
diff --git a/service/java/com/android/server/wifi/WifiNetworkSelector.java b/service/java/com/android/server/wifi/WifiNetworkSelector.java
index 5bf608e..f1debca 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSelector.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSelector.java
@@ -283,6 +283,14 @@
             return false;
         }
 
+        // External scorer is not being used, and the current network's score is below the
+        // sufficient score threshold configured for the AOSP scorer.
+        if (!mWifiGlobals.isUsingExternalScorer()
+                && wifiInfo.getScore()
+                < mWifiGlobals.getWifiLowConnectedScoreThresholdToTriggerScanForMbb()) {
+            return false;
+        }
+
         // OEM paid/private networks are only available to system apps, so this is never sufficient.
         if (network.oemPaid || network.oemPrivate) {
             localLog("Current network is oem paid/private");
@@ -1017,6 +1025,33 @@
     }
 
     /**
+     * Update the candidate security params against a scan detail.
+     *
+     * @param network the target network.
+     * @param scanDetail the target scan detail.
+     */
+    public void updateNetworkCandidateSecurityParams(
+            WifiConfiguration network, ScanDetail scanDetail) {
+        if (network == null) return;
+        if (scanDetail == null) return;
+
+        ScanResult scanResult = scanDetail.getScanResult();
+        List<SecurityParams> scanResultParamsList = ScanResultUtil
+                .generateSecurityParamsListFromScanResult(scanResult);
+        if (scanResultParamsList == null) return;
+        // Under some conditions, the legacy type is preferred to have better
+        // connectivity behaviors, and the auto-upgrade type should be removed.
+        removeSecurityParamsIfNecessary(network, scanResultParamsList);
+        SecurityParams params = ScanResultMatchInfo.getBestMatchingSecurityParams(
+                network,
+                scanResultParamsList);
+        if (params == null) return;
+        updateSecurityParamsForTransitionModeIfNecessary(scanResult, params);
+        mWifiConfigManager.setNetworkCandidateScanResult(
+                network.networkId, scanResult, 0, params);
+    }
+
+    /**
      * Using the registered Scorers, choose the best network from the list of Candidate(s).
      * The ScanDetailCache is also updated here.
      * @param candidates - Candidates to perferm network selection on.
@@ -1041,19 +1076,7 @@
             WifiConfiguration config = mWifiConfigManager
                     .getConfiguredNetwork(choice.candidateKey.networkId);
             if (config == null) continue;
-            List<SecurityParams> scanResultParamsList = ScanResultUtil
-                    .generateSecurityParamsListFromScanResult(scanDetail.getScanResult());
-            if (scanResultParamsList == null) continue;
-            // Under some conditions, the legacy type is preferred to have better
-            // connectivity behaviors, and the auto-upgrade type should be removed.
-            removeSecurityParamsIfNecessary(config, scanResultParamsList);
-            SecurityParams params = ScanResultMatchInfo.getBestMatchingSecurityParams(
-                    config,
-                    scanResultParamsList);
-            if (params == null) continue;
-            updateSecurityParamsForTransitionModeIfNecessary(scanDetail.getScanResult(), params);
-            mWifiConfigManager.setNetworkCandidateScanResult(choice.candidateKey.networkId,
-                    scanDetail.getScanResult(), 0, params);
+            updateNetworkCandidateSecurityParams(config, scanDetail);
         }
 
         for (Collection<WifiCandidates.Candidate> group : groupedCandidates) {
@@ -1319,17 +1342,7 @@
         for (ScanDetail scanDetail : scanDetails) {
             WifiConfiguration network =
                     mWifiConfigManager.getSavedNetworkForScanDetail(scanDetail);
-            if (network == null || network.getSecurityParamsList().size() < 2) continue;
-
-            List<SecurityParams> scanResultParamsList = ScanResultUtil
-                    .generateSecurityParamsListFromScanResult(scanDetail.getScanResult());
-            if (scanResultParamsList == null) continue;
-
-            SecurityParams params = ScanResultMatchInfo.getBestMatchingSecurityParams(network,
-                    scanResultParamsList);
-            if (params == null) continue;
-
-            network.getNetworkSelectionStatus().setCandidateSecurityParams(params);
+            updateNetworkCandidateSecurityParams(network, scanDetail);
         }
     }
 }
diff --git a/service/java/com/android/server/wifi/WifiScoreReport.java b/service/java/com/android/server/wifi/WifiScoreReport.java
index c68c6c1..d9a3aff 100644
--- a/service/java/com/android/server/wifi/WifiScoreReport.java
+++ b/service/java/com/android/server/wifi/WifiScoreReport.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wifi;
 
+import static com.android.server.wifi.ClientModeImpl.WIFI_WORK_SOURCE;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.net.Network;
@@ -115,6 +117,10 @@
     private final DeviceConfigFacade mDeviceConfigFacade;
     private final ExternalScoreUpdateObserverProxy mExternalScoreUpdateObserverProxy;
     private final WifiInfo mWifiInfoNoReset;
+    private final WifiGlobals mWifiGlobals;
+    private final ActiveModeWarden mActiveModeWarden;
+    private final WifiConnectivityManager mWifiConnectivityManager;
+    private long mLastLowScoreScanTimestampMs = -1;
 
     /**
      * Callback from {@link ExternalScoreUpdateObserverProxy}
@@ -500,7 +506,10 @@
             AdaptiveConnectivityEnabledSettingObserver adaptiveConnectivityEnabledSettingObserver,
             String interfaceName,
             ExternalScoreUpdateObserverProxy externalScoreUpdateObserverProxy,
-            WifiSettingsStore wifiSettingsStore) {
+            WifiSettingsStore wifiSettingsStore,
+            WifiGlobals wifiGlobals,
+            ActiveModeWarden activeModeWarden,
+            WifiConnectivityManager wifiConnectivityManager) {
         mScoringParams = scoringParams;
         mClock = clock;
         mAdaptiveConnectivityEnabledSettingObserver = adaptiveConnectivityEnabledSettingObserver;
@@ -518,6 +527,9 @@
         mExternalScoreUpdateObserverProxy = externalScoreUpdateObserverProxy;
         mWifiSettingsStore = wifiSettingsStore;
         mWifiInfoNoReset = new WifiInfo(mWifiInfo);
+        mWifiGlobals = wifiGlobals;
+        mActiveModeWarden = activeModeWarden;
+        mWifiConnectivityManager = wifiConnectivityManager;
     }
 
     /**
@@ -535,6 +547,7 @@
         mLastDownwardBreachTimeMillis = 0;
         mLastScoreBreachLowTimeMillis = INVALID_WALL_CLOCK_MILLIS;
         mLastScoreBreachHighTimeMillis = INVALID_WALL_CLOCK_MILLIS;
+        mLastLowScoreScanTimestampMs = -1;
         if (mVerboseLoggingEnabled) Log.d(TAG, "reset");
     }
 
@@ -615,12 +628,25 @@
             score = 0;
         }
 
+        if (score < mWifiGlobals.getWifiLowConnectedScoreThresholdToTriggerScanForMbb()
+                && enoughTimePassedSinceLastLowConnectedScoreScan()
+                && mActiveModeWarden.canRequestSecondaryTransientClientModeManager()) {
+            mLastLowScoreScanTimestampMs = mClock.getElapsedSinceBootMillis();
+            mWifiConnectivityManager.forceConnectivityScan(WIFI_WORK_SOURCE);
+        }
+
         // report score
         mLegacyIntScore = score;
         reportNetworkScoreToConnectivityServiceIfNecessary();
         updateWifiMetrics(millis, s2);
     }
 
+    private boolean enoughTimePassedSinceLastLowConnectedScoreScan() {
+        return mLastLowScoreScanTimestampMs == -1
+                || mClock.getElapsedSinceBootMillis() - mLastLowScoreScanTimestampMs
+                > (mWifiGlobals.getWifiLowConnectedScoreScanPeriodSeconds() * 1000);
+    }
+
     private int getCurrentNetId() {
         int netId = 0;
         if (mNetworkAgent != null) {
@@ -851,6 +877,7 @@
             return false;
         }
         mWifiConnectedNetworkScorerHolder = scorerHolder;
+        mWifiGlobals.setUsingExternalScorer(true);
 
         // Register to receive updates from external scorer.
         mExternalScoreUpdateObserverProxy.registerCallback(mScoreUpdateObserverCallback);
@@ -1017,6 +1044,7 @@
         Log.d(TAG, "Using VelocityBasedConnectedScore");
         mVelocityBasedConnectedScore = new VelocityBasedConnectedScore(mScoringParams, mClock);
         mWifiConnectedNetworkScorerHolder = null;
+        mWifiGlobals.setUsingExternalScorer(false);
         mExternalScoreUpdateObserverProxy.unregisterCallback(mScoreUpdateObserverCallback);
         mWifiMetrics.setIsExternalWifiScorerOn(false);
     }
diff --git a/service/java/com/android/server/wifi/WifiServiceImpl.java b/service/java/com/android/server/wifi/WifiServiceImpl.java
index 2fba0de..81db677 100644
--- a/service/java/com/android/server/wifi/WifiServiceImpl.java
+++ b/service/java/com/android/server/wifi/WifiServiceImpl.java
@@ -33,9 +33,6 @@
 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_SIM_INSERTED;
 import static com.android.server.wifi.ClientModeImpl.RESET_SIM_REASON_SIM_REMOVED;
 import static com.android.server.wifi.SelfRecovery.REASON_API_CALL;
-import static com.android.server.wifi.WifiConfigurationUtil.addSecurityTypeToNetworkId;
-import static com.android.server.wifi.WifiConfigurationUtil.convertWifiInfoSecurityTypeToWifiConfiguration;
-import static com.android.server.wifi.WifiConfigurationUtil.removeSecurityTypeFromNetworkId;
 import static com.android.server.wifi.WifiSettingsConfigStore.WIFI_VERBOSE_LOGGING_ENABLED;
 
 import android.Manifest;
@@ -188,7 +185,7 @@
     private final ActiveModeWarden mActiveModeWarden;
     private final ScanRequestProxy mScanRequestProxy;
 
-    private final Context mContext;
+    private final WifiContext mContext;
     private final FrameworkFacade mFacade;
     private final Clock mClock;
 
@@ -319,7 +316,7 @@
     }
 
 
-    public WifiServiceImpl(Context context, WifiInjector wifiInjector) {
+    public WifiServiceImpl(WifiContext context, WifiInjector wifiInjector) {
         mContext = context;
         mWifiInjector = wifiInjector;
         mClock = wifiInjector.getClock();
@@ -2721,9 +2718,6 @@
             throw new SecurityException("Caller is not a device owner, profile owner, system app,"
                     + " or privileged app");
         }
-        if (config != null) {
-            config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
-        }
         return addOrUpdateNetworkInternal(config, packageName, uid);
     }
 
@@ -2744,9 +2738,6 @@
                     .c(Binder.getCallingUid()).flush();
             return -1;
         }
-        if (config != null) {
-            config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
-        }
         mLog.info("addOrUpdateNetwork uid=%").c(Binder.getCallingUid()).flush();
         return addOrUpdateNetworkInternal(config, packageName, callingUid).networkId;
     }
@@ -2815,8 +2806,7 @@
                         .getNetworkId(),
                 WifiConfiguration.INVALID_NETWORK_ID);
         if (networkId >= 0) {
-            return new AddNetworkResult(AddNetworkResult.STATUS_SUCCESS, addSecurityTypeToNetworkId(
-                    networkId, config.getDefaultSecurityParams().getSecurityType()));
+            return new AddNetworkResult(AddNetworkResult.STATUS_SUCCESS, networkId);
         }
         return new AddNetworkResult(
                 AddNetworkResult.STATUS_ADD_WIFI_CONFIG_FAILURE, -1);
@@ -2853,12 +2843,10 @@
                     .c(Binder.getCallingUid()).flush();
             return false;
         }
-        final int internalNetId = removeSecurityTypeFromNetworkId(netId);
         int callingUid = Binder.getCallingUid();
         mLog.info("removeNetwork uid=%").c(callingUid).flush();
         return mWifiThreadRunner.call(
-                () -> mWifiConfigManager.removeNetwork(internalNetId, callingUid, packageName),
-                false);
+                () -> mWifiConfigManager.removeNetwork(netId, callingUid, packageName), false);
     }
 
     @Override
@@ -2930,7 +2918,6 @@
                     .c(Binder.getCallingUid()).flush();
             return false;
         }
-        final int internalNetId = removeSecurityTypeFromNetworkId(netId);
         int callingUid = Binder.getCallingUid();
         // TODO b/33807876 Log netId
         mLog.info("enableNetwork uid=% disableOthers=%")
@@ -2939,11 +2926,10 @@
 
         mWifiMetrics.incrementNumEnableNetworkCalls();
         if (disableOthers) {
-            return triggerConnectAndReturnStatus(internalNetId, callingUid);
+            return triggerConnectAndReturnStatus(netId, callingUid);
         } else {
             return mWifiThreadRunner.call(
-                    () -> mWifiConfigManager.enableNetwork(
-                            internalNetId, false, callingUid, packageName),
+                    () -> mWifiConfigManager.enableNetwork(netId, false, callingUid, packageName),
                     false);
         }
     }
@@ -2965,12 +2951,10 @@
                     .c(Binder.getCallingUid()).flush();
             return false;
         }
-        final int internalNetId = removeSecurityTypeFromNetworkId(netId);
         int callingUid = Binder.getCallingUid();
         mLog.info("disableNetwork uid=%").c(callingUid).flush();
         return mWifiThreadRunner.call(
-                () -> mWifiConfigManager.disableNetwork(
-                        internalNetId, callingUid, packageName), false);
+                () -> mWifiConfigManager.disableNetwork(netId, callingUid, packageName), false);
     }
 
     /**
@@ -2994,6 +2978,11 @@
         mWifiThreadRunner.post(() -> {
             mWifiConfigManager
                     .startRestrictingAutoJoinToSubscriptionId(subscriptionId);
+            // Clear all cached candidates to avoid the imminent disconnect connecting back to a
+            // cached candidate that's likely no longer valid after
+            // startRestrictingAutoJoinToSubscriptionId is called. Let the disconnection trigger
+            // a new scan to ensure proper network selection is done.
+            mWifiConnectivityManager.clearCachedCandidates();
             // always disconnect here and rely on auto-join to find the appropriate carrier network
             // to join. Even if we are currently connected to the carrier-merged wifi, it's still
             // better to disconnect here because it's possible that carrier wifi offload is
@@ -3045,11 +3034,10 @@
     public void allowAutojoin(int netId, boolean choice) {
         enforceNetworkSettingsPermission();
 
-        final int internalNetId = removeSecurityTypeFromNetworkId(netId);
         int callingUid = Binder.getCallingUid();
         mLog.info("allowAutojoin=% uid=%").c(choice).c(callingUid).flush();
         mWifiThreadRunner.post(() -> {
-            WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(internalNetId);
+            WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
             if (config == null) {
                 return;
             }
@@ -3076,13 +3064,13 @@
             // even for Suggestion, modify the current ephemeral configuration so that
             // existing configuration auto-connection is updated correctly
             if (choice != config.allowAutojoin) {
-                mWifiConfigManager.allowAutojoin(internalNetId, choice);
+                mWifiConfigManager.allowAutojoin(netId, choice);
                 // do not log this metrics for passpoint networks again here since it's already
                 // logged in PasspointManager.
                 if (!config.isPasspoint()) {
                     mWifiMetrics.logUserActionEvent(choice
                             ? UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_ON
-                            : UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF, internalNetId);
+                            : UserActionEvent.EVENT_CONFIGURE_AUTO_CONNECT_OFF, netId);
                 }
             }
         });
@@ -3214,11 +3202,7 @@
                     Log.v(TAG, "Keeping REDACT_FOR_ACCESS_FINE_LOCATION:" + ignored);
                 }
             }
-            WifiInfo wifiInfoCopy = wifiInfo.makeCopy(redactions);
-            wifiInfoCopy.setNetworkId(addSecurityTypeToNetworkId(wifiInfoCopy.getNetworkId(),
-                    convertWifiInfoSecurityTypeToWifiConfiguration(
-                            wifiInfoCopy.getCurrentSecurityType())));
-            return wifiInfoCopy;
+            return wifiInfo.makeCopy(redactions);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -4659,9 +4643,7 @@
                         mDppManager.startDppAsConfiguratorInitiator(
                                 uid, packageName,
                                 mActiveModeWarden.getPrimaryClientModeManager().getInterfaceName(),
-                                binder, enrolleeUri,
-                                removeSecurityTypeFromNetworkId(selectedNetworkId), netRole,
-                                callback)));
+                                binder, enrolleeUri, selectedNetworkId, netRole, callback)));
     }
 
     /**
@@ -4932,10 +4914,6 @@
         if (!isPrivileged(Binder.getCallingPid(), uid)) {
             throw new SecurityException(TAG + ": Permission denied");
         }
-        if (config != null) {
-            config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
-        }
-        final int netIdArg = removeSecurityTypeFromNetworkId(netId);
         mLog.info("connect uid=%").c(uid).flush();
         mWifiThreadRunner.post(() -> {
             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
@@ -4955,15 +4933,14 @@
                 broadcastWifiCredentialChanged(WifiManager.WIFI_CREDENTIAL_SAVED, config);
             } else {
                 if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
-                    mWifiMetrics.logUserActionEvent(
-                            UserActionEvent.EVENT_MANUAL_CONNECT, netIdArg);
+                    mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_MANUAL_CONNECT, netId);
                 }
-                result = new NetworkUpdateResult(netIdArg);
+                result = new NetworkUpdateResult(netId);
             }
             WifiConfiguration configuration = mWifiConfigManager
                     .getConfiguredNetwork(result.getNetworkId());
             if (configuration == null) {
-                Log.e(TAG, "connect to Invalid network Id=" + netIdArg);
+                Log.e(TAG, "connect to Invalid network Id=" + netId);
                 wrapper.sendFailure(WifiManager.ERROR);
                 return;
             }
@@ -5027,9 +5004,6 @@
         if (!isPrivileged(Binder.getCallingPid(), uid)) {
             throw new SecurityException(TAG + ": Permission denied");
         }
-        if (config != null) {
-            config.networkId = removeSecurityTypeFromNetworkId(config.networkId);
-        }
         mLog.info("save uid=%").c(uid).flush();
         mWifiThreadRunner.post(() -> {
             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
@@ -5059,16 +5033,15 @@
         if (!isPrivileged(Binder.getCallingPid(), uid)) {
             throw new SecurityException(TAG + ": Permission denied");
         }
-        final int internalNetId = removeSecurityTypeFromNetworkId(netId);
         mLog.info("forget uid=%").c(Binder.getCallingUid()).flush();
         if (mWifiPermissionsUtil.checkNetworkSettingsPermission(uid)) {
             // It's important to log this metric before the actual forget executes because
             // the netId becomes invalid after the forget operation.
-            mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_FORGET_WIFI, internalNetId);
+            mWifiMetrics.logUserActionEvent(UserActionEvent.EVENT_FORGET_WIFI, netId);
         }
         mWifiThreadRunner.post(() -> {
-            WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(internalNetId);
-            boolean success = mWifiConfigManager.removeNetwork(internalNetId, uid, null);
+            WifiConfiguration config = mWifiConfigManager.getConfiguredNetwork(netId);
+            boolean success = mWifiConfigManager.removeNetwork(netId, uid, null);
             ActionListenerWrapper wrapper = new ActionListenerWrapper(callback);
             if (success) {
                 wrapper.sendSuccess();
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index a86cd8f..425269b 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -150,7 +150,7 @@
     private final WifiCountryCode mWifiCountryCode;
     private final WifiLastResortWatchdog mWifiLastResortWatchdog;
     private final WifiServiceImpl mWifiService;
-    private final Context mContext;
+    private final WifiContext mContext;
     private final ConnectivityManager mConnectivityManager;
     private final WifiCarrierInfoManager mWifiCarrierInfoManager;
     private final WifiNetworkFactory mWifiNetworkFactory;
@@ -199,7 +199,7 @@
         }
     }
 
-    WifiShellCommand(WifiInjector wifiInjector, WifiServiceImpl wifiService, Context context,
+    WifiShellCommand(WifiInjector wifiInjector, WifiServiceImpl wifiService, WifiContext context,
             WifiGlobals wifiGlobals, WifiThreadRunner wifiThreadRunner) {
         mWifiGlobals = wifiGlobals;
         mWifiThreadRunner = wifiThreadRunner;
@@ -490,6 +490,10 @@
                     }
                     return 0;
                 }
+                case "reload-resources": {
+                    mContext.resetResourceCache();
+                    return 0;
+                }
                 case "force-country-code": {
                     boolean enabled = getNextArgRequiredTrueOrFalse("enabled", "disabled");
                     if (enabled) {
@@ -1624,6 +1628,10 @@
         pw.println("  pmksa-flush <networkId>");
         pw.println("        - Flush the local PMKSA cache associated with the network id."
                 + " Use list-networks to retrieve <networkId> for the network");
+        pw.println("  reload-resources");
+        pw.println(
+                "    Reset the WiFi resources cache which will cause them to be reloaded next "
+                        + "time they are accessed. Necessary if overlays are manually modified.");
     }
 
     private void onHelpPrivileged(PrintWriter pw) {
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
index f4742ba..fa06e03 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ActiveModeWardenTest.java
@@ -748,6 +748,43 @@
     }
 
     /**
+     * Verify that when there are only secondary CMMs available, the user toggling wifi on will
+     * create a new primary CMM.
+     */
+    @Test
+    public void testToggleWifiWithOnlySecondaryCmmsCreatesPrimaryOrScanOnlyCmm() throws Exception {
+        enterClientModeActiveState();
+        verify(mWifiInjector, times(1)).makeClientModeManager(
+                any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
+
+        // toggling wifi on again should be no-op when primary is already available
+        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
+        mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
+        mLooper.dispatchAll();
+
+        verify(mWifiInjector, times(1)).makeClientModeManager(
+                any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
+
+        // Make the primary CMM change to local only secondary role.
+        when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_LOCAL_ONLY);
+        mClientListener.onRoleChanged(mClientModeManager);
+        mLooper.dispatchAll();
+
+        // Verify that there only exists the ROLE_CLIENT_LOCAL_ONLY CMM.
+        List<ClientModeManager> currentCMMs = mActiveModeWarden.getClientModeManagers();
+        assertEquals(1, currentCMMs.size());
+        assertTrue(currentCMMs.get(0).getRole() == ROLE_CLIENT_LOCAL_ONLY);
+
+        // verify wifi toggling on should recreate the primary CMM
+        when(mSettingsStore.isWifiToggleEnabled()).thenReturn(true);
+        mActiveModeWarden.wifiToggled(TEST_WORKSOURCE);
+        mLooper.dispatchAll();
+
+        verify(mWifiInjector, times(2)).makeClientModeManager(
+                any(), eq(TEST_WORKSOURCE), eq(ROLE_CLIENT_PRIMARY), anyBoolean());
+    }
+
+    /**
      * Reentering EnabledState should be a NOP.
      */
     @Test
diff --git a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index e324f21..fe50b24 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -44,6 +44,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
@@ -96,8 +97,10 @@
 import android.net.NetworkInfo;
 import android.net.NetworkProvider;
 import android.net.NetworkSpecifier;
+import android.net.ProvisioningConfigurationParcelable;
 import android.net.StaticIpConfiguration;
 import android.net.Uri;
+import android.net.apf.ApfCapabilities;
 import android.net.ip.IIpClient;
 import android.net.ip.IpClientCallbacks;
 import android.net.vcn.VcnManager;
@@ -187,7 +190,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
@@ -402,6 +404,7 @@
     static final int      sFreq1 = 5240;
     static final String   WIFI_IFACE_NAME = "mockWlan";
     static final String sFilsSsid = "FILS-AP";
+    static final ApfCapabilities APF_CAP = new ApfCapabilities(1, 2, 3);
 
     ClientModeImpl mCmi;
     HandlerThread mWifiCoreThread;
@@ -485,6 +488,7 @@
             mOffloadDisabledListenerArgumentCaptor = ArgumentCaptor.forClass(
                     WifiCarrierInfoManager.OnCarrierOffloadDisabledListener.class);
     @Captor ArgumentCaptor<BroadcastReceiver> mScreenStateBroadcastReceiverCaptor;
+    @Captor ArgumentCaptor<ProvisioningConfigurationParcelable> mProvisioningConfigurationCaptor;
 
     private void setUpWifiNative() throws Exception {
         when(mWifiNative.getStaFactoryMacAddress(WIFI_IFACE_NAME)).thenReturn(
@@ -509,6 +513,7 @@
                     }
                 });
         when(mWifiNative.connectToNetwork(any(), any())).thenReturn(true);
+        when(mWifiNative.getApfCapabilities(anyString())).thenReturn(APF_CAP);
     }
 
     /** Reset verify() counters on WifiNative, and restore when() mocks on mWifiNative */
@@ -878,20 +883,26 @@
      */
     @Test
     public void triggerConnectWithUpgradeType() throws Exception {
-        WifiConfiguration config = spy(WifiConfigurationTestUtil.createOpenOweNetwork());
+        String ssid = "TestOpenOweSsid";
+        WifiConfiguration config = spy(WifiConfigurationTestUtil.createOpenOweNetwork(
+                ScanResultUtil.createQuotedSSID(ssid)));
         doAnswer(new AnswerWithArguments() {
-            public List<WifiCandidates.Candidate> answer(
-                    List<ScanDetail> scanDetails, Set<String> bssidBlocklist,
-                    List<WifiNetworkSelector.ClientModeManagerState> cmmStates,
-                    boolean untrustedNetworkAllowed,
-                    boolean oemPaidNetworkAllowed, boolean oemPrivateNetworkAllowed) {
+            public void answer(
+                    WifiConfiguration network, ScanDetail scanDetail) {
+                if (!config.SSID.equals(network.SSID)) return;
                 config.getNetworkSelectionStatus().setCandidateSecurityParams(
                         SecurityParams.createSecurityParamsBySecurityType(
                                 WifiConfiguration.SECURITY_TYPE_OWE));
-                return null;
             }
-        }).when(mWifiNetworkSelector).getCandidatesFromScan(any(), any(), any(),
-                anyBoolean(), anyBoolean(), anyBoolean());
+        }).when(mWifiNetworkSelector).updateNetworkCandidateSecurityParams(any(), any());
+        String caps = "[RSN-OWE_TRANSITION]";
+        ScanResult scanResult = new ScanResult(WifiSsid.createFromAsciiEncoded(ssid),
+                ssid, TEST_BSSID_STR, 1245, 0, caps, -78, 2412, 1025, 22, 33, 20, 0, 0, true);
+        ScanResult.InformationElement ie = createIE(ScanResult.InformationElement.EID_SSID,
+                ssid.getBytes(StandardCharsets.UTF_8));
+        scanResult.informationElements = new ScanResult.InformationElement[]{ie};
+        when(mScanRequestProxy.getScanResults()).thenReturn(Arrays.asList(scanResult));
+
         config.networkId = FRAMEWORK_NETWORK_ID;
         config.setRandomizedMacAddress(TEST_LOCAL_MAC_ADDRESS);
         config.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
@@ -6448,6 +6459,9 @@
     public void testPacketFilter() throws Exception {
         connect();
 
+        verify(mIpClient).startProvisioning(mProvisioningConfigurationCaptor.capture());
+        assertEquals(APF_CAP, mProvisioningConfigurationCaptor.getValue().apfCapabilities);
+
         byte[] filter = new byte[20];
         new Random().nextBytes(filter);
         mIpClientCallback.installPacketFilter(filter);
@@ -6463,6 +6477,26 @@
     }
 
     @Test
+    public void testPacketFilterOnSecondarySupported() throws Exception {
+        mResources.setBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta, true);
+        when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
+        connect();
+
+        verify(mIpClient).startProvisioning(mProvisioningConfigurationCaptor.capture());
+        assertEquals(APF_CAP, mProvisioningConfigurationCaptor.getValue().apfCapabilities);
+    }
+
+    @Test
+    public void testPacketFilterOnSecondaryNotSupported() throws Exception {
+        mResources.setBoolean(R.bool.config_wifiEnableApfOnNonPrimarySta, false);
+        when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
+        connect();
+
+        verify(mIpClient).startProvisioning(mProvisioningConfigurationCaptor.capture());
+        assertNull(mProvisioningConfigurationCaptor.getValue().apfCapabilities);
+    }
+
+    @Test
     public void testPacketFilterOnRoleChangeOnSecondaryCmm() throws Exception {
         when(mClientModeManager.getRole()).thenReturn(ROLE_CLIENT_SECONDARY_TRANSIENT);
         connect();
@@ -6743,4 +6777,103 @@
 
         triggerConnect();
     }
+
+    private void verifyUpdateAutoUpgradeFlagForSaeOnR(
+            boolean isWpa3SaeUpgradeEnabled, boolean isWpa2PersonalOnlyNetworkInRange,
+            boolean isWpa2Wpa3PersonalTransitionNetworkInRange,
+            boolean isWpa3PersonalOnlyNetworkInRange, boolean shouldBeUpdated)
+            throws Exception {
+
+        when(mWifiGlobals.isWpa3SaeUpgradeEnabled()).thenReturn(isWpa3SaeUpgradeEnabled);
+        when(mScanRequestProxy.isWpa2PersonalOnlyNetworkInRange(any()))
+                .thenReturn(isWpa2PersonalOnlyNetworkInRange);
+        when(mScanRequestProxy.isWpa2Wpa3PersonalTransitionNetworkInRange(any()))
+                .thenReturn(isWpa2Wpa3PersonalTransitionNetworkInRange);
+        when(mScanRequestProxy.isWpa3PersonalOnlyNetworkInRange(any()))
+                .thenReturn(isWpa3PersonalOnlyNetworkInRange);
+        initializeAndAddNetworkAndVerifySuccess();
+
+        WifiConfiguration config = WifiConfigurationTestUtil.createPskSaeNetwork();
+        config.networkId = TEST_NETWORK_ID;
+        when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID)).thenReturn(config);
+
+        IActionListener connectActionListener = mock(IActionListener.class);
+        mCmi.connectNetwork(
+                new NetworkUpdateResult(TEST_NETWORK_ID),
+                new ActionListenerWrapper(connectActionListener),
+                Process.SYSTEM_UID);
+        mLooper.dispatchAll();
+        verify(connectActionListener).onSuccess();
+        if (shouldBeUpdated) {
+            verify(mWifiConfigManager).updateIsAddedByAutoUpgradeFlag(
+                    eq(TEST_NETWORK_ID), eq(WifiConfiguration.SECURITY_TYPE_SAE),
+                    eq(false));
+        } else {
+            verify(mWifiConfigManager, never()).updateIsAddedByAutoUpgradeFlag(
+                    anyInt(), anyInt(), anyBoolean());
+        }
+    }
+
+    /**
+     * Tests that manual connection to a network (from settings app) updates
+     * the auto upgrade flag for SAE on R.
+     * - SAE auto-upgrade is disabled.
+     * - No WPA2 PSK network
+     * - No WPA2/WPA3 network
+     * - A WPA3-SAE-only network exists.
+     */
+    @Test
+    public void testManualConnectUpdateAutoUpgradeFlagForSaeOnR() throws Exception {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        verifyUpdateAutoUpgradeFlagForSaeOnR(false, false, false, true, true);
+    }
+
+    /**
+     * Tests that manual connection to a network (from settings app) does not update
+     * the auto upgrade flag for SAE on R if auto-upgrade is enabled.
+     */
+    @Test
+    public void testManualConnectNotUpdateAutoUpgradeFlagForSaeOnRWhenAutoUpgradeEnabled()
+            throws Exception {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        verifyUpdateAutoUpgradeFlagForSaeOnR(true, false, false, true, false);
+    }
+
+    /**
+     * Tests that manual connection to a network (from settings app) does not update
+     * the auto upgrade flag for SAE on R if there are psk networks.
+     */
+    @Test
+    public void testManualConnectNotUpdateAutoUpgradeFlagForSaeOnRWithPskNetworks()
+            throws Exception {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        verifyUpdateAutoUpgradeFlagForSaeOnR(false, true, false, true, false);
+    }
+
+    /**
+     * Tests that manual connection to a network (from settings app) does not update
+     * the auto upgrade flag for SAE on R if there are psk/ase networks.
+     */
+    @Test
+    public void testManualConnectNotUpdateAutoUpgradeFlagForSaeOnRWithPskSaeNetworks()
+            throws Exception {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        verifyUpdateAutoUpgradeFlagForSaeOnR(false, false, true, true, false);
+    }
+
+    /**
+     * Tests that manual connection to a network (from settings app) does not update
+     * the auto upgrade flag for SAE on R if there is no WPA3 SAE only network..
+     */
+    @Test
+    public void testManualConnectNotUpdateAutoUpgradeFlagForSaeOnRWithoutSaeOnlyNetworks()
+            throws Exception {
+        assumeFalse(SdkLevel.isAtLeastS());
+
+        verifyUpdateAutoUpgradeFlagForSaeOnR(false, false, true, true, false);
+    }
 }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java
index 0be8888..a2c241b 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/DppManagerTest.java
@@ -581,9 +581,7 @@
 
         dppEventCallback.onSuccessConfigReceived(selectedNetwork);
         mLooper.dispatchAll();
-        verify(mDppCallback).onSuccessConfigReceived(
-                eq(WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                        TEST_NETWORK_ID, WifiConfiguration.SECURITY_TYPE_SAE)));
+        verify(mDppCallback).onSuccessConfigReceived(eq(TEST_NETWORK_ID));
         verify(mDppCallback, never()).onSuccess(anyInt());
         verify(mDppCallback, never()).onFailure(anyInt(), anyString(), anyString(), any());
         verify(mDppMetrics).updateDppEnrolleeInitiatorRequests();
@@ -1139,7 +1137,7 @@
         selectedNetwork.SSID = TEST_SSID;
         selectedNetwork.networkId = TEST_NETWORK_ID;
         selectedNetwork.preSharedKey = TEST_PASSWORD;
-        selectedNetwork.setSecurityParams(WifiConfiguration.SECURITY_TYPE_SAE);
+        selectedNetwork.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.SAE);
 
         // Generate a progress event
         dppEventCallback.onProgress(AUTHENTICATION_SUCCESS);
@@ -1153,9 +1151,7 @@
 
         dppEventCallback.onSuccessConfigReceived(selectedNetwork);
         mLooper.dispatchAll();
-        verify(mDppCallback).onSuccessConfigReceived(
-                eq(WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                        TEST_NETWORK_ID, WifiConfiguration.SECURITY_TYPE_SAE)));
+        verify(mDppCallback).onSuccessConfigReceived(eq(TEST_NETWORK_ID));
         verify(mDppCallback, never()).onSuccess(anyInt());
         verify(mDppCallback, never()).onFailure(anyInt(), anyString(), anyString(), any());
         verify(mDppMetrics).updateDppEnrolleeResponderRequests();
diff --git a/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
index c7127ce..f62fc2b 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/HalDeviceManagerTest.java
@@ -985,7 +985,7 @@
 
         // Verify a runnable is posted because current thread is different than the intended thread
         // for running "onDestroyed"
-        verify(staIfaceOnDestroyedHandler).post(lambdaCaptor.capture());
+        verify(staIfaceOnDestroyedHandler).postAtFrontOfQueue(lambdaCaptor.capture());
 
         // Verify onDestroyed is only run after the posted runnable is dispatched
         verify(staIdl, never()).onDestroyed("wlan0");
@@ -1012,7 +1012,7 @@
         simulateStartAndStopWifi(staIdl, staIfaceOnDestroyedHandler);
 
         // Verify a runnable is never posted
-        verify(staIfaceOnDestroyedHandler, never()).post(any());
+        verify(staIfaceOnDestroyedHandler, never()).postAtFrontOfQueue(any());
         // Verify onDestroyed is triggered directly
         verify(staIdl).onDestroyed("wlan0");
     }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
index a0c4bf1..0647b33 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/SoftApManagerTest.java
@@ -272,6 +272,7 @@
         // Default init STA enabled
         when(mResources.getBoolean(R.bool.config_wifiStaWithBridgedSoftApConcurrencySupported))
                 .thenReturn(true);
+        when(mWifiNative.isStaApConcurrencySupported()).thenReturn(true);
         when(mActiveModeWarden.getClientModeManagers())
                 .thenReturn(mTestClientModeManagers);
         mTestClientModeManagers.add(mPrimaryConcreteClientModeManager);
@@ -3169,4 +3170,29 @@
         configBuilder.setBand(SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ);
         startSoftApAndVerifyEnabled(apConfig, TEST_COUNTRY_CODE, configBuilder.build());
     }
+
+    private SoftApConfiguration generateBridgedModeSoftApConfig(SoftApConfiguration config)
+            throws Exception {
+        int[] dual_bands = {SoftApConfiguration.BAND_2GHZ ,
+                SoftApConfiguration.BAND_2GHZ | SoftApConfiguration.BAND_5GHZ};
+        Builder configBuilder = new SoftApConfiguration.Builder(
+                config != null ? config : mDefaultApConfig);
+        configBuilder.setBands(dual_bands);
+        return configBuilder.build();
+    }
+
+    @Test
+    public void testBridgedApEnabledWhenStaExistButStaApConcurrencyNotSupported()
+            throws Exception {
+        assumeTrue(SdkLevel.isAtLeastS());
+        when(mWifiNative.isStaApConcurrencySupported()).thenReturn(false);
+        SoftApConfiguration bridgedConfig = new SoftApConfiguration.Builder(
+                generateBridgedModeSoftApConfig(null)).build();
+
+        SoftApModeConfiguration apConfig = new SoftApModeConfiguration(
+                WifiManager.IFACE_IP_MODE_TETHERED, bridgedConfig,
+                mTestSoftApCapability);
+        startSoftApAndVerifyEnabled(apConfig, TEST_COUNTRY_CODE, bridgedConfig);
+    }
 }
+
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
index 67bf1e8..847afe4 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationTestUtil.java
@@ -724,7 +724,7 @@
     }
 
 
-    /**
+   /**
      * Asserts that the 2 WifiConfigurations are equal. This only compares the elements saved
      * for softAp used.
      */
@@ -853,26 +853,6 @@
     }
 
     /**
-     * Assert that the 2 lists of WifiConfigurations are equal.
-     */
-    public static void assertConfigurationsEqual(
-            List<WifiConfiguration> expected, List<WifiConfiguration> actual) {
-        assertEquals(expected.size(), actual.size());
-        for (WifiConfiguration expectedConfiguration : expected) {
-            String expectedConfigKey = expectedConfiguration.getProfileKey();
-            boolean didCompare = false;
-            for (WifiConfiguration actualConfiguration : actual) {
-                String actualConfigKey = actualConfiguration.getProfileKey();
-                if (actualConfigKey.equals(expectedConfigKey)) {
-                    assertConfigurationEqual(expectedConfiguration, actualConfiguration);
-                    didCompare = true;
-                }
-            }
-            assertTrue(didCompare);
-        }
-    }
-
-    /**
      * Assert that the 2 NetworkSelectionStatus's are equal. This compares all the elements saved
      * for config store.
      */
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
index a715422..c71fb1a 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConfigurationUtilTest.java
@@ -16,13 +16,9 @@
 
 package com.android.server.wifi;
 
-import static android.net.wifi.WifiConfiguration.INVALID_NETWORK_ID;
 import static android.net.wifi.WifiEnterpriseConfig.OCSP_NONE;
 import static android.net.wifi.WifiEnterpriseConfig.OCSP_REQUIRE_CERT_STATUS;
 
-import static com.android.server.wifi.WifiConfigurationUtil.addSecurityTypeToNetworkId;
-import static com.android.server.wifi.WifiConfigurationUtil.convertWifiInfoSecurityTypeToWifiConfiguration;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -34,7 +30,6 @@
 import android.net.wifi.SecurityParams;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiEnterpriseConfig;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.net.wifi.WifiNetworkSpecifier;
 import android.net.wifi.WifiScanner;
@@ -43,8 +38,6 @@
 
 import androidx.test.filters.SmallTest;
 
-import com.android.modules.utils.build.SdkLevel;
-
 import org.junit.Test;
 
 import java.security.cert.X509Certificate;
@@ -1274,112 +1267,4 @@
         assertTrue(WifiConfigurationUtil.validate(config,
                 WifiConfigurationUtil.VALIDATE_FOR_UPDATE));
     }
-
-    /**
-     * Verify the behavior of convertWifiInfoSecurityTypeToWifiConfiguration
-     */
-    @Test
-    public void testConvertWifiInfoSecurityTypeToWifiConfiguration() {
-        assertEquals(WifiConfiguration.SECURITY_TYPE_OPEN,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_OPEN));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_WEP,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_WEP));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_PSK,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_PSK));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_EAP,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_EAP));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_SAE,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_SAE));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
-                convertWifiInfoSecurityTypeToWifiConfiguration(
-                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_OWE,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_OWE));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_WAPI_PSK,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_WAPI_PSK));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_WAPI_CERT,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_WAPI_CERT));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
-                convertWifiInfoSecurityTypeToWifiConfiguration(
-                        WifiInfo.SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_OSEN,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_OSEN));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2,
-                convertWifiInfoSecurityTypeToWifiConfiguration(
-                        WifiInfo.SECURITY_TYPE_PASSPOINT_R1_R2));
-        assertEquals(WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3,
-                convertWifiInfoSecurityTypeToWifiConfiguration(
-                        WifiInfo.SECURITY_TYPE_PASSPOINT_R3));
-        assertEquals(-1, convertWifiInfoSecurityTypeToWifiConfiguration(13));
-        assertEquals(-1,
-                convertWifiInfoSecurityTypeToWifiConfiguration(WifiInfo.SECURITY_TYPE_UNKNOWN));
-    }
-
-    /**
-     * Verify that adding and removing the security type for network ID behaves correctly
-     */
-    @Test
-    public void testAddAndRemoveSecurityTypeForNetworkId() {
-        List<Integer> securityListNoPasspoint = Arrays.asList(
-                WifiConfiguration.SECURITY_TYPE_OPEN,
-                WifiConfiguration.SECURITY_TYPE_WEP,
-                WifiConfiguration.SECURITY_TYPE_PSK,
-                WifiConfiguration.SECURITY_TYPE_EAP,
-                WifiConfiguration.SECURITY_TYPE_SAE,
-                WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE_192_BIT,
-                WifiConfiguration.SECURITY_TYPE_OWE,
-                WifiConfiguration.SECURITY_TYPE_WAPI_PSK,
-                WifiConfiguration.SECURITY_TYPE_WAPI_CERT,
-                WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE,
-                WifiConfiguration.SECURITY_TYPE_OSEN
-        );
-
-        List<Integer> securityListPasspoint = Arrays.asList(
-                WifiConfiguration.SECURITY_TYPE_PASSPOINT_R1_R2,
-                WifiConfiguration.SECURITY_TYPE_PASSPOINT_R3
-        );
-
-        List<Integer> securityList = new ArrayList<>();
-        securityList.addAll(securityListPasspoint);
-        securityList.addAll(securityListNoPasspoint);
-
-        final int netId = 1;
-        if (!SdkLevel.isAtLeastS()) {
-            // INVALID_NET_ID should remain the same from either adding or removing
-            assertEquals(INVALID_NETWORK_ID, WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                    INVALID_NETWORK_ID, WifiConfiguration.SECURITY_TYPE_OPEN));
-            assertEquals(INVALID_NETWORK_ID, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                    INVALID_NETWORK_ID));
-            // Add and then remove should result in the original netId
-            for (@WifiConfiguration.SecurityType int securityType : securityList) {
-                assertEquals(netId, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                        WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                                netId, securityType)));
-            }
-            // Multiple removes should result in the same netId as a single remove
-            for (@WifiConfiguration.SecurityType int securityType : securityList) {
-                assertEquals(WifiConfigurationUtil.removeSecurityTypeFromNetworkId(netId),
-                        WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                                WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                                        WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                                                netId, securityType))));
-            }
-            // A unique net id should be created for each non-passpoint security type added
-            assertEquals(securityListNoPasspoint.size(), securityListNoPasspoint.stream()
-                    .map(security -> addSecurityTypeToNetworkId(netId, security))
-                    .distinct()
-                    .count());
-
-            // Passpoint should keep its security type for R WifiTrackerLib
-            for (@WifiConfiguration.SecurityType int securityType : securityListPasspoint) {
-                assertEquals(netId, WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                                netId, securityType));
-            }
-        } else {
-            // Add should do nothing for SDK level S and above.
-            for (@WifiConfiguration.SecurityType int securityType : securityList) {
-                assertEquals(netId, addSecurityTypeToNetworkId(netId, securityType));
-            }
-        }
-    }
 }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
index a1bdaed..ad889fc 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiConnectivityManagerTest.java
@@ -1793,6 +1793,47 @@
     }
 
     /**
+     * Verify that when cached candidates get cleared there will no longer be retries after a
+     * connection failure.
+     */
+    @Test
+    public void testNoRetryConnectionOnFailureAfterCacheCleared() {
+        // Setup WifiNetworkSelector to return 2 valid candidates from scan results
+        MacAddress macAddress = MacAddress.fromString(CANDIDATE_BSSID_2);
+        WifiCandidates.Key key = new WifiCandidates.Key(mock(ScanResultMatchInfo.class),
+                macAddress, 0, WifiConfiguration.SECURITY_TYPE_OPEN);
+        WifiCandidates.Candidate otherCandidate = mock(WifiCandidates.Candidate.class);
+        when(otherCandidate.getKey()).thenReturn(key);
+        List<WifiCandidates.Candidate> candidateList = new ArrayList<>();
+        candidateList.add(mCandidate1);
+        candidateList.add(otherCandidate);
+        when(mWifiNS.getCandidatesFromScan(any(), any(), any(), anyBoolean(), anyBoolean(),
+                anyBoolean())).thenReturn(candidateList);
+
+        // Set WiFi to disconnected state to trigger scan
+        mWifiConnectivityManager.handleConnectionStateChanged(
+                mPrimaryClientModeManager,
+                WifiConnectivityManager.WIFI_STATE_DISCONNECTED);
+        mLooper.dispatchAll();
+        // Verify a connection starting
+        verify(mWifiNS).selectNetwork((List<WifiCandidates.Candidate>)
+                argThat(new WifiCandidatesListSizeMatcher(2)));
+        verify(mPrimaryClientModeManager).startConnectToNetwork(anyInt(), anyInt(), any());
+
+        // now clear the cached candidates
+        mWifiConnectivityManager.clearCachedCandidates();
+
+        // Simulate the connection failing
+        mWifiConnectivityManager.handleConnectionAttemptEnded(
+                mPrimaryClientModeManager,
+                WifiMetrics.ConnectionEvent.FAILURE_ASSOCIATION_REJECTION, CANDIDATE_BSSID,
+                CANDIDATE_SSID);
+
+        // Verify there no re-attempt to connect
+        verify(mPrimaryClientModeManager).startConnectToNetwork(anyInt(), anyInt(), any());
+    }
+
+    /**
      * Verify that the cached candidates that become disabled are not selected for connection.
      */
     @Test
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
index 6e82f82..3d1eb30 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiNetworkSelectorTest.java
@@ -121,6 +121,8 @@
         mThroughputScorer = new ThroughputScorer(mScoringParams);
         when(mWifiInjector.getActiveModeWarden()).thenReturn(mActiveModeWarden);
         when(mWifiInjector.getWifiGlobals()).thenReturn(mWifiGlobals);
+        when(mWifiGlobals.getWifiLowConnectedScoreThresholdToTriggerScanForMbb()).thenReturn(
+                ConnectedScore.WIFI_TRANSITION_SCORE);
         when(mActiveModeWarden.getPrimaryClientModeManager()).thenReturn(mClientModeManager);
         if (WifiNetworkSelector.PRESET_CANDIDATE_SCORER_NAME.equals(
                 mThroughputScorer.getIdentifier())) {
@@ -333,6 +335,7 @@
         when(mWifiInfo.getNetworkId()).thenReturn(WifiConfiguration.INVALID_NETWORK_ID);
         when(mWifiInfo.getBSSID()).thenReturn(null);
         when(mWifiInfo.isUsable()).thenReturn(true);
+        when(mWifiInfo.getScore()).thenReturn(ConnectedScore.WIFI_INITIAL_SCORE);
         when(mSecondaryWifiInfo.isUsable()).thenReturn(true);
     }
 
@@ -367,6 +370,29 @@
         assertFalse(mWifiNetworkSelector.isNetworkSufficient(mWifiInfo));
     }
 
+    @Test
+    public void testNetworkInsufficientWhenLowAospScore() {
+        // mock current network to be connected
+        WifiConfiguration testConfig = WifiConfigurationTestUtil.createOpenNetwork();
+        when(mWifiInfo.getSupplicantState()).thenReturn(SupplicantState.COMPLETED);
+        when(mWifiConfigManager.getConfiguredNetwork(anyInt()))
+                .thenReturn(testConfig);
+        when(mWifiInfo.getScore()).thenReturn(ConnectedScore.WIFI_TRANSITION_SCORE);
+
+        // verify the current network is sufficient
+        assertTrue(mWifiNetworkSelector.isNetworkSufficient(mWifiInfo));
+
+        // verify the current network is no longer sufficient after the score drops below
+        // WIFI_TRANSITION_SCORE.
+        when(mWifiInfo.getScore()).thenReturn(ConnectedScore.WIFI_TRANSITION_SCORE - 1);
+        assertFalse(mWifiNetworkSelector.isNetworkSufficient(mWifiInfo));
+
+        // verify that when the external scorer is used, aosp score no longer affect network
+        // selection.
+        when(mWifiGlobals.isUsingExternalScorer()).thenReturn(true);
+        assertTrue(mWifiNetworkSelector.isNetworkSufficient(mWifiInfo));
+    }
+
     /**
      * No network selection if scan result is empty.
      *
@@ -669,7 +695,7 @@
         // Do network selection.
         List<WifiCandidates.Candidate> candidates = mWifiNetworkSelector.getCandidatesFromScan(
                 scanDetails, blocklist,
-                Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, true, false, mWifiInfo)),
+                Arrays.asList(new ClientModeManagerState(TEST_IFACE_NAME, false, true, mWifiInfo)),
                 false, true, true);
         WifiConfiguration candidate = mWifiNetworkSelector.selectNetwork(candidates);
         verify(mWifiMetrics).incrementNetworkSelectionFilteredBssidCount(0);
@@ -2047,6 +2073,7 @@
         when(mWifiInfo.is5GHz()).thenReturn(true);
         when(mWifiInfo.getFrequency()).thenReturn(5000);
         when(mWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 2);
+        when(mWifiInfo.getScore()).thenReturn(ConnectedScore.WIFI_MAX_SCORE);
         when(mWifiInfo.getSuccessfulRxPacketsPerSecond())
                 .thenReturn(mMinPacketRateActiveTraffic + 1.0);
 
@@ -2058,6 +2085,7 @@
         when(mSecondaryWifiInfo.is5GHz()).thenReturn(true);
         when(mSecondaryWifiInfo.getFrequency()).thenReturn(5000);
         when(mSecondaryWifiInfo.getRssi()).thenReturn(mThresholdQualifiedRssi5G + 2);
+        when(mSecondaryWifiInfo.getScore()).thenReturn(ConnectedScore.WIFI_MAX_SCORE);
         when(mSecondaryWifiInfo.getSuccessfulRxPacketsPerSecond())
                 .thenReturn(mMinPacketRateActiveTraffic + 1.0);
 
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
index 15a3e33..64f4c84 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiScoreReportTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wifi;
 
+import static com.android.server.wifi.ClientModeImpl.WIFI_WORK_SOURCE;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
@@ -76,6 +78,7 @@
 public class WifiScoreReportTest extends WifiBaseTest {
     class FakeClock extends Clock {
         long mWallClockMillis = 1500000000000L;
+        long mElapsedSinceBootMillis = 0L;
         int mStepMillis = 1001;
 
         @Override
@@ -83,8 +86,14 @@
             mWallClockMillis += mStepMillis;
             return mWallClockMillis;
         }
+
+        @Override
+        public long getElapsedSinceBootMillis() {
+            return mElapsedSinceBootMillis;
+        }
     }
 
+    private static final int TEST_LOW_CONNECTED_SCORE_SCAN_PERIOD_SECONDS = 60;
     private static final int TEST_NETWORK_ID = 860370;
     private static final int TEST_SESSION_ID = 8603703; // last digit is a check digit
     private static final String TEST_IFACE_NAME = "wlan0";
@@ -113,6 +122,8 @@
     @Mock ExternalScoreUpdateObserverProxy mExternalScoreUpdateObserverProxy;
     @Mock WifiSettingsStore mWifiSettingsStore;
     @Mock WifiGlobals mWifiGlobals;
+    @Mock ActiveModeWarden mActiveModeWarden;
+    @Mock WifiConnectivityManager mWifiConnectivityManager;
     @Captor ArgumentCaptor<WifiManager.ScoreUpdateObserver> mExternalScoreUpdateObserverCbCaptor;
     private TestLooper mLooper;
 
@@ -192,6 +203,11 @@
         mWifiInfo.setFrequency(2412);
         mWifiInfo.setBSSID(TEST_BSSID);
         mLooper = new TestLooper();
+        when(mActiveModeWarden.canRequestSecondaryTransientClientModeManager()).thenReturn(true);
+        when(mWifiGlobals.getWifiLowConnectedScoreThresholdToTriggerScanForMbb()).thenReturn(
+                ConnectedScore.WIFI_TRANSITION_SCORE);
+        when(mWifiGlobals.getWifiLowConnectedScoreScanPeriodSeconds()).thenReturn(
+                TEST_LOW_CONNECTED_SCORE_SCAN_PERIOD_SECONDS);
         when(mContext.getResources()).thenReturn(mResources);
         when(mNetwork.getNetId()).thenReturn(0);
         when(mNetworkAgent.getNetwork()).thenReturn(mNetwork);
@@ -208,7 +224,8 @@
                 mWifiNative, mWifiBlocklistMonitor, mWifiThreadRunner, mWifiScoreCard,
                 mDeviceConfigFacade, mContext,
                 mAdaptiveConnectivityEnabledSettingObserver, TEST_IFACE_NAME,
-                mExternalScoreUpdateObserverProxy, mWifiSettingsStore);
+                mExternalScoreUpdateObserverProxy, mWifiSettingsStore,
+                mWifiGlobals, mActiveModeWarden, mWifiConnectivityManager);
         mWifiScoreReport.onRoleChanged(ActiveModeManager.ROLE_CLIENT_PRIMARY);
         mWifiScoreReport.setNetworkAgent(mNetworkAgent);
         when(mDeviceConfigFacade.getMinConfirmationDurationSendLowScoreMs()).thenReturn(
@@ -479,6 +496,7 @@
         }
         int score = mWifiInfo.getScore();
         assertTrue(score > ConnectedScore.WIFI_TRANSITION_SCORE);
+        verify(mWifiConnectivityManager, never()).forceConnectivityScan(any());
     }
 
     /**
@@ -517,6 +535,73 @@
         }
     }
 
+    @Test
+    public void testAospScoreBreachTriggersScan() throws Exception {
+        // initially called once
+        verifySentAnyNetworkScore();
+
+        // First has good RSSI but low traffic
+        mWifiInfo.setRssi(-33);
+        mWifiInfo.setLinkSpeed(6); // Mbps
+        mWifiInfo.setFrequency(5220);
+        mWifiScoreReport.enableVerboseLogging(true);
+        mWifiInfo.setSuccessfulTxPacketsPerSecond(0.1);
+        mWifiInfo.setSuccessfulRxPacketsPerSecond(0.1);
+        for (int i = 0; i < 10; i++) {
+            mWifiScoreReport.calculateAndReportScore();
+        }
+        assertTrue("wifi score should be high",
+                mWifiInfo.getScore() >= ConnectedScore.WIFI_TRANSITION_SCORE);
+        verify(mWifiConnectivityManager, never()).forceConnectivityScan(any());
+
+        // Then simulate low RSSI and traffic, and verify score becomes low and a scan is triggered.
+        mWifiInfo.setRssi(-100);
+        for (int i = 0; i < 10; i++) {
+            mWifiScoreReport.calculateAndReportScore();
+        }
+        assertTrue("wifi score should be low",
+                mWifiInfo.getScore() < ConnectedScore.WIFI_TRANSITION_SCORE);
+        verify(mWifiConnectivityManager).forceConnectivityScan(WIFI_WORK_SOURCE);
+
+        // move time forward slightly, not passing enough time to do another scan.
+        mClock.mElapsedSinceBootMillis = (long) TEST_LOW_CONNECTED_SCORE_SCAN_PERIOD_SECONDS * 1000;
+
+        // trigger low score again and verify no additional scan yet.
+        mWifiScoreReport.calculateAndReportScore();
+        verify(mWifiConnectivityManager).forceConnectivityScan(WIFI_WORK_SOURCE);
+
+        // move time past the threshold to trigger scan again and verify the scan happens
+        mClock.mElapsedSinceBootMillis =
+                (long) TEST_LOW_CONNECTED_SCORE_SCAN_PERIOD_SECONDS * 1000 + 1;
+        mWifiScoreReport.calculateAndReportScore();
+        verify(mWifiConnectivityManager, times(2)).forceConnectivityScan(WIFI_WORK_SOURCE);
+    }
+
+    /**
+     * When the AOSP score is low but external scorer is registered, scan will not be triggered.
+     */
+    @Test
+    public void testAospScoreBreachNoScanWhenExternalScorerEnabled() throws Exception {
+        // register external scorer
+        mWifiScoreReport.setWifiConnectedNetworkScorer(mAppBinder, mWifiConnectedNetworkScorer);
+        verify(mWifiGlobals).setUsingExternalScorer(true);
+        mWifiInfo.setFrequency(5220);
+        for (int rssi = -60; rssi >= -83; rssi -= 1) {
+            mWifiInfo.setRssi(rssi);
+            mWifiScoreReport.calculateAndReportScore();
+        }
+        int score = mWifiInfo.getScore();
+        assertTrue(score < ConnectedScore.WIFI_TRANSITION_SCORE);
+        verify(mWifiConnectivityManager, never()).forceConnectivityScan(any());
+
+        // when the external score is cleared, scan should be triggered.
+        mWifiScoreReport.clearWifiConnectedNetworkScorer();
+        mWifiScoreReport.calculateAndReportScore();
+        assertTrue(score < ConnectedScore.WIFI_TRANSITION_SCORE);
+        verify(mWifiConnectivityManager).forceConnectivityScan(any());
+        verify(mWifiGlobals).setUsingExternalScorer(false);
+    }
+
     /**
      * When the score ramps down to the exit theshold, let go.
      */
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
index 66e78b3..f437a7b 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiServiceImplTest.java
@@ -298,7 +298,7 @@
     final ArgumentCaptor<SoftApModeConfiguration> mSoftApModeConfigCaptor =
             ArgumentCaptor.forClass(SoftApModeConfiguration.class);
 
-    @Mock Context mContext;
+    @Mock WifiContext mContext;
     @Mock Context mContextAsUser;
     @Mock WifiInjector mWifiInjector;
     @Mock WifiCountryCode mWifiCountryCode;
@@ -2421,8 +2421,7 @@
 
         assertEquals(TEST_SSID_WITH_QUOTES, connectionInfo.getSSID());
         assertEquals(TEST_BSSID, connectionInfo.getBSSID());
-        assertEquals(TEST_NETWORK_ID, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                connectionInfo.getNetworkId()));
+        assertEquals(TEST_NETWORK_ID, connectionInfo.getNetworkId());
         assertEquals(TEST_FQDN, connectionInfo.getPasspointFqdn());
         assertEquals(TEST_FRIENDLY_NAME, connectionInfo.getPasspointProviderFriendlyName());
     }
@@ -2450,8 +2449,7 @@
 
         assertEquals(TEST_SSID_WITH_QUOTES, connectionInfo.getSSID());
         assertEquals(TEST_BSSID, connectionInfo.getBSSID());
-        assertEquals(TEST_NETWORK_ID, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                connectionInfo.getNetworkId()));
+        assertEquals(TEST_NETWORK_ID, connectionInfo.getNetworkId());
         assertEquals(TEST_FQDN, connectionInfo.getPasspointFqdn());
         assertEquals(TEST_FRIENDLY_NAME, connectionInfo.getPasspointProviderFriendlyName());
     }
@@ -2479,8 +2477,7 @@
 
         assertEquals(TEST_SSID_WITH_QUOTES, connectionInfo.getSSID());
         assertEquals(TEST_BSSID, connectionInfo.getBSSID());
-        assertEquals(TEST_NETWORK_ID, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                connectionInfo.getNetworkId()));
+        assertEquals(TEST_NETWORK_ID, connectionInfo.getNetworkId());
         assertEquals(TEST_FQDN, connectionInfo.getPasspointFqdn());
         assertEquals(TEST_FRIENDLY_NAME, connectionInfo.getPasspointProviderFriendlyName());
     }
@@ -4070,8 +4067,7 @@
                 any(PasspointConfiguration.class), anyInt(), eq(TEST_PACKAGE_NAME), eq(false),
                 eq(true))).thenReturn(true);
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
         verifyCheckChangePermission(TEST_PACKAGE_NAME);
         verify(mPasspointManager).addOrUpdateProvider(
@@ -5784,8 +5780,7 @@
 
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
 
         verifyCheckChangePermission(TEST_PACKAGE_NAME);
@@ -5806,8 +5801,7 @@
 
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
 
         // Ensure that we don't check for change permission.
@@ -5832,8 +5826,7 @@
 
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
 
         verifyCheckChangePermission(TEST_PACKAGE_NAME);
@@ -5856,8 +5849,7 @@
 
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
 
         verifyCheckChangePermission(TEST_PACKAGE_NAME);
@@ -5880,8 +5872,7 @@
 
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
 
         verifyCheckChangePermission(TEST_PACKAGE_NAME);
@@ -5903,8 +5894,7 @@
 
         WifiConfiguration config = WifiConfigurationTestUtil.createOpenNetwork();
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
 
         verifyCheckChangePermission(TEST_PACKAGE_NAME);
@@ -7495,6 +7485,7 @@
         mWifiServiceImpl.startRestrictingAutoJoinToSubscriptionId(1);
         mLooper.dispatchAll();
         verify(mWifiConfigManager).startRestrictingAutoJoinToSubscriptionId(1);
+        verify(mWifiConnectivityManager).clearCachedCandidates();
         verify(mClientModeManager).disconnect();
     }
 
@@ -8193,8 +8184,7 @@
 
         // Verify operation succeeds
         mLooper.startAutoDispatch();
-        assertEquals(0, WifiConfigurationUtil.removeSecurityTypeFromNetworkId(
-                mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME)));
+        assertEquals(0, mWifiServiceImpl.addOrUpdateNetwork(config, TEST_PACKAGE_NAME));
         mLooper.stopAutoDispatchAndIgnoreExceptions();
         verify(mWifiConfigManager).addOrUpdateNetwork(any(),  anyInt(), any());
     }
@@ -8246,12 +8236,6 @@
         multiTypeConfigs.add(WifiConfigurationTestUtil.createOpenOweNetwork());
         multiTypeConfigs.add(WifiConfigurationTestUtil.createPskSaeNetwork());
         multiTypeConfigs.add(WifiConfigurationTestUtil.createWpa2Wpa3EnterpriseNetwork());
-        // Add a valid network ID for each multi-type config to verify the network IDs of the
-        // single-type configs.
-        int i = 0;
-        for (WifiConfiguration config : multiTypeConfigs) {
-            config.networkId = i++;
-        }
         return multiTypeConfigs;
     }
 
@@ -8268,6 +8252,9 @@
     private List<WifiConfiguration> generateExpectedConfigs(
             List<WifiConfiguration> testConfigs,
             boolean saeAutoUpgradeEnabled, boolean oweAutoUpgradeEnabled) {
+        if (!SdkLevel.isAtLeastS()) {
+            return testConfigs;
+        }
         WifiConfiguration tmpConfig;
         List<WifiConfiguration> expectedConfigs = new ArrayList<>();
         tmpConfig = new WifiConfiguration(testConfigs.get(0));
@@ -8299,20 +8286,11 @@
                 SecurityParams.createSecurityParamsBySecurityType(
                         WifiConfiguration.SECURITY_TYPE_EAP));
         expectedConfigs.add(tmpConfig);
-        if (SdkLevel.isAtLeastS()) {
-            // WPA2/WPA3-Enterprise config maps only to WPA2-Enterprise for R, but should map to
-            // both WPA2 and WPA3-Enterprise for S and beyond.
-            tmpConfig = new WifiConfiguration(testConfigs.get(2));
-            tmpConfig.setSecurityParams(
-                    SecurityParams.createSecurityParamsBySecurityType(
-                            WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
-            expectedConfigs.add(tmpConfig);
-        } else {
-            for (WifiConfiguration config : expectedConfigs) {
-                config.networkId = WifiConfigurationUtil.addSecurityTypeToNetworkId(
-                        config.networkId, config.getDefaultSecurityParams().getSecurityType());
-            }
-        }
+        tmpConfig = new WifiConfiguration(testConfigs.get(2));
+        tmpConfig.setSecurityParams(
+                SecurityParams.createSecurityParamsBySecurityType(
+                        WifiConfiguration.SECURITY_TYPE_EAP_WPA3_ENTERPRISE));
+        expectedConfigs.add(tmpConfig);
         return expectedConfigs;
     }
 
@@ -8341,9 +8319,9 @@
 
         List<WifiConfiguration> expectedConfigs = generateExpectedConfigs(
                 testConfigs, true, true);
-        WifiConfigurationTestUtil.assertConfigurationsEqual(
+        WifiConfigurationTestUtil.assertConfigurationsEqualForBackup(
                 expectedConfigs, configs.getList());
-        WifiConfigurationTestUtil.assertConfigurationsEqual(
+        WifiConfigurationTestUtil.assertConfigurationsEqualForBackup(
                 expectedConfigs, privilegedConfigs.getList());
     }
 
@@ -8372,9 +8350,9 @@
 
         List<WifiConfiguration> expectedConfigs = generateExpectedConfigs(
                 testConfigs, false, false);
-        WifiConfigurationTestUtil.assertConfigurationsEqual(
+        WifiConfigurationTestUtil.assertConfigurationsEqualForBackup(
                 expectedConfigs, configs.getList());
-        WifiConfigurationTestUtil.assertConfigurationsEqual(
+        WifiConfigurationTestUtil.assertConfigurationsEqualForBackup(
                 expectedConfigs, privilegedConfigs.getList());
     }
 
@@ -8403,9 +8381,9 @@
 
         List<WifiConfiguration> expectedConfigs = generateExpectedConfigs(
                 testConfigs, true, true);
-        WifiConfigurationTestUtil.assertConfigurationsEqual(
+        WifiConfigurationTestUtil.assertConfigurationsEqualForBackup(
                 expectedConfigs, configs.getList());
-        WifiConfigurationTestUtil.assertConfigurationsEqual(
+        WifiConfigurationTestUtil.assertConfigurationsEqualForBackup(
                 expectedConfigs, privilegedConfigs.getList());
     }
 }
diff --git a/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java b/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java
index 211537e..385eedf 100644
--- a/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java
+++ b/service/tests/wifitests/src/com/android/server/wifi/WifiShellCommandTest.java
@@ -42,7 +42,6 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
-import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.wifi.SoftApConfiguration;
 import android.net.wifi.SupplicantState;
@@ -86,7 +85,7 @@
     @Mock WifiCountryCode mWifiCountryCode;
     @Mock WifiLastResortWatchdog mWifiLastResortWatchdog;
     @Mock WifiServiceImpl mWifiService;
-    @Mock Context mContext;
+    @Mock WifiContext mContext;
     @Mock ConnectivityManager mConnectivityManager;
     @Mock WifiCarrierInfoManager mWifiCarrierInfoManager;
     @Mock WifiNetworkFactory mWifiNetworkFactory;