Merge changes Icb062ffb,I66c4e8f5,I85247411,Id47c19b7,Ib713c4ae, ...
* changes:
[NS A36] Add a test for lost trusted capability
[NS A35] Send updated scores to factories at the end.
[NS A34] Still more simplification
[NS A33] Unify changing the default network
[NS A32] More simplification
[NS A31] Simplification
[NS A30] Note linger out of the rematch loop
[NS A29] Call LOST callbacks at the end of the rematch.
[NS A28] Move setting the default network out of the rematch loop.
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index 59e5a64..a6b345f 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -36,4 +36,12 @@
return (b != null) ? -1 : 0;
}
}
+
+ /**
+ * Returns its first argument if non-null, and the second otherwise.
+ */
+ @Nullable
+ public static <T> T getOrElse(@Nullable final T object, @Nullable final T otherwise) {
+ return null != object ? object : otherwise;
+ }
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4b9925f..0e17b23 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6197,12 +6197,16 @@
}
}
- private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, NetworkAgentInfo nai) {
- int score = 0;
- int serial = 0;
+ private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest,
+ @Nullable NetworkAgentInfo nai) {
+ final int score;
+ final int serial;
if (nai != null) {
score = nai.getCurrentScore();
serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = 0;
}
if (VDBG || DDBG){
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
@@ -6365,20 +6369,28 @@
}
}
- private void makeDefault(@NonNull final NetworkAgentInfo newNetwork) {
+ private void makeDefault(@Nullable final NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
+ mDefaultNetworkNai = newNetwork;
+
try {
- mNMS.setDefaultNetId(newNetwork.network.netId);
+ if (null != newNetwork) {
+ mNMS.setDefaultNetId(newNetwork.network.netId);
+ } else {
+ mNMS.clearDefaultNetId();
+ }
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
- mDefaultNetworkNai = newNetwork;
notifyLockdownVpn(newNetwork);
- handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
- updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
- mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+ handleApplyDefaultProxy(null != newNetwork
+ ? newNetwork.linkProperties.getHttpProxy() : null);
+ updateTcpBufferSizes(null != newNetwork
+ ? newNetwork.linkProperties.getTcpBufferSizes() : null);
+ mDnsManager.setDefaultDnsSystemProperties(null != newNetwork
+ ? newNetwork.linkProperties.getDnsServers() : Collections.EMPTY_LIST);
notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
updateAllVpnsCapabilities();
@@ -6457,6 +6469,16 @@
void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
mRematchedNetworks.add(network);
}
+
+ // Will return null if this reassignment does not change the network assigned to
+ // the passed request.
+ @Nullable
+ private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
+ for (final RequestReassignment event : getRequestReassignments()) {
+ if (nri == event.mRequest) return event;
+ }
+ return null;
+ }
}
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
@@ -6523,8 +6545,6 @@
@NonNull final NetworkAgentInfo newNetwork, final long now) {
ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
- boolean isNewDefault = false;
- NetworkAgentInfo oldDefaultNetwork = null;
changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
newNetwork.isBackgroundNetwork()));
@@ -6541,6 +6561,8 @@
final NetworkRequestInfo nri = entry.getKey();
final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
final NetworkAgentInfo newSatisfier = entry.getValue();
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, previousSatisfier, newSatisfier));
if (newSatisfier != null) {
if (VDBG) log("rematch for " + newSatisfier.name());
if (previousSatisfier != null) {
@@ -6553,25 +6575,9 @@
if (VDBG || DDBG) log(" accepting network in place of null");
}
newSatisfier.unlingerRequest(nri.request);
- nri.mSatisfier = newSatisfier;
if (!newSatisfier.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
}
- changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
- nri, previousSatisfier, newSatisfier));
- // Tell NetworkProviders about the new score, so they can stop
- // trying to connect if they know they cannot match it.
- // TODO - this could get expensive if we have a lot of requests for this
- // network. Think about if there is a way to reduce this. Push
- // netid->request mapping to each provider?
- sendUpdatedScoreToFactories(nri.request, newSatisfier);
- if (isDefaultRequest(nri)) {
- isNewDefault = true;
- oldDefaultNetwork = previousSatisfier;
- if (previousSatisfier != null) {
- mLingerMonitor.noteLingerDefaultNetwork(previousSatisfier, newSatisfier);
- }
- }
} else {
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
// mark it as no longer satisfying "nri". Because networks are processed by
@@ -6585,35 +6591,8 @@
" request " + nri.request.requestId);
}
newNetwork.removeRequest(nri.request.requestId);
- if (previousSatisfier == newNetwork) {
- nri.mSatisfier = null;
- if (isDefaultRequest(nri)) mDefaultNetworkNai = null;
- sendUpdatedScoreToFactories(nri.request, null);
- } else {
- Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
- newNetwork.name() +
- " without updating mSatisfier or providers!");
- }
- // TODO: Technically, sending CALLBACK_LOST here is
- // incorrect if there is a replacement network currently
- // connected that can satisfy nri, which is a request
- // (not a listen). However, the only capability that can both
- // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
- // so this code is only incorrect for a network that loses
- // the TRUSTED capability, which is a rare case.
- callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
}
- }
-
- if (isNewDefault) {
- updateDataActivityTracking(newNetwork, oldDefaultNetwork);
- // Notify system services that this network is up.
- makeDefault(newNetwork);
- // Log 0 -> X and Y -> X default network transitions, where X is the new default.
- mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
- now, newNetwork, oldDefaultNetwork);
- // Have a new default network, release the transition wakelock in
- scheduleReleaseNetworkTransitionWakelock();
+ nri.mSatisfier = newSatisfier;
}
}
@@ -6641,14 +6620,48 @@
rematchNetworkAndRequests(changes, nai, now);
}
- final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
+ final NetworkReassignment.RequestReassignment reassignment =
+ changes.getReassignment(defaultRequestInfo);
+ final NetworkAgentInfo newDefaultNetwork =
+ null != reassignment ? reassignment.mNewNetwork : oldDefaultNetwork;
+
+ if (oldDefaultNetwork != newDefaultNetwork) {
+ if (oldDefaultNetwork != null) {
+ mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
+ }
+ updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ // Notify system services of the new default.
+ makeDefault(newDefaultNetwork);
+ // Log 0 -> X and Y -> X default network transitions, where X is the new default.
+ mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
+ now, newDefaultNetwork, oldDefaultNetwork);
+ // Have a new default network, release the transition wakelock in
+ scheduleReleaseNetworkTransitionWakelock();
+ }
// Notify requested networks are available after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (final NetworkReassignment.RequestReassignment event :
changes.getRequestReassignments()) {
+ // Tell NetworkProviders about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
+ // TODO - this could get expensive if there are a lot of outstanding requests for this
+ // network. Think of a way to reduce this. Push netid->request mapping to each factory?
+ sendUpdatedScoreToFactories(event.mRequest.request, event.mNewNetwork);
+
if (null != event.mNewNetwork) {
notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ } else {
+ // TODO: Technically, sending CALLBACK_LOST here is
+ // incorrect if there is a replacement network currently
+ // connected that can satisfy nri, which is a request
+ // (not a listen). However, the only capability that can both
+ // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
+ // so this code is only incorrect for a network that loses
+ // the TRUSTED capability, which is a rare case.
+ callCallbackForRequest(event.mRequest, event.mOldNetwork,
+ ConnectivityManager.CALLBACK_LOST, 0);
}
}
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index 929dfc4..7071510 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -16,6 +16,10 @@
package com.android.server.connectivity;
+import static android.net.ConnectivityManager.NETID_UNSET;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -27,18 +31,16 @@
import android.text.format.DateUtils;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.SparseBooleanArray;
-import java.util.Arrays;
-import java.util.HashMap;
+import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.MessageUtils;
-import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import static android.net.ConnectivityManager.NETID_UNSET;
+import java.util.Arrays;
+import java.util.HashMap;
/**
* Class that monitors default network linger events and possibly notifies the user of network
@@ -206,8 +208,19 @@
mEverNotified.put(fromNai.network.netId, true);
}
+ /**
+ * Put up or dismiss a notification or toast for of a change in the default network if needed.
+ *
+ * Putting up a notification when switching from no network to some network is not supported
+ * and as such this method can't be called with a null |fromNai|. It can be called with a
+ * null |toNai| if there isn't a default network any more.
+ *
+ * @param fromNai switching from this NAI
+ * @param toNai switching to this NAI
+ */
// The default network changed from fromNai to toNai due to a change in score.
- public void noteLingerDefaultNetwork(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+ public void noteLingerDefaultNetwork(@NonNull final NetworkAgentInfo fromNai,
+ @Nullable final NetworkAgentInfo toNai) {
if (VDBG) {
Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.name() +
" everValidated=" + fromNai.everValidated +
@@ -221,6 +234,10 @@
// Internet access).
maybeStopNotifying(fromNai);
+ // If the network was simply lost (either because it disconnected or because it stopped
+ // being the default with no replacement), then don't show a notification.
+ if (null == toNai) return;
+
// If this network never validated, don't notify. Otherwise, we could do things like:
//
// 1. Unvalidated wifi connects.
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 50f1bbe..1442b31 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -5741,6 +5741,40 @@
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @Test
+ public final void testLoseTrusted() throws Exception {
+ final NetworkRequest trustedRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_TRUSTED)
+ .build();
+ final TestNetworkCallback trustedCallback = new TestNetworkCallback();
+ mCm.requestNetwork(trustedRequest, trustedCallback);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
+
+ mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ // There is currently a bug where losing the TRUSTED capability will send a LOST
+ // callback to requests before the available callback, in spite of the semantics
+ // of the requests dictating this should not happen. This is considered benign, but
+ // ideally should be fixed in the future.
+ trustedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
+
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ verify(mNetworkManagementService).clearDefaultNetId();
+
+ mCm.unregisterNetworkCallback(trustedCallback);
+ }
+
@Ignore // 40%+ flakiness : figure out why and re-enable.
@Test
public final void testBatteryStatsNetworkType() throws Exception {