ClientModeImpl: Disconnect if network is marked metered

1) If the network is marked metered from unmetered/none by either the
app or user post connection, trigger a disconnect to ensure that all
apps re-read the meteredness of the network (when connected back again).
2) If the network is marked unmetered/none from metered by either the
app or user post connection, just update the network capabilities.

Also,
a) Modified the onNetworkUpdated() WifiConfigManager callback to include
both the previous and new config to help clients compare what has changed.
b) If a suggestion is being updated and the network is cached in
WifiConfigManager (either because we're connected to that or was connectable
in the recent past), trigger an immediate update of configuration. This ensures
that any metered changes take effect immediately.
c) Similarly for passpoint networks cached in WifiConfigManager, trigger
an immediate of configuration. This ensures that any metered changes take
effect immediately.
d) Removed update of existing config in NetworkSuggestionNominator which
is redundant with (b)
e) Ensure that all configs sent out from WifiConfigManager callbacks
have their passwords masked to ensure they're not accidentally sent out
of the stack.
f) Added a shell command to just add/update network config without
triggering a connect immediately.

Bug: 153127005
Test: atest com.android.server.wifi
Test: Manual steps
Suggestion Metered change (unmetered->metered):
adb shell cmd wifi add-suggestion <ssid> open
adb shell cmd wifi start-scan
adb shell cmd wifi status -> connected as unmetered
adb shell cmd wifi add-suggestion GoogleGuest open -m
adb shell cmd wifi status -> disconnected
adb shell cmd wifi status -> connected back as metered
adb shell cmd wifi add-suggestion GoogleGuest open
adb shell cmd wifi status -> remained connected, but changed to unmetered

Saved network Metered change (unmetered->metered):
adb shell cmd wifi add-network <ssid> open
adb shell cmd wifi start-scan
adb shell cmd wifi status -> connected as unmetered
adb shell cmd wifi add-network GoogleGuest open -m
adb shell cmd wifi status -> disconnected
adb shell cmd wifi status -> connected back as metered
adb shell cmd wifi add-network GoogleGuest open
adb shell cmd wifi status -> remained connected, but changed to unmetered

Change-Id: Id313a302dc529fcafa8e2d1a8442f748896cab89
diff --git a/service/java/com/android/server/wifi/ClientModeImpl.java b/service/java/com/android/server/wifi/ClientModeImpl.java
index 85eeb22..2b39105 100644
--- a/service/java/com/android/server/wifi/ClientModeImpl.java
+++ b/service/java/com/android/server/wifi/ClientModeImpl.java
@@ -1105,12 +1105,31 @@
             mWifiNative.removeNetworkCachedData(config.networkId);
         }
 
-
         @Override
-        public void onNetworkUpdated(WifiConfiguration config) {
-            // User might have changed meteredOverride, so update capabilities
-            if (config.networkId == mLastNetworkId) {
-                updateCapabilities();
+        public void onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig) {
+            // Check if user/app change meteredOverride for connected network.
+            if (newConfig.networkId != mLastNetworkId
+                    || newConfig.meteredOverride == oldConfig.meteredOverride) {
+                // nothing to do.
+                return;
+            }
+            boolean isMetered = WifiConfiguration.isMetered(newConfig, mWifiInfo);
+            boolean wasMetered = WifiConfiguration.isMetered(oldConfig, mWifiInfo);
+            if (isMetered == wasMetered) {
+                // no meteredness change, nothing to do.
+                if (mVerboseLoggingEnabled) {
+                    Log.v(TAG, "User/app changed meteredOverride, but no change in meteredness");
+                }
+                return;
+            }
+            // If unmetered->metered trigger a disconnect.
+            // If metered->unmetered update capabilities.
+            if (isMetered) {
+                Log.w(TAG, "Network marked metered, triggering disconnect");
+                sendMessage(CMD_DISCONNECT);
+            } else {
+                Log.i(TAG, "Network marked unmetered, triggering capabilities update");
+                updateCapabilities(newConfig);
             }
         }
 
@@ -4446,10 +4465,14 @@
     }
 
     private void updateCapabilities(WifiConfiguration currentWifiConfiguration) {
+        updateCapabilities(getCapabilities(currentWifiConfiguration));
+    }
+
+    private void updateCapabilities(NetworkCapabilities networkCapabilities) {
         if (mNetworkAgent == null) {
             return;
         }
-        mNetworkAgent.sendNetworkCapabilities(getCapabilities(currentWifiConfiguration));
+        mNetworkAgent.sendNetworkCapabilities(networkCapabilities);
     }
 
     private void handleEapAuthFailure(int networkId, int errorCode) {
diff --git a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
index a8d181f..c4fd6a9 100644
--- a/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
+++ b/service/java/com/android/server/wifi/NetworkSuggestionNominator.java
@@ -196,19 +196,6 @@
                 if (matchingExtNetworkSuggestionsFromSamePackage.isEmpty()) {
                     continue;
                 }
-                ExtendedWifiNetworkSuggestion matchingExtNetworkSuggestion =
-                        matchingExtNetworkSuggestionsFromSamePackage.stream().findFirst().get();
-                // Update the WifiConfigManager with the latest WifiConfig
-                WifiConfiguration config =
-                        matchingExtNetworkSuggestion.createInternalWifiConfiguration();
-                NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(
-                        config,
-                        matchingExtNetworkSuggestion.perAppInfo.uid,
-                        matchingExtNetworkSuggestion.perAppInfo.packageName);
-                if (result.isSuccess()) {
-                    wCmConfiguredNetwork = mWifiConfigManager.getConfiguredNetwork(
-                            result.getNetworkId());
-                }
                 // If the network is currently blacklisted, ignore.
                 if (!wCmConfiguredNetwork.getNetworkSelectionStatus().isNetworkEnabled()
                         && !mWifiConfigManager.tryEnableNetwork(wCmConfiguredNetwork.networkId)) {
diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java
index 4e4f51d..91ebe6b 100644
--- a/service/java/com/android/server/wifi/WifiConfigManager.java
+++ b/service/java/com/android/server/wifi/WifiConfigManager.java
@@ -107,6 +107,8 @@
     /**
      * Interface for other modules to listen to the network updated
      * events.
+     * Note: Credentials are masked to avoid accidentally sending credentials outside the stack.
+     * Use WifiConfigManager#getConfiguredNetworkWithPassword() to retrieve credentials.
      */
     public interface OnNetworkUpdateListener {
         /**
@@ -131,8 +133,12 @@
         void onNetworkTemporarilyDisabled(@NonNull WifiConfiguration config, int disableReason);
         /**
          * Invoked on network being updated.
+         *
+         * @param newConfig Updated WifiConfiguration object.
+         * @param oldConfig Prev WifiConfiguration object.
          */
-        void onNetworkUpdated(@NonNull WifiConfiguration config);
+        void onNetworkUpdated(
+                @NonNull WifiConfiguration newConfig, @NonNull WifiConfiguration oldConfig);
     }
     /**
      * Max size of scan details to cache in {@link #mScanDetailCaches}.
@@ -1323,9 +1329,9 @@
             Log.e(TAG, "Cannot add/update network before store is read!");
             return new NetworkUpdateResult(WifiConfiguration.INVALID_NETWORK_ID);
         }
+        WifiConfiguration existingConfig = getInternalConfiguredNetwork(config);
         if (!config.isEphemeral()) {
             // Removes the existing ephemeral network if it exists to add this configuration.
-            WifiConfiguration existingConfig = getConfiguredNetwork(config.getKey());
             if (existingConfig != null && existingConfig.isEphemeral()) {
                 // In this case, new connection for this config won't happen because same
                 // network is already registered as an ephemeral network.
@@ -1352,11 +1358,13 @@
         }
 
         for (OnNetworkUpdateListener listener : mListeners) {
-            WifiConfiguration configForListener = new WifiConfiguration(newConfig);
             if (result.isNewNetwork()) {
-                listener.onNetworkAdded(configForListener);
+                listener.onNetworkAdded(
+                        createExternalWifiConfiguration(newConfig, true, Process.WIFI_UID));
             } else {
-                listener.onNetworkUpdated(configForListener);
+                listener.onNetworkUpdated(
+                        createExternalWifiConfiguration(newConfig, true, Process.WIFI_UID),
+                        createExternalWifiConfiguration(existingConfig, true, Process.WIFI_UID));
             }
         }
         return result;
@@ -1445,8 +1453,8 @@
             saveToStore(true);
         }
         for (OnNetworkUpdateListener listener : mListeners) {
-            WifiConfiguration configForListener = new WifiConfiguration(config);
-            listener.onNetworkRemoved(configForListener);
+            listener.onNetworkRemoved(
+                    createExternalWifiConfiguration(config, true, Process.WIFI_UID));
         }
         return true;
     }
@@ -1606,8 +1614,8 @@
         // Clear out all the disable reason counters.
         status.clearDisableReasonCounter();
         for (OnNetworkUpdateListener listener : mListeners) {
-            WifiConfiguration configForListener = new WifiConfiguration(config);
-            listener.onNetworkEnabled(configForListener);
+            listener.onNetworkEnabled(
+                    createExternalWifiConfiguration(config, true, Process.WIFI_UID));
         }
     }
 
@@ -1623,8 +1631,8 @@
         status.setDisableTime(mClock.getElapsedSinceBootMillis());
         status.setNetworkSelectionDisableReason(disableReason);
         for (OnNetworkUpdateListener listener : mListeners) {
-            WifiConfiguration configForListener = new WifiConfiguration(config);
-            listener.onNetworkTemporarilyDisabled(configForListener, disableReason);
+            listener.onNetworkTemporarilyDisabled(
+                    createExternalWifiConfiguration(config, true, Process.WIFI_UID), disableReason);
         }
     }
 
@@ -1641,7 +1649,8 @@
         status.setNetworkSelectionDisableReason(disableReason);
         for (OnNetworkUpdateListener listener : mListeners) {
             WifiConfiguration configForListener = new WifiConfiguration(config);
-            listener.onNetworkPermanentlyDisabled(configForListener, disableReason);
+            listener.onNetworkPermanentlyDisabled(
+                    createExternalWifiConfiguration(config, true, Process.WIFI_UID), disableReason);
         }
     }
 
diff --git a/service/java/com/android/server/wifi/WifiConnectivityManager.java b/service/java/com/android/server/wifi/WifiConnectivityManager.java
index 712dbcd..59b3e3d 100644
--- a/service/java/com/android/server/wifi/WifiConnectivityManager.java
+++ b/service/java/com/android/server/wifi/WifiConnectivityManager.java
@@ -709,7 +709,7 @@
             updateScan();
         }
         @Override
-        public void onNetworkUpdated(WifiConfiguration config) {
+        public void onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig) {
             updateScan();
         }
         @Override
diff --git a/service/java/com/android/server/wifi/WifiHealthMonitor.java b/service/java/com/android/server/wifi/WifiHealthMonitor.java
index 123c576..0b0c68d 100644
--- a/service/java/com/android/server/wifi/WifiHealthMonitor.java
+++ b/service/java/com/android/server/wifi/WifiHealthMonitor.java
@@ -965,7 +965,7 @@
         }
 
         @Override
-        public void onNetworkUpdated(WifiConfiguration config) {
+        public void onNetworkUpdated(WifiConfiguration newConfig, WifiConfiguration oldConfig) {
         }
     }
 
diff --git a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
index 19c9da1..ef05ccb 100644
--- a/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
+++ b/service/java/com/android/server/wifi/WifiNetworkSuggestionsManager.java
@@ -264,6 +264,17 @@
                     && TextUtils.equals(perAppInfo.packageName, other.perAppInfo.packageName);
         }
 
+        /**
+         * Helper method to set the carrier Id.
+         */
+        public void setCarrierId(int carrierId) {
+            if (wns.passpointConfiguration == null) {
+                wns.wifiConfiguration.carrierId = carrierId;
+            } else {
+                wns.passpointConfiguration.setCarrierId(carrierId);
+            }
+        }
+
         @Override
         public String toString() {
             return new StringBuilder(wns.toString())
@@ -794,6 +805,29 @@
                         Collectors.toSet()));
     }
 
+    private void updateWifiConfigInWcmIfPresent(
+            WifiConfiguration newConfig, int uid, String packageName) {
+        WifiConfiguration configInWcm =
+                mWifiConfigManager.getConfiguredNetwork(newConfig.getKey());
+        if (configInWcm == null) return;
+        // !suggestion
+        if (!configInWcm.fromWifiNetworkSuggestion) return;
+        // is suggestion from same app.
+        if (configInWcm.creatorUid != uid
+                || !TextUtils.equals(configInWcm.creatorName, packageName)) {
+            return;
+        }
+        NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(
+                newConfig, uid, packageName);
+        if (!result.isSuccess()) {
+            Log.e(TAG, "Failed to update config in WifiConfigManager");
+        } else {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "Updated config in WifiConfigManager");
+            }
+        }
+    }
+
     /**
      * Add the provided list of network suggestions from the corresponding app's active list.
      */
@@ -862,10 +896,20 @@
         }
 
         for (ExtendedWifiNetworkSuggestion ewns: extNetworkSuggestions) {
-            if (ewns.wns.passpointConfiguration == null) {
-                if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
-                    ewns.wns.wifiConfiguration.carrierId = carrierId;
+            if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
+                ewns.setCarrierId(carrierId);
+            }
+            // If network has no IMSI protection and user didn't approve exemption, make it initial
+            // auto join disabled
+            if (isSimBasedSuggestion(ewns)) {
+                int subId = mTelephonyUtil.getMatchingSubId(getCarrierIdFromSuggestion(ewns));
+                if (!(mTelephonyUtil.requiresImsiEncryption(subId)
+                        || hasUserApprovedImsiPrivacyExemptionForCarrier(
+                        getCarrierIdFromSuggestion(ewns)))) {
+                    ewns.isAutojoinEnabled = false;
                 }
+            }
+            if (ewns.wns.passpointConfiguration == null) {
                 if (ewns.wns.wifiConfiguration.isEnterprise()) {
                     if (!mWifiKeyStore.updateNetworkKeys(ewns.wns.wifiConfiguration, null)) {
                         Log.e(TAG, "Enterprise network install failure for SSID: "
@@ -873,11 +917,13 @@
                         continue;
                     }
                 }
+                // If we have a config in WifiConfigManager for this suggestion, update
+                // WifiConfigManager with the latest WifiConfig.
+                // Note: Similar logic is present in PasspointManager for passpoint networks.
+                updateWifiConfigInWcmIfPresent(
+                        ewns.createInternalWifiConfiguration(), uid, packageName);
                 addToScanResultMatchInfoMap(ewns);
             } else {
-                if (carrierId != TelephonyManager.UNKNOWN_CARRIER_ID) {
-                    ewns.wns.passpointConfiguration.setCarrierId(carrierId);
-                }
                 ewns.wns.passpointConfiguration.setAutojoinEnabled(ewns.isAutojoinEnabled);
                 // Install Passpoint config, if failure, ignore that suggestion
                 if (!mWifiInjector.getPasspointManager().addOrUpdateProvider(
@@ -889,16 +935,6 @@
                 }
                 addToPasspointInfoMap(ewns);
             }
-            // If network has no IMSI protection and user didn't approve exemption, make it initial
-            // auto join disabled
-            if (isSimBasedSuggestion(ewns)) {
-                int subId = mTelephonyUtil.getMatchingSubId(getCarrierIdFromSuggestion(ewns));
-                if (!(mTelephonyUtil.requiresImsiEncryption(subId)
-                        || hasUserApprovedImsiPrivacyExemptionForCarrier(
-                                getCarrierIdFromSuggestion(ewns)))) {
-                    ewns.isAutojoinEnabled = false;
-                }
-            }
             perAppInfo.extNetworkSuggestions.remove(ewns);
             perAppInfo.extNetworkSuggestions.add(ewns);
         }
diff --git a/service/java/com/android/server/wifi/WifiShellCommand.java b/service/java/com/android/server/wifi/WifiShellCommand.java
index cbab50c..37f8d10 100644
--- a/service/java/com/android/server/wifi/WifiShellCommand.java
+++ b/service/java/com/android/server/wifi/WifiShellCommand.java
@@ -25,6 +25,8 @@
 import android.content.pm.ParceledListSlice;
 import android.net.ConnectivityManager;
 import android.net.MacAddress;
+import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.wifi.IActionListener;
 import android.net.wifi.ScanResult;
@@ -77,6 +79,7 @@
     // However, these do perform permission checks in the corresponding WifiService methods.
     private static final String[] NON_PRIVILEGED_COMMANDS = {
             "add-suggestion",
+            "add-network",
             "connect-network",
             "forget-network",
             "get-country-code",
@@ -410,6 +413,28 @@
                     countDownLatch.await(500, TimeUnit.MILLISECONDS);
                     break;
                 }
+                case "add-network": {
+                    CountDownLatch countDownLatch = new CountDownLatch(1);
+                    IActionListener.Stub actionListener = new IActionListener.Stub() {
+                        @Override
+                        public void onSuccess() throws RemoteException {
+                            pw.println("Save successful");
+                            countDownLatch.countDown();
+                        }
+
+                        @Override
+                        public void onFailure(int i) throws RemoteException {
+                            pw.println("Save failed");
+                            countDownLatch.countDown();
+                        }
+                    };
+                    mWifiService.save(
+                            buildWifiConfiguration(pw), new Binder(), actionListener,
+                            actionListener.hashCode());
+                    // wait for status.
+                    countDownLatch.await(500, TimeUnit.MILLISECONDS);
+                    break;
+                }
                 case "forget-network": {
                     String networkId = getNextArgRequired();
                     CountDownLatch countDownLatch = new CountDownLatch(1);
@@ -444,7 +469,11 @@
                     if (wifiEnabled) {
                         if (info.getSupplicantState() == SupplicantState.COMPLETED) {
                             pw.println("Wifi is connected to " + info.getSSID());
-                            pw.println("Connection Details: " + info);
+                            pw.println("WifiInfo: " + info);
+                            Network network = mWifiService.getCurrentNetwork();
+                            NetworkCapabilities capabilities =
+                                    mConnectivityManager.getNetworkCapabilities(network);
+                            pw.println("NetworkCapabilities: " + capabilities);
                         } else {
                             pw.println("Wifi is not connected");
                         }
@@ -762,7 +791,18 @@
         pw.println("  list-networks");
         pw.println("    Lists the saved networks");
         pw.println("  connect-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m]");
-        pw.println("    Connect to a network with provided params and save");
+        pw.println("    Connect to a network with provided params and add to saved networks list");
+        pw.println("    <ssid> - SSID of the network");
+        pw.println("    open|owe|wpa2|wpa3 - Security type of the network.");
+        pw.println("        - Use 'open' or 'owe' for networks with no passphrase");
+        pw.println("           - 'open' - Open networks (Most prevalent)");
+        pw.println("           - 'owe' - Enhanced open networks");
+        pw.println("        - Use 'wpa2' or 'wpa3' for networks with passphrase");
+        pw.println("           - 'wpa2' - WPA-2 PSK networks (Most prevalent)");
+        pw.println("           - 'wpa3' - WPA-3 PSK networks");
+        pw.println("    -m - Mark the network metered.");
+        pw.println("  add-network <ssid> open|owe|wpa2|wpa3 [<passphrase>] [-m]");
+        pw.println("    Add/update saved network with provided params");
         pw.println("    <ssid> - SSID of the network");
         pw.println("    open|owe|wpa2|wpa3 - Security type of the network.");
         pw.println("        - Use 'open' or 'owe' for networks with no passphrase");
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
index d3e405b..14f326e 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointManager.java
@@ -51,6 +51,7 @@
 import android.util.Pair;
 
 import com.android.server.wifi.Clock;
+import com.android.server.wifi.NetworkUpdateResult;
 import com.android.server.wifi.WifiConfigManager;
 import com.android.server.wifi.WifiConfigStore;
 import com.android.server.wifi.WifiInjector;
@@ -375,6 +376,30 @@
         }
     }
 
+    private void updateWifiConfigInWcmIfPresent(
+            WifiConfiguration newConfig, int uid, String packageName, boolean isFromSuggestion) {
+        WifiConfiguration configInWcm =
+                mWifiConfigManager.getConfiguredNetwork(newConfig.getKey());
+        if (configInWcm == null) return;
+        // suggestion != saved
+        if (isFromSuggestion != configInWcm.fromWifiNetworkSuggestion) return;
+        // is suggestion from same app.
+        if (isFromSuggestion
+                && (configInWcm.creatorUid != uid
+                || !TextUtils.equals(configInWcm.creatorName, packageName))) {
+            return;
+        }
+        NetworkUpdateResult result = mWifiConfigManager.addOrUpdateNetwork(
+                newConfig, uid, packageName);
+        if (!result.isSuccess()) {
+            Log.e(TAG, "Failed to update config in WifiConfigManager");
+        } else {
+            if (mVerboseLoggingEnabled) {
+                Log.v(TAG, "Updated config in WifiConfigManager");
+            }
+        }
+    }
+
     /**
      * Add or update a Passpoint provider with the given configuration.
      *
@@ -423,7 +448,7 @@
         if (mProviders.containsKey(config.getUniqueId())) {
             PasspointProvider old = mProviders.get(config.getUniqueId());
             // If new profile is from suggestion and from a different App, ignore new profile,
-            // return true.
+            // return false.
             // If from same app, update it.
             if (isFromSuggestion && !old.getPackageName().equals(packageName)) {
                 newProvider.uninstallCertsAndKeys();
@@ -437,6 +462,10 @@
             if (!old.equals(newProvider)) {
                 mWifiConfigManager.removePasspointConfiguredNetwork(
                         newProvider.getWifiConfig().getKey());
+            } else {
+                // If there is a config cached in WifiConfigManager, update it with new info.
+                updateWifiConfigInWcmIfPresent(
+                        newProvider.getWifiConfig(), uid, packageName, isFromSuggestion);
             }
         }
         newProvider.enableVerboseLogging(mVerboseLoggingEnabled ? 1 : 0);
diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkNominateHelper.java b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkNominateHelper.java
index 27c8331..22ce2f0 100644
--- a/service/java/com/android/server/wifi/hotspot2/PasspointNetworkNominateHelper.java
+++ b/service/java/com/android/server/wifi/hotspot2/PasspointNetworkNominateHelper.java
@@ -202,6 +202,8 @@
         }
 
         // Add or update with the newly created WifiConfiguration to WifiConfigManager.
+        // NOTE: if existingNetwork != null, this update is a no-op in most cases if the SSID is the
+        // same (since we update the cached config in PasspointManager#addOrUpdateProvider().
         NetworkUpdateResult result;
         if (config.fromWifiNetworkSuggestion) {
             result = mWifiConfigManager.addOrUpdateNetwork(
diff --git a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
index 1930cd1..448cee1 100644
--- a/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/ClientModeImplTest.java
@@ -16,6 +16,9 @@
 
 package com.android.server.wifi;
 
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_METERED;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NOT_METERED;
 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NONE;
 import static android.net.wifi.WifiConfiguration.NetworkSelectionStatus.DISABLED_NO_INTERNET_TEMPORARY;
 
@@ -47,6 +50,7 @@
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 import static org.mockito.Mockito.withSettings;
 
@@ -155,7 +159,6 @@
 import java.util.BitSet;
 import java.util.Collections;
 import java.util.List;
-import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
 import java.util.function.Consumer;
 
@@ -2418,11 +2421,8 @@
         assertFalse(mCmi.shouldEvaluateWhetherToSendExplicitlySelected(currentConfig));
     }
 
-    private void expectRegisterNetworkAgent() {
-        expectRegisterNetworkAgent((config) -> { });
-    }
-
-    private void expectRegisterNetworkAgent(Consumer<NetworkAgentConfig> configChecker) {
+    private void expectRegisterNetworkAgent(Consumer<NetworkAgentConfig> configChecker,
+            Consumer<NetworkCapabilities> networkCapabilitiesChecker) {
         // Expects that the code calls registerNetworkAgent and provides a way for the test to
         // verify the messages sent through the NetworkAgent to ConnectivityService.
         // We cannot just use a mock object here because mWifiNetworkAgent is private to CMI.
@@ -2430,23 +2430,34 @@
         ArgumentCaptor<Messenger> messengerCaptor = ArgumentCaptor.forClass(Messenger.class);
         ArgumentCaptor<NetworkAgentConfig> configCaptor =
                 ArgumentCaptor.forClass(NetworkAgentConfig.class);
+        ArgumentCaptor<NetworkCapabilities> networkCapabilitiesCaptor =
+                ArgumentCaptor.forClass(NetworkCapabilities.class);
         verify(mConnectivityManager).registerNetworkAgent(messengerCaptor.capture(),
-                any(NetworkInfo.class), any(LinkProperties.class), any(NetworkCapabilities.class),
+                any(NetworkInfo.class), any(LinkProperties.class),
+                networkCapabilitiesCaptor.capture(),
                 anyInt(), configCaptor.capture(), anyInt());
 
         registerAsyncChannel((x) -> {
             mNetworkAgentAsyncChannel = x;
         }, messengerCaptor.getValue(), mNetworkAgentHandler);
         configChecker.accept(configCaptor.getValue());
+        networkCapabilitiesChecker.accept(networkCapabilitiesCaptor.getValue());
 
         mNetworkAgentAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
         mLooper.dispatchAll();
     }
 
-    private void expectNetworkAgentMessage(int what, int arg1, int arg2, Object obj) {
-        verify(mNetworkAgentHandler).handleMessage(argThat(msg ->
-                what == msg.what && arg1 == msg.arg1 && arg2 == msg.arg2
-                && Objects.equals(obj, msg.obj)));
+    private void expectNetworkAgentUpdateCapabilities(
+            Consumer<NetworkCapabilities> networkCapabilitiesChecker) {
+        // We cannot just use a mock object here because mWifiNetworkAgent is private to CMI.
+        // TODO (b/134538181): consider exposing WifiNetworkAgent and using mocks.
+        ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
+        mLooper.dispatchAll();
+        verify(mNetworkAgentHandler).handleMessage(messageCaptor.capture());
+        Message message = messageCaptor.getValue();
+        assertNotNull(message);
+        assertEquals(NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED, message.what);
+        networkCapabilitiesChecker.accept((NetworkCapabilities) message.obj);
     }
 
     /**
@@ -2466,7 +2477,7 @@
             assertTrue(agentConfig.explicitlySelected);
             assertFalse(agentConfig.acceptUnvalidated);
             assertFalse(agentConfig.acceptPartialConnectivity);
-        });
+        }, (cap) -> { });
     }
 
     /**
@@ -2486,7 +2497,7 @@
             assertFalse(agentConfig.explicitlySelected);
             assertFalse(agentConfig.acceptUnvalidated);
             assertTrue(agentConfig.acceptPartialConnectivity);
-        });
+        }, (cap) -> { });
     }
 
     /**
@@ -2506,7 +2517,7 @@
             assertTrue(agentConfig.explicitlySelected);
             assertTrue(agentConfig.acceptUnvalidated);
             assertTrue(agentConfig.acceptPartialConnectivity);
-        });
+        }, (cap) -> { });
     }
 
     /**
@@ -4817,4 +4828,155 @@
         assertEquals(mConnectedNetwork.trusted, mCmi.getWifiInfo().isTrusted());
         assertEquals(mConnectedNetwork.osu, mCmi.getWifiInfo().isOsuAp());
     }
+
+    /**
+     * Verify that we disconnect when we mark a previous unmetered network metered.
+     */
+    @Test
+    public void verifyDisconnectOnMarkingNetworkMetered() throws Exception {
+        connect();
+        expectRegisterNetworkAgent((config) -> { }, (cap) -> {
+            assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+
+        WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
+
+        mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
+        mLooper.dispatchAll();
+        assertEquals("DisconnectingState", getCurrentState().getName());
+    }
+
+    /**
+     * Verify that we only update capabilites when we mark a previous unmetered network metered.
+     */
+    @Test
+    public void verifyUpdateCapabilitiesOnMarkingNetworkUnmetered() throws Exception {
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
+        connect();
+        expectRegisterNetworkAgent((config) -> { }, (cap) -> {
+            assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+        reset(mNetworkAgentHandler);
+
+        WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NOT_METERED;
+
+        mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
+        mLooper.dispatchAll();
+        assertEquals("ConnectedState", getCurrentState().getName());
+
+        expectNetworkAgentUpdateCapabilities((cap) -> {
+            assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+    }
+
+
+    /**
+     * Verify that we disconnect when we mark a previous unmetered network metered.
+     */
+    @Test
+    public void verifyDisconnectOnMarkingNetworkAutoMeteredWithMeteredHint() throws Exception {
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NOT_METERED;
+        connect();
+        expectRegisterNetworkAgent((config) -> { }, (cap) -> {
+            assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+        reset(mNetworkAgentHandler);
+
+        // Mark network metered none.
+        WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
+
+        // Set metered hint in WifiInfo (either via DHCP or ScanResult IE).
+        WifiInfo wifiInfo = mCmi.getWifiInfo();
+        wifiInfo.setMeteredHint(true);
+
+        mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
+        mLooper.dispatchAll();
+        assertEquals("DisconnectingState", getCurrentState().getName());
+    }
+
+    /**
+     * Verify that we only update capabilites when we mark a previous unmetered network metered.
+     */
+    @Test
+    public void verifyUpdateCapabilitiesOnMarkingNetworkAutoMeteredWithoutMeteredHint()
+            throws Exception {
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
+        connect();
+        expectRegisterNetworkAgent((config) -> { }, (cap) -> {
+            assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+        reset(mNetworkAgentHandler);
+
+        WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
+
+        // Reset metered hint in WifiInfo.
+        WifiInfo wifiInfo = mCmi.getWifiInfo();
+        wifiInfo.setMeteredHint(false);
+
+        mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
+        mLooper.dispatchAll();
+        assertEquals("ConnectedState", getCurrentState().getName());
+
+        expectNetworkAgentUpdateCapabilities((cap) -> {
+            assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+    }
+
+    /**
+     * Verify that we do nothing on no metered change.
+     */
+    @Test
+    public void verifyDoNothingMarkingNetworkAutoMeteredWithMeteredHint() throws Exception {
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_METERED;
+        connect();
+        expectRegisterNetworkAgent((config) -> { }, (cap) -> {
+            assertFalse(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+        reset(mNetworkAgentHandler);
+
+        // Mark network metered none.
+        WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
+
+        // Set metered hint in WifiInfo (either via DHCP or ScanResult IE).
+        WifiInfo wifiInfo = mCmi.getWifiInfo();
+        wifiInfo.setMeteredHint(true);
+
+        mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
+        mLooper.dispatchAll();
+        assertEquals("ConnectedState", getCurrentState().getName());
+
+        verifyNoMoreInteractions(mNetworkAgentHandler);
+    }
+
+    /**
+     * Verify that we do nothing on no metered change.
+     */
+    @Test
+    public void verifyDoNothingMarkingNetworkAutoMeteredWithoutMeteredHint() throws Exception {
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NOT_METERED;
+        connect();
+        expectRegisterNetworkAgent((config) -> { }, (cap) -> {
+            assertTrue(cap.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED));
+        });
+        reset(mNetworkAgentHandler);
+
+        // Mark network metered none.
+        WifiConfiguration oldConfig = new WifiConfiguration(mConnectedNetwork);
+        mConnectedNetwork.meteredOverride = METERED_OVERRIDE_NONE;
+
+        // Reset metered hint in WifiInfo.
+        WifiInfo wifiInfo = mCmi.getWifiInfo();
+        wifiInfo.setMeteredHint(false);
+
+        mConfigUpdateListenerCaptor.getValue().onNetworkUpdated(mConnectedNetwork, oldConfig);
+        mLooper.dispatchAll();
+        assertEquals("ConnectedState", getCurrentState().getName());
+
+        verifyNoMoreInteractions(mNetworkAgentHandler);
+    }
 }
diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
index 17bb4c1..f8084e3 100644
--- a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionNominatorTest.java
@@ -470,11 +470,6 @@
                 .isNetworkTemporarilyDisabledByUser(anyString());
         verify(mWifiConfigManager)
                 .getConfiguredNetwork(suggestions[0].wns.wifiConfiguration.getKey());
-        verify(mWifiConfigManager).addOrUpdateNetwork(
-                argThat(new WifiConfigMatcher(suggestions[0].wns.wifiConfiguration)),
-                eq(suggestions[0].perAppInfo.uid), eq(suggestions[0].perAppInfo.packageName));
-        verify(mWifiConfigManager).getConfiguredNetwork(
-                suggestions[0].wns.wifiConfiguration.networkId);
         // Verify we did not try to add any new networks or other interactions with
         // WifiConfigManager.
         verifyNoMoreInteractions(mWifiConfigManager);
@@ -586,11 +581,6 @@
                 .isNetworkTemporarilyDisabledByUser(anyString());
         verify(mWifiConfigManager).getConfiguredNetwork(eq(
                 suggestions[0].wns.wifiConfiguration.getKey()));
-        verify(mWifiConfigManager).addOrUpdateNetwork(
-                argThat(new WifiConfigMatcher(suggestions[0].wns.wifiConfiguration)),
-                eq(suggestions[0].perAppInfo.uid), eq(suggestions[0].perAppInfo.packageName));
-        verify(mWifiConfigManager).getConfiguredNetwork(
-                suggestions[0].wns.wifiConfiguration.networkId);
         verify(mWifiConfigManager).tryEnableNetwork(eq(
                 suggestions[0].wns.wifiConfiguration.networkId));
         // Verify we did not try to add any new networks or other interactions with
@@ -655,11 +645,6 @@
                 .isNetworkTemporarilyDisabledByUser(anyString());
         verify(mWifiConfigManager).getConfiguredNetwork(eq(
                 suggestions[0].wns.wifiConfiguration.getKey()));
-        verify(mWifiConfigManager).addOrUpdateNetwork(
-                argThat(new WifiConfigMatcher(suggestions[0].wns.wifiConfiguration)),
-                eq(suggestions[0].perAppInfo.uid), eq(suggestions[0].perAppInfo.packageName));
-        verify(mWifiConfigManager).getConfiguredNetwork(
-                suggestions[0].wns.wifiConfiguration.networkId);
         verify(mWifiConfigManager).tryEnableNetwork(eq(
                 suggestions[0].wns.wifiConfiguration.networkId));
         // Verify we did not try to add any new networks or other interactions with
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
index a892831..e6741d0 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java
@@ -507,7 +507,7 @@
         // Now change BSSID for the network.
         assertAndSetNetworkBSSID(openNetwork, TEST_BSSID);
         // Change the trusted bit.
-        openNetwork.trusted = true;
+        openNetwork.trusted = false;
         verifyUpdateNetworkToWifiConfigManagerWithoutIpChange(openNetwork);
 
         // Now verify that the modification has been effective.
@@ -515,8 +515,16 @@
                 mWifiConfigManager.getConfiguredNetworksWithPasswords();
         WifiConfigurationTestUtil.assertConfigurationsEqualForConfigManagerAddOrUpdate(
                 networks, retrievedNetworks);
-        verify(mWcmListener).onNetworkUpdated(wifiConfigCaptor.capture());
-        assertEquals(openNetwork.networkId, wifiConfigCaptor.getValue().networkId);
+        verify(mWcmListener).onNetworkUpdated(
+                wifiConfigCaptor.capture(), wifiConfigCaptor.capture());
+        WifiConfiguration newConfig = wifiConfigCaptor.getAllValues().get(1);
+        WifiConfiguration oldConfig = wifiConfigCaptor.getAllValues().get(0);
+        assertEquals(openNetwork.networkId, newConfig.networkId);
+        assertFalse(newConfig.trusted);
+        assertEquals(TEST_BSSID, newConfig.BSSID);
+        assertEquals(openNetwork.networkId, oldConfig.networkId);
+        assertTrue(oldConfig.trusted);
+        assertNull(oldConfig.BSSID);
     }
 
     /**
diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
index bb090ca..9048cb0 100644
--- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkSuggestionsManagerTest.java
@@ -106,6 +106,7 @@
  */
 @SmallTest
 public class WifiNetworkSuggestionsManagerTest extends WifiBaseTest {
+
     private static final String TEST_PACKAGE_1 = "com.test12345";
     private static final String TEST_PACKAGE_2 = "com.test54321";
     private static final String TEST_APP_NAME_1 = "test12345";
@@ -516,7 +517,7 @@
      * Verify that modify networks that are already active is allowed.
      */
     @Test
-    public void testAddNetworkSuggestionsSuccessOnInPlaceModification() {
+    public void testAddNetworkSuggestionsSuccessOnInPlaceModificationWhenNotInWcm() {
         WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
                 WifiConfigurationTestUtil.createOpenNetwork(), null, false, false, true, true);
         List<WifiNetworkSuggestion> networkSuggestionList1 =
@@ -528,7 +529,15 @@
                 mWifiNetworkSuggestionsManager.add(networkSuggestionList1, TEST_UID_1,
                         TEST_PACKAGE_1, TEST_FEATURE));
 
-        // Modify the original suggestion.
+        // Assert that the original config was not metered.
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+                networkSuggestion.wifiConfiguration.meteredOverride);
+
+        // Nothing in WCM.
+        when(mWifiConfigManager.getConfiguredNetwork(networkSuggestion.wifiConfiguration.getKey()))
+                .thenReturn(null);
+
+        // Modify the original suggestion to mark it metered.
         networkSuggestion.wifiConfiguration.meteredOverride =
                 WifiConfiguration.METERED_OVERRIDE_METERED;
 
@@ -539,6 +548,61 @@
         assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
                 mWifiNetworkSuggestionsManager
                         .get(TEST_PACKAGE_1).get(0).wifiConfiguration.meteredOverride);
+        // Verify we did not update config in WCM.
+        verify(mWifiConfigManager, never()).addOrUpdateNetwork(any(), anyInt(), any());
+    }
+
+    /**
+     * Verify that modify networks that are already active and is cached in WifiConfigManager is
+     * allowed and also updates the cache in WifiConfigManager.
+     */
+    @Test
+    public void testAddNetworkSuggestionsSuccessOnInPlaceModificationWhenInWcm() {
+        WifiNetworkSuggestion networkSuggestion = new WifiNetworkSuggestion(
+                WifiConfigurationTestUtil.createOpenNetwork(), null, false, false, true, true);
+        List<WifiNetworkSuggestion> networkSuggestionList1 =
+                new ArrayList<WifiNetworkSuggestion>() {{
+                    add(networkSuggestion);
+                }};
+
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList1, TEST_UID_1,
+                        TEST_PACKAGE_1, TEST_FEATURE));
+
+        // Assert that the original config was not metered.
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_NONE,
+                networkSuggestion.wifiConfiguration.meteredOverride);
+
+        // Store the original WifiConfiguration from WifiConfigManager.
+        WifiConfiguration configInWcm =
+                new WifiConfiguration(networkSuggestion.wifiConfiguration);
+        configInWcm.creatorUid = TEST_UID_1;
+        configInWcm.creatorName = TEST_PACKAGE_1;
+        configInWcm.fromWifiNetworkSuggestion = true;
+        setupGetConfiguredNetworksFromWcm(configInWcm);
+
+        // Modify the original suggestion to mark it metered.
+        networkSuggestion.wifiConfiguration.meteredOverride =
+                WifiConfiguration.METERED_OVERRIDE_METERED;
+
+        when(mWifiConfigManager.addOrUpdateNetwork(any(), eq(TEST_UID_1), eq(TEST_PACKAGE_1)))
+                .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID));
+        // Replace attempt should success.
+        assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
+                mWifiNetworkSuggestionsManager.add(networkSuggestionList1, TEST_UID_1,
+                        TEST_PACKAGE_1, TEST_FEATURE));
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
+                mWifiNetworkSuggestionsManager
+                        .get(TEST_PACKAGE_1).get(0).wifiConfiguration.meteredOverride);
+
+        // Verify we did update config in WCM.
+        ArgumentCaptor<WifiConfiguration> configCaptor =
+                ArgumentCaptor.forClass(WifiConfiguration.class);
+        verify(mWifiConfigManager).addOrUpdateNetwork(
+                configCaptor.capture(), eq(TEST_UID_1), eq(TEST_PACKAGE_1));
+        assertNotNull(configCaptor.getValue());
+        assertEquals(WifiConfiguration.METERED_OVERRIDE_METERED,
+                configCaptor.getValue().meteredOverride);
     }
 
     /**
@@ -3004,11 +3068,11 @@
                     add(networkSuggestion2);
                     add(networkSuggestion3);
                 }};
-        setupAddToWifiConfigManager(networkSuggestion1.wifiConfiguration,
-                networkSuggestion2.wifiConfiguration, networkSuggestion3.wifiConfiguration);
         assertEquals(WifiManager.STATUS_NETWORK_SUGGESTIONS_SUCCESS,
                 mWifiNetworkSuggestionsManager.add(networkSuggestionList, TEST_UID_1,
                         TEST_PACKAGE_1, TEST_FEATURE));
+        setupGetConfiguredNetworksFromWcm(networkSuggestion1.wifiConfiguration,
+                networkSuggestion2.wifiConfiguration, networkSuggestion3.wifiConfiguration);
         // When app is not approved, empty list will be returned
         mWifiNetworkSuggestionsManager.setHasUserApprovedForApp(false, TEST_PACKAGE_1);
         List<WifiConfiguration> wifiConfigurationList = mWifiNetworkSuggestionsManager
@@ -3029,20 +3093,9 @@
         assertEquals(expectedSuggestions, actualSuggestions);
     }
 
-    private void setupAddToWifiConfigManager(WifiConfiguration...configs) {
+    private void setupGetConfiguredNetworksFromWcm(WifiConfiguration...configs) {
         for (int i = 0; i < configs.length; i++) {
             WifiConfiguration config = configs[i];
-            config.fromWifiNetworkSuggestion = true;
-            config.ephemeral = true;
-            // setup & verify the WifiConfigmanager interactions for adding/enabling the network.
-            when(mWifiConfigManager.addOrUpdateNetwork(
-                    eq(config), anyInt(), anyString()))
-                    .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID + i));
-            when(mWifiConfigManager.updateNetworkSelectionStatus(eq(TEST_NETWORK_ID + i), anyInt()))
-                    .thenReturn(true);
-            config.networkId = TEST_NETWORK_ID + i;
-            when(mWifiConfigManager.getConfiguredNetwork(TEST_NETWORK_ID + i))
-                    .thenReturn(config);
             when(mWifiConfigManager.getConfiguredNetwork(config.getKey())).thenReturn(config);
         }
     }
diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
index 98dbcb9..3f92809 100644
--- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
+++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointManagerTest.java
@@ -32,6 +32,7 @@
 import static android.net.wifi.WifiManager.EXTRA_URL;
 
 import static com.android.server.wifi.WifiConfigurationTestUtil.SECURITY_EAP;
+import static com.android.server.wifi.WifiConfigurationTestUtil.TEST_NETWORK_ID;
 
 import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
 import static org.junit.Assert.assertEquals;
@@ -39,6 +40,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.anyBoolean;
@@ -88,6 +90,7 @@
 import com.android.server.wifi.Clock;
 import com.android.server.wifi.FakeKeys;
 import com.android.server.wifi.FrameworkFacade;
+import com.android.server.wifi.NetworkUpdateResult;
 import com.android.server.wifi.WifiBaseTest;
 import com.android.server.wifi.WifiConfigManager;
 import com.android.server.wifi.WifiConfigStore;
@@ -887,6 +890,27 @@
         assertEquals(origConfig, origProviders.get(0).getConfig());
         assertEquals(1, mSharedDataSource.getProviderIndex());
 
+        // Add same provider as existing suggestion provider
+        // This should be no WifiConfig deletion
+        WifiConfiguration origWifiConfig = origProvider.getWifiConfig();
+        when(mWifiConfigManager.getConfiguredNetwork(origWifiConfig.getKey()))
+                .thenReturn(origWifiConfig);
+        when(mWifiConfigManager.addOrUpdateNetwork(
+                origWifiConfig, TEST_CREATOR_UID, TEST_PACKAGE))
+                .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID));
+        assertTrue(mManager.addOrUpdateProvider(origConfig, TEST_CREATOR_UID, TEST_PACKAGE,
+                false, true));
+        verify(mWifiConfigManager, never()).removePasspointConfiguredNetwork(
+                origWifiConfig.getKey());
+        verify(mWifiConfigManager).addOrUpdateNetwork(
+                argThat((c) -> c.FQDN.equals(TEST_FQDN)), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE));
+        verify(mWifiConfigManager).saveToStore(true);
+        verify(mWifiMetrics).incrementNumPasspointProviderInstallation();
+        verify(mWifiMetrics).incrementNumPasspointProviderInstallSuccess();
+        assertEquals(2, mSharedDataSource.getProviderIndex());
+        reset(mWifiMetrics);
+        reset(mWifiConfigManager);
+
         // Add another provider with the same base domain as the existing provider.
         // This should replace the existing provider with the new configuration.
         PasspointConfiguration newConfig = createTestConfigWithUserCredential(TEST_FQDN,
@@ -895,6 +919,8 @@
         when(mObjectFactory.makePasspointProvider(eq(newConfig), eq(mWifiKeyStore),
                 eq(mTelephonyUtil), anyLong(), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE),
                 eq(false))).thenReturn(newProvider);
+        when(mWifiConfigManager.getConfiguredNetwork(origProvider.getWifiConfig().getKey()))
+                .thenReturn(origWifiConfig);
         assertTrue(mManager.addOrUpdateProvider(newConfig, TEST_CREATOR_UID, TEST_PACKAGE,
                 false, true));
 
@@ -913,7 +939,7 @@
         assertEquals(2, newProviders.size());
         assertTrue(newConfig.equals(newProviders.get(0).getConfig())
                 || newConfig.equals(newProviders.get(1).getConfig()));
-        assertEquals(2, mSharedDataSource.getProviderIndex());
+        assertEquals(3, mSharedDataSource.getProviderIndex());
     }
 
     /**
@@ -2064,10 +2090,21 @@
 
         // Add same provider as existing suggestion provider
         // This should be no WifiConfig deletion
+        WifiConfiguration origWifiConfig = origProvider.getWifiConfig();
+        origWifiConfig.fromWifiNetworkSuggestion = true;
+        origWifiConfig.creatorUid = TEST_CREATOR_UID;
+        origWifiConfig.creatorName = TEST_PACKAGE;
+        when(mWifiConfigManager.getConfiguredNetwork(origWifiConfig.getKey()))
+                .thenReturn(origWifiConfig);
+        when(mWifiConfigManager.addOrUpdateNetwork(
+                origWifiConfig, TEST_CREATOR_UID, TEST_PACKAGE))
+                .thenReturn(new NetworkUpdateResult(TEST_NETWORK_ID));
         assertTrue(mManager.addOrUpdateProvider(origConfig, TEST_CREATOR_UID, TEST_PACKAGE,
                 true, true));
         verify(mWifiConfigManager, never()).removePasspointConfiguredNetwork(
-                origProvider.getWifiConfig().getKey());
+                origWifiConfig.getKey());
+        verify(mWifiConfigManager).addOrUpdateNetwork(
+                argThat((c) -> c.FQDN.equals(TEST_FQDN)), eq(TEST_CREATOR_UID), eq(TEST_PACKAGE));
         verify(mWifiConfigManager).saveToStore(true);
         verify(mWifiMetrics).incrementNumPasspointProviderInstallation();
         verify(mWifiMetrics).incrementNumPasspointProviderInstallSuccess();