Merge changes from topic "ifaceStatsDetail" into pi-dev
* changes:
Remove the unused file parsing function
Use eBPF map data for per iface stats
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index bd4a27c..227a4cb 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -228,7 +228,7 @@
* @param capability The capability to add to unwanted capability list.
* @return The builder to facilitate chaining.
*
- * @removed
+ * @hide
*/
public Builder addUnwantedCapability(@NetworkCapabilities.NetCapability int capability) {
mNetworkCapabilities.addUnwantedCapability(capability);
@@ -436,7 +436,7 @@
/**
* @see Builder#addUnwantedCapability(int)
*
- * @removed
+ * @hide
*/
public boolean hasUnwantedCapability(@NetCapability int capability) {
return networkCapabilities.hasUnwantedCapability(capability);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 5afb0a6..9994462 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -238,8 +238,9 @@
private KeyStore mKeyStore;
+ @VisibleForTesting
@GuardedBy("mVpns")
- private final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
+ protected final SparseArray<Vpn> mVpns = new SparseArray<Vpn>();
// TODO: investigate if mLockdownEnabled can be removed and replaced everywhere by
// a direct call to LockdownVpnTracker.isEnabled().
@@ -929,6 +930,15 @@
deps);
}
+ private static NetworkCapabilities createDefaultNetworkCapabilitiesForUid(int uid) {
+ final NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_RESTRICTED);
+ netCap.removeCapability(NET_CAPABILITY_NOT_VPN);
+ netCap.setSingleUid(uid);
+ return netCap;
+ }
+
private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
NetworkCapabilities netCap = new NetworkCapabilities();
@@ -1181,12 +1191,20 @@
int vpnNetId = NETID_UNSET;
synchronized (mVpns) {
final Vpn vpn = mVpns.get(user);
+ // TODO : now that capabilities contain the UID, the appliesToUid test should
+ // be removed as the satisfying test below should be enough.
if (vpn != null && vpn.appliesToUid(uid)) vpnNetId = vpn.getNetId();
}
NetworkAgentInfo nai;
if (vpnNetId != NETID_UNSET) {
nai = getNetworkAgentInfoForNetId(vpnNetId);
- if (nai != null) return nai.network;
+ if (nai != null) {
+ final NetworkCapabilities requiredCaps =
+ createDefaultNetworkCapabilitiesForUid(uid);
+ if (requiredCaps.satisfiedByNetworkCapabilities(nai.networkCapabilities)) {
+ return nai.network;
+ }
+ }
}
nai = getDefaultNetwork();
if (nai != null
@@ -1401,8 +1419,10 @@
private NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
NetworkCapabilities nc, int callerPid, int callerUid) {
final NetworkCapabilities newNc = new NetworkCapabilities(nc);
- if (!checkSettingsPermission(callerPid, callerUid)) newNc.setUids(null);
- if (!checkSettingsPermission(callerPid, callerUid)) newNc.setSSID(null);
+ if (!checkSettingsPermission(callerPid, callerUid)) {
+ newNc.setUids(null);
+ newNc.setSSID(null);
+ }
return newNc;
}
@@ -4304,8 +4324,7 @@
// the default network request. This allows callers to keep track of
// the system default network.
if (type == NetworkRequest.Type.TRACK_DEFAULT) {
- networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
- networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
+ networkCapabilities = createDefaultNetworkCapabilitiesForUid(Binder.getCallingUid());
enforceAccessPermission();
} else {
networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -4562,7 +4581,7 @@
// Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
private final NetworkRequest mDefaultRequest;
-
+
// Request used to optionally keep mobile data active even when higher
// priority networks like Wi-Fi are active.
private final NetworkRequest mDefaultMobileDataRequest;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index 7aaac06..d51a196 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -49,6 +49,7 @@
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -211,6 +212,8 @@
}
// Validation statuses of <hostname, ipAddress> pairs for a single netId
+ // Caution : not thread-safe. As mentioned in the top file comment, all
+ // methods of this class must only be called on ConnectivityService's thread.
private Map<Pair<String, InetAddress>, ValidationStatus> mValidationMap;
private PrivateDnsValidationStatuses() {
@@ -262,6 +265,16 @@
mValidationMap.put(p, ValidationStatus.FAILED);
}
}
+
+ private LinkProperties fillInValidatedPrivateDns(LinkProperties lp) {
+ lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
+ mValidationMap.forEach((key, value) -> {
+ if (value == ValidationStatus.SUCCEEDED) {
+ lp.addValidatedPrivateDnsServer(key.second);
+ }
+ });
+ return lp;
+ }
}
private final Context mContext;
@@ -315,23 +328,19 @@
PRIVATE_DNS_OFF);
final boolean useTls = privateDnsCfg.useTls;
+ final PrivateDnsValidationStatuses statuses =
+ useTls ? mPrivateDnsValidationMap.get(netId) : null;
+ final boolean validated = (null != statuses) && statuses.hasValidatedServer();
final boolean strictMode = privateDnsCfg.inStrictMode();
- final String tlsHostname = strictMode ? privateDnsCfg.hostname : "";
+ final String tlsHostname = strictMode ? privateDnsCfg.hostname : null;
+ final boolean usingPrivateDns = strictMode || validated;
- if (strictMode) {
- lp.setUsePrivateDns(true);
- lp.setPrivateDnsServerName(tlsHostname);
- } else if (useTls) {
- // We are in opportunistic mode. Private DNS should be used if there
- // is a known DNS-over-TLS validated server.
- boolean validated = mPrivateDnsValidationMap.containsKey(netId) &&
- mPrivateDnsValidationMap.get(netId).hasValidatedServer();
- lp.setUsePrivateDns(validated);
- lp.setPrivateDnsServerName(null);
+ lp.setUsePrivateDns(usingPrivateDns);
+ lp.setPrivateDnsServerName(tlsHostname);
+ if (usingPrivateDns && null != statuses) {
+ statuses.fillInValidatedPrivateDns(lp);
} else {
- // Private DNS is disabled.
- lp.setUsePrivateDns(false);
- lp.setPrivateDnsServerName(null);
+ lp.setValidatedPrivateDnsServers(Collections.EMPTY_LIST);
}
}
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
index 703b415..dec8ca2 100644
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -49,4 +49,14 @@
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
}
+
+ /**
+ * Returns true if the APF interpreter advertises support for the data buffer access opcodes
+ * LDDW and STDW.
+ *
+ * Full LDDW and STDW support is present from APFv4 on.
+ */
+ public boolean hasDataAccess() {
+ return apfVersionSupported >= 4;
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 482d6e1..5b73bba 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -84,6 +84,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.UserInfo;
import android.content.res.Resources;
import android.net.CaptivePortal;
import android.net.ConnectivityManager;
@@ -201,6 +202,7 @@
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
@Mock INetworkManagementService mNetworkManagementService;
@Mock INetworkStatsService mStatsService;
+ @Mock Vpn mMockVpn;
private ArgumentCaptor<String[]> mStringArrayCaptor = ArgumentCaptor.forClass(String[].class);
@@ -505,6 +507,7 @@
mWrappedNetworkMonitor.gen204ProbeResult = 204;
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(mNetworkCapabilities.getTransportTypes()[0])
+ .clearCapabilities()
.build();
callback = new NetworkCallback() {
public void onCapabilitiesChanged(Network network,
@@ -888,6 +891,15 @@
return mLastCreatedNetworkMonitor;
}
+ public void mockVpn(int uid) {
+ synchronized (mVpns) {
+ // This has no effect unless the VPN is actually connected, because things like
+ // getActiveNetworkForUidInternal call getNetworkAgentInfoForNetId on the VPN
+ // netId, and check if that network is actually connected.
+ mVpns.put(UserHandle.getUserId(Process.myUid()), mMockVpn);
+ }
+ }
+
public void waitForIdle(int timeoutMs) {
waitForIdleHandler(mHandlerThread, timeoutMs);
}
@@ -914,6 +926,7 @@
MockitoAnnotations.initMocks(this);
when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
+ when(mMockVpn.appliesToUid(Process.myUid())).thenReturn(true);
// InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
// http://b/25897652 .
@@ -935,6 +948,7 @@
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
mService.systemReady();
+ mService.mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
// Ensure that the default setting for Captive Portals is used for most tests
@@ -1347,6 +1361,7 @@
private final static int TIMEOUT_MS = 100;
private final LinkedBlockingQueue<CallbackInfo> mCallbacks = new LinkedBlockingQueue<>();
+ private Network mLastAvailableNetwork;
protected void setLastCallback(CallbackState state, Network network, Object o) {
mCallbacks.offer(new CallbackInfo(state, network, o));
@@ -1354,6 +1369,7 @@
@Override
public void onAvailable(Network network) {
+ mLastAvailableNetwork = network;
setLastCallback(CallbackState.AVAILABLE, network, null);
}
@@ -1389,9 +1405,14 @@
@Override
public void onLost(Network network) {
+ mLastAvailableNetwork = null;
setLastCallback(CallbackState.LOST, network, null);
}
+ public Network getLastAvailableNetwork() {
+ return mLastAvailableNetwork;
+ }
+
CallbackInfo nextCallback(int timeoutMs) {
CallbackInfo cb = null;
try {
@@ -1658,6 +1679,7 @@
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.connect(true);
// We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
@@ -1668,6 +1690,7 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.connect(true);
callback.expectAvailableCallbacksUnvalidated(mEthernetNetworkAgent);
@@ -1676,11 +1699,13 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
for (int i = 0; i < 4; i++) {
MockNetworkAgent oldNetwork, newNetwork;
@@ -1709,6 +1734,7 @@
defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
defaultCallback.assertNoCallback();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Wifi no longer satisfies our listen, which is for an unmetered network.
// But because its score is 55, it's still up (and the default network).
@@ -1718,8 +1744,11 @@
mWiFiNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(callback);
waitForIdle();
@@ -1736,6 +1765,7 @@
callback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
@@ -1744,12 +1774,14 @@
callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
// Cell is lingered because it would not satisfy any request, even if it validated.
@@ -1760,6 +1792,7 @@
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
@@ -1767,6 +1800,7 @@
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
@@ -1778,6 +1812,7 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
@@ -1786,12 +1821,15 @@
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
// If a network is lingering, and we add and remove a request from it, resume lingering.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
@@ -1799,6 +1837,7 @@
// TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -1815,6 +1854,7 @@
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Cell is now the default network. Pin it with a cell-specific request.
noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1825,6 +1865,7 @@
mWiFiNetworkAgent.connect(true);
callback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// The default request is lingering on cell, but nothing happens to cell, and we send no
// callbacks for it, because it's kept up by cellRequest.
callback.assertNoCallback();
@@ -1848,6 +1889,7 @@
callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
trackDefaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
defaultCallback.expectAvailableDoubleValidatedCallbacks(mEthernetNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Let linger run its course.
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent, lingerTimeoutMs);
@@ -2496,23 +2538,27 @@
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
cellNetworkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
// Bring down wifi. Expect the default network callback to notified of LOST wifi
// followed by AVAILABLE cell.
@@ -2523,6 +2569,23 @@
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
+
+ final int uid = Process.myUid();
+ final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);
+ vpnNetworkAgent.setUids(ranges);
+ vpnNetworkAgent.connect(true);
+ defaultNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ vpnNetworkAgent.disconnect();
+ defaultNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ waitForIdle();
+ assertEquals(null, mCm.getActiveNetwork());
}
@Test
@@ -4015,6 +4078,7 @@
final TestNetworkCallback genericNotVpnNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
final NetworkRequest genericNotVpnRequest = new NetworkRequest.Builder().build();
final NetworkRequest genericRequest = new NetworkRequest.Builder()
.removeCapability(NET_CAPABILITY_NOT_VPN).build();
@@ -4027,6 +4091,8 @@
mCm.registerNetworkCallback(genericNotVpnRequest, genericNotVpnNetworkCallback);
mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+ defaultCallback.assertNoCallback();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
@@ -4034,15 +4100,14 @@
genericNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
genericNotVpnNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
wifiNetworkCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
-
- // TODO : check callbacks agree with the return value of mCm.getActiveNetwork().
- // Right now this is not possible because establish() is not adequately instrumented
- // in this test.
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
final ArraySet<UidRange> ranges = new ArraySet<>();
ranges.add(new UidRange(uid, uid));
+ when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);
vpnNetworkAgent.setUids(ranges);
vpnNetworkAgent.connect(false);
@@ -4050,10 +4115,14 @@
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
genericNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
genericNotVpnNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCapabilitiesLike(nc -> null == nc.getUids(), vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
vpnNetworkAgent.setUids(ranges);
@@ -4063,6 +4132,14 @@
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ // TODO : The default network callback should actually get a LOST call here (also see the
+ // comment below for AVAILABLE). This is because ConnectivityService does not look at UID
+ // ranges at all when determining whether a network should be rematched. In practice, VPNs
+ // can't currently update their UIDs without disconnecting, so this does not matter too
+ // much, but that is the reason the test here has to check for an update to the
+ // capabilities instead of the expected LOST then AVAILABLE.
+ defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
+
ranges.add(new UidRange(uid, uid));
vpnNetworkAgent.setUids(ranges);
@@ -4070,6 +4147,9 @@
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ // TODO : Here like above, AVAILABLE would be correct, but because this can't actually
+ // happen outside of the test, ConnectivityService does not rematch callbacks.
+ defaultCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, vpnNetworkAgent);
mWiFiNetworkAgent.disconnect();
@@ -4077,6 +4157,7 @@
genericNotVpnNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
wifiNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
vpnNetworkCallback.assertNoCallback();
+ defaultCallback.assertNoCallback();
vpnNetworkAgent.disconnect();
@@ -4084,9 +4165,61 @@
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
vpnNetworkCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
mCm.unregisterNetworkCallback(wifiNetworkCallback);
mCm.unregisterNetworkCallback(vpnNetworkCallback);
+ mCm.unregisterNetworkCallback(defaultCallback);
+ }
+
+ @Test
+ public void testVpnWithAndWithoutInternet() {
+ final int uid = Process.myUid();
+
+ final TestNetworkCallback defaultCallback = new TestNetworkCallback();
+ mCm.registerDefaultNetworkCallback(defaultCallback);
+ defaultCallback.assertNoCallback();
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+
+ defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);
+ vpnNetworkAgent.setUids(ranges);
+ vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */);
+
+ defaultCallback.assertNoCallback();
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ vpnNetworkAgent.disconnect();
+ defaultCallback.assertNoCallback();
+
+ vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);
+ vpnNetworkAgent.setUids(ranges);
+ vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */);
+ defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
+
+ vpnNetworkAgent.disconnect();
+ defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent);
+ defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
+
+ vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN);
+ when(mMockVpn.getNetId()).thenReturn(vpnNetworkAgent.getNetwork().netId);
+ ranges.clear();
+ vpnNetworkAgent.setUids(ranges);
+
+ vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */);
+ defaultCallback.assertNoCallback();
+
+ mCm.unregisterNetworkCallback(defaultCallback);
}
}
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index bcd8bf3..1ec4eec 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -28,8 +28,11 @@
import android.content.ContentResolver;
import android.content.Context;
+import android.net.IpPrefix;
+import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.RouteInfo;
import android.os.INetworkManagementService;
import android.provider.Settings;
import android.support.test.filters.SmallTest;
@@ -40,6 +43,7 @@
import com.android.server.connectivity.MockableSystemProperties;
import java.net.InetAddress;
+import java.util.Arrays;
import org.junit.runner.RunWith;
import org.junit.Before;
@@ -56,6 +60,7 @@
@RunWith(AndroidJUnit4.class)
@SmallTest
public class DnsManagerTest {
+ static final String TEST_IFACENAME = "test_wlan0";
static final int TEST_NETID = 100;
static final int TEST_NETID_ALTERNATE = 101;
static final int TEST_NETID_UNTRACKED = 102;
@@ -92,6 +97,7 @@
mDnsManager.updatePrivateDns(new Network(TEST_NETID_ALTERNATE),
mDnsManager.getPrivateDnsConfig());
LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(TEST_IFACENAME);
lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
@@ -109,21 +115,51 @@
mDnsManager.updatePrivateDnsStatus(TEST_NETID_ALTERNATE, fixedLp);
assertTrue(fixedLp.isPrivateDnsActive());
assertNull(fixedLp.getPrivateDnsServerName());
+ assertEquals(Arrays.asList(InetAddress.getByName("4.4.4.4")),
+ fixedLp.getValidatedPrivateDnsServers());
- // Switch to strict mode
+ // Set up addresses for strict mode and switch to it.
+ lp.addLinkAddress(new LinkAddress("192.0.2.4/24"));
+ lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("192.0.2.4"),
+ TEST_IFACENAME));
+ lp.addLinkAddress(new LinkAddress("2001:db8:1::1/64"));
+ lp.addRoute(new RouteInfo((IpPrefix) null, InetAddress.getByName("2001:db8:1::1"),
+ TEST_IFACENAME));
+
Settings.Global.putString(mContentResolver,
- Settings.Global.PRIVATE_DNS_MODE,
- PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
+ Settings.Global.PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_PROVIDER_HOSTNAME);
Settings.Global.putString(mContentResolver,
Settings.Global.PRIVATE_DNS_SPECIFIER, "strictmode.com");
mDnsManager.updatePrivateDns(new Network(TEST_NETID),
- mDnsManager.getPrivateDnsConfig());
+ new DnsManager.PrivateDnsConfig("strictmode.com", new InetAddress[] {
+ InetAddress.parseNumericAddress("6.6.6.6"),
+ InetAddress.parseNumericAddress("2001:db8:66:66::1")
+ }));
mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT);
fixedLp = new LinkProperties(lp);
mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
assertTrue(fixedLp.isPrivateDnsActive());
assertEquals("strictmode.com", fixedLp.getPrivateDnsServerName());
+ // No validation events yet.
+ assertEquals(Arrays.asList(new InetAddress[0]), fixedLp.getValidatedPrivateDnsServers());
+ // Validate one.
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("6.6.6.6"), "strictmode.com", true));
fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+ assertEquals(Arrays.asList(InetAddress.parseNumericAddress("6.6.6.6")),
+ fixedLp.getValidatedPrivateDnsServers());
+ // Validate the 2nd one.
+ mDnsManager.updatePrivateDnsValidation(
+ new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
+ InetAddress.parseNumericAddress("2001:db8:66:66::1"), "strictmode.com", true));
+ fixedLp = new LinkProperties(lp);
+ mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
+ assertEquals(Arrays.asList(
+ InetAddress.parseNumericAddress("2001:db8:66:66::1"),
+ InetAddress.parseNumericAddress("6.6.6.6")),
+ fixedLp.getValidatedPrivateDnsServers());
}
@Test