Merge changes Ie756b9aa,I38110f3a am: 87bf9bc09c am: c823b4d1b5

Change-Id: I884650a0a0fbf1a96f81ca927886eb2a563f4e28
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0ad275f..753c117 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6464,20 +6464,77 @@
                    newNetwork.name(), score, newNetwork.getCurrentScore()));
         }
 
+        // Notify requested networks are available after the default net is switched, but
+        // before LegacyTypeTracker sends legacy broadcasts
+        for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
+
         // Second pass: process all listens.
         if (wasBackgroundNetwork != newNetwork.isBackgroundNetwork()) {
-            // If the network went from background to foreground or vice versa, we need to update
-            // its foreground state. It is safe to do this after rematching the requests because
-            // NET_CAPABILITY_FOREGROUND does not affect requests, as is not a requestable
-            // capability and does not affect the network's score (see the Slog.wtf call above).
-            updateCapabilities(score, newNetwork, newNetwork.networkCapabilities);
+            // TODO : most of the following is useless because the only thing that changed
+            // here is whether the network is a background network. Clean this up.
+
+            NetworkCapabilities newNc = mixInCapabilities(newNetwork,
+                    newNetwork.networkCapabilities);
+
+            if (Objects.equals(newNetwork.networkCapabilities, newNc)) return;
+
+            final int oldPermission = getNetworkPermission(newNetwork.networkCapabilities);
+            final int newPermission = getNetworkPermission(newNc);
+            if (oldPermission != newPermission && newNetwork.created && !newNetwork.isVPN()) {
+                try {
+                    mNMS.setNetworkPermission(newNetwork.network.netId, newPermission);
+                } catch (RemoteException e) {
+                    loge("Exception in setNetworkPermission: " + e);
+                }
+            }
+
+            final NetworkCapabilities prevNc;
+            synchronized (newNetwork) {
+                prevNc = newNetwork.networkCapabilities;
+                newNetwork.setNetworkCapabilities(newNc);
+            }
+
+            updateUids(newNetwork, prevNc, newNc);
+
+            if (newNetwork.getCurrentScore() == score
+                    && newNc.equalRequestableCapabilities(prevNc)) {
+                // If the requestable capabilities haven't changed, and the score hasn't changed,
+                // then the change we're processing can't affect any requests, it can only affect
+                // the listens on this network.
+                processListenRequests(newNetwork, true);
+            } else {
+                rematchAllNetworksAndRequests();
+                notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_CAP_CHANGED);
+            }
+
+            if (prevNc != null) {
+                final boolean oldMetered = prevNc.isMetered();
+                final boolean newMetered = newNc.isMetered();
+                final boolean meteredChanged = oldMetered != newMetered;
+
+                if (meteredChanged) {
+                    maybeNotifyNetworkBlocked(newNetwork, oldMetered, newMetered,
+                            mRestrictBackground, mRestrictBackground);
+                }
+
+                final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING)
+                        != newNc.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+
+                // Report changes that are interesting for network statistics tracking.
+                if (meteredChanged || roamingChanged) {
+                    notifyIfacesChangedForNetworkStats();
+                }
+            }
+
+            if (!newNc.hasTransport(TRANSPORT_VPN)) {
+                // Tell VPNs about updated capabilities, since they may need to
+                // bubble those changes through.
+                updateAllVpnsCapabilities();
+            }
+
         } else {
             processListenRequests(newNetwork, false);
         }
-
-        // do this after the default net is switched, but
-        // before LegacyTypeTracker sends legacy broadcasts
-        for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
     }
 
     /**
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index fd3ed7d..a24426b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -3134,14 +3134,11 @@
                 .addTransportType(TRANSPORT_CELLULAR).build();
         final TestNetworkCallback cellCallback = new TestNetworkCallback();
         mCm.requestNetwork(cellRequest, cellCallback);
-        // NOTE: This request causes the network's capabilities to change. This
-        // is currently delivered before the onAvailable() callbacks.
-        // TODO: Fix this.
-        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         cellCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         fgCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
         // Expect a network capabilities update with FOREGROUND, because the most recent
         // request causes its state to change.
+        cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
         assertTrue(isForegroundNetwork(mCellNetworkAgent));
         assertTrue(isForegroundNetwork(mWiFiNetworkAgent));