summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Jeff Sharkey <jsharkey@android.com> 2017-10-27 17:22:59 -0600
committer Jeff Sharkey <jsharkey@android.com> 2017-11-01 19:05:42 -0600
commit72f9c42b9e59761a28d6b32c42f65de57c98daed (patch)
tree6d251e198355ecf7ac44781a287ca6ece2cb2827
parentc173c93c1ca84652a102ed12b95e0c3b5b63d69c (diff)
Define NOT_ROAMING network capability.
The "roaming" state of a network really belongs on NetworkCapabilities instead of being published through NetworkInfo.isRoaming(). One major reason is to support developers creating NetworkRequests for a non-roaming network. Watch for any capability changes that network statistics are interested in (either metered or roaming) and notify it to perform an update pass; fixes bug where we previously only triggered on roaming changes. Fix bug in VPNs where metered/roaming capabilities of underlying networks weren't being propagated; this was probably preventing some jobs from running over unmetered networks, and causing other jobs to run over roaming networks! Also passes along link bandwidth information from underlying networks, and propegates any changes to underlying networks. Fix race condition by reading prevNc inside lock. Utility methods correctly calculate min/max link bandwidth values. Test: bit FrameworksNetTests:android.net.,com.android.server.net.,com.android.server.connectivity.,com.android.server.ConnectivityServiceTest Bug: 68397798, 16207332 Change-Id: I3e1a6544c902bf3a79356b72d3616af1fd2b0f49
-rw-r--r--api/current.txt3
-rw-r--r--api/system-current.txt3
-rw-r--r--api/test-current.txt3
-rw-r--r--core/java/android/net/NetworkCapabilities.java119
-rw-r--r--core/java/android/net/NetworkIdentity.java4
-rw-r--r--core/java/android/net/NetworkInfo.java13
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java38
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java63
-rw-r--r--tests/net/java/android/net/NetworkCapabilitiesTest.java25
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java83
-rw-r--r--tests/net/java/com/android/server/connectivity/VpnTest.java101
-rw-r--r--tests/net/java/com/android/server/net/NetworkStatsServiceTest.java9
12 files changed, 405 insertions, 59 deletions
diff --git a/api/current.txt b/api/current.txt
index 3bff61f290e7..a8250e256c97 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -25691,6 +25691,7 @@ package android.net {
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -25721,7 +25722,7 @@ package android.net {
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
diff --git a/api/system-current.txt b/api/system-current.txt
index d2f919702217..3b0da5ee3438 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -27889,6 +27889,7 @@ package android.net {
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -27919,7 +27920,7 @@ package android.net {
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
diff --git a/api/test-current.txt b/api/test-current.txt
index d8a71a53ef2d..97bc448ba1bf 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -25801,6 +25801,7 @@ package android.net {
field public static final int NET_CAPABILITY_MMS = 0; // 0x0
field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
@@ -25831,7 +25832,7 @@ package android.net {
method public boolean isConnected();
method public boolean isConnectedOrConnecting();
method public boolean isFailover();
- method public boolean isRoaming();
+ method public deprecated boolean isRoaming();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index db12dd9724dc..ee75fd443052 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -17,6 +17,7 @@
package android.net;
import android.annotation.IntDef;
+import android.net.ConnectivityManager.NetworkCallback;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,15 +31,24 @@ import java.util.Objects;
import java.util.StringJoiner;
/**
- * This class represents the capabilities of a network. This is used both to specify
- * needs to {@link ConnectivityManager} and when inspecting a network.
- *
- * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method
- * of network selection. Rather than indicate a need for Wi-Fi because an application
- * needs high bandwidth and risk obsolescence when a new, fast network appears (like LTE),
- * the application should specify it needs high bandwidth. Similarly if an application
- * needs an unmetered network for a bulk transfer it can specify that rather than assuming
- * all cellular based connections are metered and all Wi-Fi based connections are not.
+ * Representation of the capabilities of a network. This object serves two
+ * purposes:
+ * <ul>
+ * <li>An expression of the current capabilities of an active network, typically
+ * expressed through
+ * {@link NetworkCallback#onCapabilitiesChanged(Network, NetworkCapabilities)}
+ * or {@link ConnectivityManager#getNetworkCapabilities(Network)}.
+ * <li>An expression of the future capabilities of a desired network, typically
+ * expressed through {@link NetworkRequest}.
+ * </ul>
+ * <p>
+ * This replaces the old {@link ConnectivityManager#TYPE_MOBILE} method of
+ * network selection. Rather than indicate a need for Wi-Fi because an
+ * application needs high bandwidth and risk obsolescence when a new, fast
+ * network appears (like LTE), the application should specify it needs high
+ * bandwidth. Similarly if an application needs an unmetered network for a bulk
+ * transfer it can specify that rather than assuming all cellular based
+ * connections are metered and all Wi-Fi based connections are not.
*/
public final class NetworkCapabilities implements Parcelable {
private static final String TAG = "NetworkCapabilities";
@@ -101,6 +111,7 @@ public final class NetworkCapabilities implements Parcelable {
NET_CAPABILITY_NOT_VPN,
NET_CAPABILITY_VALIDATED,
NET_CAPABILITY_CAPTIVE_PORTAL,
+ NET_CAPABILITY_NOT_ROAMING,
NET_CAPABILITY_FOREGROUND,
})
public @interface NetCapability { }
@@ -218,11 +229,16 @@ public final class NetworkCapabilities implements Parcelable {
public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
/**
+ * Indicates that this network is not roaming.
+ */
+ public static final int NET_CAPABILITY_NOT_ROAMING = 18;
+
+ /**
* Indicates that this network is available for use by apps, and not a network that is being
* kept up in the background to facilitate fast network switching.
* @hide
*/
- public static final int NET_CAPABILITY_FOREGROUND = 18;
+ public static final int NET_CAPABILITY_FOREGROUND = 19;
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_FOREGROUND;
@@ -237,6 +253,7 @@ public final class NetworkCapabilities implements Parcelable {
(1 << NET_CAPABILITY_TRUSTED) |
(1 << NET_CAPABILITY_VALIDATED) |
(1 << NET_CAPABILITY_CAPTIVE_PORTAL) |
+ (1 << NET_CAPABILITY_NOT_ROAMING) |
(1 << NET_CAPABILITY_FOREGROUND);
/**
@@ -316,6 +333,21 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets (or clears) the given capability on this {@link NetworkCapabilities}
+ * instance.
+ *
+ * @hide
+ */
+ public NetworkCapabilities setCapability(@NetCapability int capability, boolean value) {
+ if (value) {
+ addCapability(capability);
+ } else {
+ removeCapability(capability);
+ }
+ return this;
+ }
+
+ /**
* Gets all the capabilities set on this {@code NetworkCapability} instance.
*
* @return an array of capability values for this instance.
@@ -326,6 +358,15 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets all the capabilities set on this {@code NetworkCapability} instance.
+ *
+ * @hide
+ */
+ public void setCapabilities(@NetCapability int[] capabilities) {
+ mNetworkCapabilities = BitUtils.packBits(capabilities);
+ }
+
+ /**
* Tests for the presence of a capabilitity on this instance.
*
* @param capability the capabilities to be tested for.
@@ -515,6 +556,21 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets (or clears) the given transport on this {@link NetworkCapabilities}
+ * instance.
+ *
+ * @hide
+ */
+ public NetworkCapabilities setTransportType(@Transport int transportType, boolean value) {
+ if (value) {
+ addTransportType(transportType);
+ } else {
+ removeTransportType(transportType);
+ }
+ return this;
+ }
+
+ /**
* Gets all the transports set on this {@code NetworkCapability} instance.
*
* @return an array of transport type values for this instance.
@@ -525,6 +581,15 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Sets all the transports set on this {@code NetworkCapability} instance.
+ *
+ * @hide
+ */
+ public void setTransportTypes(@Transport int[] transportTypes) {
+ mTransportTypes = BitUtils.packBits(transportTypes);
+ }
+
+ /**
* Tests for the presence of a transport on this instance.
*
* @param transportType the transport type to be tested for.
@@ -549,12 +614,18 @@ public final class NetworkCapabilities implements Parcelable {
}
/**
+ * Value indicating that link bandwidth is unspecified.
+ * @hide
+ */
+ public static final int LINK_BANDWIDTH_UNSPECIFIED = 0;
+
+ /**
* Passive link bandwidth. This is a rough guide of the expected peak bandwidth
* for the first hop on the given transport. It is not measured, but may take into account
* link parameters (Radio technology, allocated channels, etc).
*/
- private int mLinkUpBandwidthKbps;
- private int mLinkDownBandwidthKbps;
+ private int mLinkUpBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
+ private int mLinkDownBandwidthKbps = LINK_BANDWIDTH_UNSPECIFIED;
/**
* Sets the upstream bandwidth for this network in Kbps. This always only refers to
@@ -571,8 +642,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param upKbps the estimated first hop upstream (device to network) bandwidth.
* @hide
*/
- public void setLinkUpstreamBandwidthKbps(int upKbps) {
+ public NetworkCapabilities setLinkUpstreamBandwidthKbps(int upKbps) {
mLinkUpBandwidthKbps = upKbps;
+ return this;
}
/**
@@ -600,8 +672,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param downKbps the estimated first hop downstream (network to device) bandwidth.
* @hide
*/
- public void setLinkDownstreamBandwidthKbps(int downKbps) {
+ public NetworkCapabilities setLinkDownstreamBandwidthKbps(int downKbps) {
mLinkDownBandwidthKbps = downKbps;
+ return this;
}
/**
@@ -628,6 +701,20 @@ public final class NetworkCapabilities implements Parcelable {
return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps &&
this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps);
}
+ /** @hide */
+ public static int minBandwidth(int a, int b) {
+ if (a == LINK_BANDWIDTH_UNSPECIFIED) {
+ return b;
+ } else if (b == LINK_BANDWIDTH_UNSPECIFIED) {
+ return a;
+ } else {
+ return Math.min(a, b);
+ }
+ }
+ /** @hide */
+ public static int maxBandwidth(int a, int b) {
+ return Math.max(a, b);
+ }
private NetworkSpecifier mNetworkSpecifier = null;
@@ -708,8 +795,9 @@ public final class NetworkCapabilities implements Parcelable {
* @param signalStrength the bearer-specific signal strength.
* @hide
*/
- public void setSignalStrength(int signalStrength) {
+ public NetworkCapabilities setSignalStrength(int signalStrength) {
mSignalStrength = signalStrength;
+ return this;
}
/**
@@ -968,6 +1056,7 @@ public final class NetworkCapabilities implements Parcelable {
case NET_CAPABILITY_NOT_VPN: return "NOT_VPN";
case NET_CAPABILITY_VALIDATED: return "VALIDATED";
case NET_CAPABILITY_CAPTIVE_PORTAL: return "CAPTIVE_PORTAL";
+ case NET_CAPABILITY_NOT_ROAMING: return "NOT_ROAMING";
case NET_CAPABILITY_FOREGROUND: return "FOREGROUND";
default: return Integer.toString(capability);
}
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index 0775bdaaf380..df404b7dce27 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -189,7 +189,8 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
String subscriberId = null;
String networkId = null;
- boolean roaming = false;
+ boolean roaming = !state.networkCapabilities.hasCapability(
+ NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
boolean metered = !state.networkCapabilities.hasCapability(
NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
@@ -203,7 +204,6 @@ public class NetworkIdentity implements Comparable<NetworkIdentity> {
}
subscriberId = state.subscriberId;
- roaming = state.networkInfo.isRoaming();
} else if (type == TYPE_WIFI) {
if (state.networkId != null) {
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index 84c32bec8ef7..d5549387755d 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -307,11 +307,17 @@ public class NetworkInfo implements Parcelable {
}
/**
- * Indicates whether the device is currently roaming on this network.
- * When {@code true}, it suggests that use of data on this network
- * may incur extra costs.
+ * Indicates whether the device is currently roaming on this network. When
+ * {@code true}, it suggests that use of data on this network may incur
+ * extra costs.
+ *
* @return {@code true} if roaming is in effect, {@code false} otherwise.
+ * @deprecated Callers should switch to checking
+ * {@link NetworkCapabilities#NET_CAPABILITY_NOT_ROAMING}
+ * instead, since that handles more complex situations, such as
+ * VPNs.
*/
+ @Deprecated
public boolean isRoaming() {
synchronized (this) {
return mIsRoaming;
@@ -320,6 +326,7 @@ public class NetworkInfo implements Parcelable {
/** {@hide} */
@VisibleForTesting
+ @Deprecated
public void setRoaming(boolean isRoaming) {
synchronized (this) {
mIsRoaming = isRoaming;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 25c96d14e9ad..708bcdde2c86 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,7 +29,10 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+
import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
@@ -71,6 +74,7 @@ import android.net.ProxyInfo;
import android.net.RouteInfo;
import android.net.UidRange;
import android.net.Uri;
+import android.net.VpnService;
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.util.MultinetworkPolicyTracker;
@@ -4664,10 +4668,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- final NetworkCapabilities prevNc = nai.networkCapabilities;
+ final NetworkCapabilities prevNc;
synchronized (nai) {
+ prevNc = nai.networkCapabilities;
nai.networkCapabilities = networkCapabilities;
}
+
if (nai.getCurrentScore() == oldScore &&
networkCapabilities.equalRequestableCapabilities(prevNc)) {
// If the requestable capabilities haven't changed, and the score hasn't changed, then
@@ -4681,6 +4687,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
rematchAllNetworksAndRequests(nai, oldScore);
notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
+
+ // Report changes that are interesting for network statistics tracking.
+ if (prevNc != null) {
+ final boolean meteredChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_METERED) !=
+ networkCapabilities.hasCapability(NET_CAPABILITY_NOT_METERED);
+ final boolean roamingChanged = prevNc.hasCapability(NET_CAPABILITY_NOT_ROAMING) !=
+ networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ if (meteredChanged || roamingChanged) {
+ notifyIfacesChangedForNetworkStats();
+ }
+ }
+
+ if (!networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+ // Tell VPNs about updated capabilities, since they may need to
+ // bubble those changes through.
+ synchronized (mVpns) {
+ for (int i = 0; i < mVpns.size(); i++) {
+ final Vpn vpn = mVpns.valueAt(i);
+ vpn.updateCapabilities();
+ }
+ }
+ }
}
public void handleUpdateLinkProperties(NetworkAgentInfo nai, LinkProperties newLp) {
@@ -5214,14 +5242,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
notifyLockdownVpn(networkAgent);
- if (oldInfo != null && oldInfo.getState() == state) {
- if (oldInfo.isRoaming() != newInfo.isRoaming()) {
- if (VDBG) log("roaming status changed, notifying NetworkStatsService");
- notifyIfacesChangedForNetworkStats();
- } else if (VDBG) log("ignoring duplicate network state non-change");
- // In either case, no further work should be needed.
- return;
- }
if (DBG) {
log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " +
(oldInfo == null ? "null" : oldInfo.getState()) +
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index a44b18dc2d8c..7715727f6d73 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -18,6 +18,8 @@ package com.android.server.connectivity;
import static android.Manifest.permission.BIND_VPN_SERVICE;
import static android.net.ConnectivityManager.NETID_UNSET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.RouteInfo.RTN_THROW;
import static android.net.RouteInfo.RTN_UNREACHABLE;
@@ -90,6 +92,8 @@ import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
import com.android.internal.notification.SystemNotificationChannels;
+import com.android.internal.util.ArrayUtils;
+import com.android.server.ConnectivityService;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -245,10 +249,10 @@ public class Vpn {
}
mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
- // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
mNetworkCapabilities = new NetworkCapabilities();
mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN);
mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN);
+ updateCapabilities();
loadAlwaysOnPackage();
}
@@ -275,6 +279,62 @@ public class Vpn {
updateAlwaysOnNotification(detailedState);
}
+ public void updateCapabilities() {
+ final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null;
+ updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks,
+ mNetworkCapabilities);
+
+ if (mNetworkAgent != null) {
+ mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities);
+ }
+ }
+
+ @VisibleForTesting
+ public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks,
+ NetworkCapabilities caps) {
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = false;
+ boolean roaming = false;
+
+ if (ArrayUtils.isEmpty(underlyingNetworks)) {
+ // No idea what the underlying networks are; assume sane defaults
+ metered = true;
+ roaming = false;
+ } else {
+ for (Network underlying : underlyingNetworks) {
+ final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying);
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
+
+ // When we have multiple networks, we have to assume the
+ // worst-case link speed and restrictions.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ if (metered) {
+ caps.removeCapability(NET_CAPABILITY_NOT_METERED);
+ } else {
+ caps.addCapability(NET_CAPABILITY_NOT_METERED);
+ }
+ if (roaming) {
+ caps.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ } else {
+ caps.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ }
+ }
+
/**
* Chooses whether to force all connections to go though VPN.
*
@@ -1344,6 +1404,7 @@ public class Vpn {
}
}
}
+ updateCapabilities();
return true;
}
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
index 7346f9f95041..cd2d0985c793 100644
--- a/tests/net/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -16,6 +16,7 @@
package android.net;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
@@ -26,13 +27,12 @@ import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
-
-import android.net.NetworkCapabilities;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
@@ -159,4 +159,25 @@ public class NetworkCapabilitiesTest {
assertNotEquals("", nc1.describeImmutableDifferences(nc2));
assertEquals("", nc1.describeImmutableDifferences(nc1));
}
+
+ @Test
+ public void testLinkBandwidthUtils() {
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
+ .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .minBandwidth(10, 20));
+
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, NetworkCapabilities
+ .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(10, NetworkCapabilities
+ .maxBandwidth(LINK_BANDWIDTH_UNSPECIFIED, 10));
+ assertEquals(10, NetworkCapabilities
+ .maxBandwidth(10, LINK_BANDWIDTH_UNSPECIFIED));
+ assertEquals(20, NetworkCapabilities
+ .maxBandwidth(10, 20));
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 27a29b68e12d..113cd37f1a27 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -23,21 +23,44 @@ import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA;
import static android.net.ConnectivityManager.TYPE_MOBILE_MMS;
import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.NetworkCapabilities.*;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_FOTA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IA;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_MMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_RCS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_SUPL;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_XCAP;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
+
+import static com.android.internal.util.TestUtils.waitForIdleHandler;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import static com.android.internal.util.TestUtils.waitForIdleHandler;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.app.NotificationManager;
@@ -45,7 +68,6 @@ import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Resources;
@@ -64,7 +86,6 @@ import android.net.MatchAllNetworkSpecifier;
import android.net.Network;
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
-import android.net.NetworkConfig;
import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
@@ -79,13 +100,9 @@ import android.net.util.MultinetworkPolicyTracker;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Message;
-import android.os.MessageQueue;
-import android.os.Messenger;
-import android.os.MessageQueue.IdleHandler;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
@@ -96,10 +113,8 @@ import android.support.test.InstrumentationRegistry;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.test.mock.MockContentResolver;
-import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
-import android.util.LogPrinter;
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
@@ -109,7 +124,6 @@ import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
-import com.android.server.connectivity.NetworkMonitor.CaptivePortalProbeResult;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -160,6 +174,7 @@ public class ConnectivityServiceTest {
@Mock IpConnectivityMetrics.Logger mMetricsService;
@Mock DefaultNetworkMetrics mDefaultNetworkMetrics;
+ @Mock INetworkStatsService mStatsService;
// This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
// do not go through ConnectivityService but talk to netd directly, so they don't automatically
@@ -858,7 +873,7 @@ public class ConnectivityServiceTest {
NetworkPolicyManagerInternal.class, mock(NetworkPolicyManagerInternal.class));
mService = new WrappedConnectivityService(mServiceContext,
mock(INetworkManagementService.class),
- mock(INetworkStatsService.class),
+ mStatsService,
mock(INetworkPolicyManager.class),
mock(IpConnectivityLog.class));
@@ -3440,6 +3455,40 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(networkCallback);
}
+ @Test
+ public void testStatsIfacesChanged() throws Exception {
+ mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+
+ // Simple connection should have updated ifaces
+ mCellNetworkAgent.connect(false);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Metered change should update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Captive portal change shouldn't update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ waitForIdle();
+ verify(mStatsService, never()).forceUpdateIfaces();
+ reset(mStatsService);
+
+ // Roaming change should update ifaces
+ mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
+ waitForIdle();
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces();
+ reset(mStatsService);
+ }
+
private void checkDirectlyConnectedRoutes(Object callbackObj,
Collection<LinkAddress> linkAddresses, Collection<RouteInfo> otherRoutes) {
assertTrue(callbackObj instanceof LinkProperties);
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index fe396c3a5c40..c29363cd1a4f 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -20,11 +20,30 @@ import static android.content.pm.UserInfo.FLAG_ADMIN;
import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
+import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import static org.mockito.AdditionalMatchers.*;
-import static org.mockito.Mockito.*;
+import static org.mockito.AdditionalMatchers.aryEq;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.annotation.UserIdInt;
import android.app.AppOpsManager;
@@ -36,6 +55,9 @@ import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.pm.UserInfo;
import android.content.res.Resources;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkInfo.DetailedState;
import android.net.UidRange;
import android.net.VpnService;
@@ -45,17 +67,17 @@ import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.UserHandle;
import android.os.UserManager;
-import android.support.test.runner.AndroidJUnit4;
import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
import android.util.ArrayMap;
import android.util.ArraySet;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
-import org.junit.runner.RunWith;
import org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import org.mockito.Answers;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -64,6 +86,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@@ -114,6 +137,7 @@ public class VpnTest {
@Mock private AppOpsManager mAppOps;
@Mock private NotificationManager mNotificationManager;
@Mock private Vpn.SystemServices mSystemServices;
+ @Mock private ConnectivityManager mConnectivityManager;
@Before
public void setUp() throws Exception {
@@ -127,6 +151,8 @@ public class VpnTest {
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
+ when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
+ .thenReturn(mConnectivityManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
R.string.config_customVpnAlwaysOnDisconnectedDialogComponent));
@@ -397,6 +423,66 @@ public class VpnTest {
order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
}
+ @Test
+ public void testCapabilities() {
+ final Vpn vpn = createVpn(primaryUser.id);
+ setMockedUsers(primaryUser);
+
+ final Network mobile = new Network(1);
+ final Network wifi = new Network(2);
+
+ final Map<Network, NetworkCapabilities> networks = new HashMap<>();
+ networks.put(mobile, new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .setLinkDownstreamBandwidthKbps(10));
+ networks.put(wifi, new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .setLinkUpstreamBandwidthKbps(20));
+ setMockedNetworks(networks);
+
+ final NetworkCapabilities caps = new NetworkCapabilities();
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertFalse(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkUpstreamBandwidthKbps());
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertFalse(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(LINK_BANDWIDTH_UNSPECIFIED, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+
+ Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps);
+ assertTrue(caps.hasTransport(TRANSPORT_VPN));
+ assertTrue(caps.hasTransport(TRANSPORT_CELLULAR));
+ assertTrue(caps.hasTransport(TRANSPORT_WIFI));
+ assertEquals(10, caps.getLinkDownstreamBandwidthKbps());
+ assertEquals(20, caps.getLinkUpstreamBandwidthKbps());
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
+ assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
+ }
+
/**
* Mock some methods of vpn object.
*/
@@ -463,4 +549,11 @@ public class VpnTest {
} catch (Exception e) {
}
}
+
+ private void setMockedNetworks(final Map<Network, NetworkCapabilities> networks) {
+ doAnswer(invocation -> {
+ final Network network = (Network) invocation.getArguments()[0];
+ return networks.get(network);
+ }).when(mConnectivityManager).getNetworkCapabilities(any());
+ }
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index fa997958ba6d..375b418bead6 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -1169,9 +1169,8 @@ public class NetworkStatsServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
- if (!isMetered) {
- capabilities.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
- }
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, !isMetered);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
return new NetworkState(info, prop, capabilities, null, null, TEST_SSID);
}
@@ -1187,6 +1186,8 @@ public class NetworkStatsServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(TEST_IFACE);
final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, !isRoaming);
return new NetworkState(info, prop, capabilities, null, subscriberId, null);
}
@@ -1196,6 +1197,8 @@ public class NetworkStatsServiceTest {
final LinkProperties prop = new LinkProperties();
prop.setInterfaceName(iface);
final NetworkCapabilities capabilities = new NetworkCapabilities();
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED, false);
+ capabilities.setCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING, true);
return new NetworkState(info, prop, capabilities, null, null, null);
}