Merge rvc-qpr-dev-plus-aosp-without-vendor@6881855
Bug: 172690556
Merged-In: I78222391b83a4add8e964340ec08bb8a1306e1c6
Change-Id: I28bbf40820674675ccf765c912aa8140d3f74ab2
diff --git a/core/java/android/net/CaptivePortal.java b/core/java/android/net/CaptivePortal.java
index 8afeb30..c2586fa 100644
--- a/core/java/android/net/CaptivePortal.java
+++ b/core/java/android/net/CaptivePortal.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
@@ -42,7 +41,6 @@
* @hide
*/
@SystemApi
- @TestApi
public static final int APP_RETURN_DISMISSED = 0;
/**
* Response code from the captive portal application, indicating that the user did not login and
@@ -52,7 +50,6 @@
* @hide
*/
@SystemApi
- @TestApi
public static final int APP_RETURN_UNWANTED = 1;
/**
* Response code from the captive portal application, indicating that the user does not wish to
@@ -62,7 +59,6 @@
* @hide
*/
@SystemApi
- @TestApi
public static final int APP_RETURN_WANTED_AS_IS = 2;
/** Event offset of request codes from captive portal application. */
private static final int APP_REQUEST_BASE = 100;
@@ -74,7 +70,6 @@
* @hide
*/
@SystemApi
- @TestApi
public static final int APP_REQUEST_REEVALUATION_REQUIRED = APP_REQUEST_BASE + 0;
private final IBinder mBinder;
@@ -154,7 +149,6 @@
* @hide
*/
@SystemApi
- @TestApi
public void useNetwork() {
try {
ICaptivePortal.Stub.asInterface(mBinder).appResponse(APP_RETURN_WANTED_AS_IS);
@@ -167,7 +161,6 @@
* @hide
*/
@SystemApi
- @TestApi
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
public void reevaluateNetwork() {
try {
@@ -183,7 +176,6 @@
* @hide
*/
@SystemApi
- @TestApi
public void logEvent(@EventId int eventId, @NonNull String packageName) {
try {
ICaptivePortal.Stub.asInterface(mBinder).logEvent(eventId, packageName);
diff --git a/core/java/android/net/CaptivePortalData.java b/core/java/android/net/CaptivePortalData.java
index 1357803..c443c75 100644
--- a/core/java/android/net/CaptivePortalData.java
+++ b/core/java/android/net/CaptivePortalData.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
@@ -30,7 +29,6 @@
* @hide
*/
@SystemApi
-@TestApi
public final class CaptivePortalData implements Parcelable {
private final long mRefreshTimeMillis;
@Nullable
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index dcf3b5c..c28a901 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -269,7 +269,6 @@
* {@hide}
*/
@SystemApi
- @TestApi
public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC =
"android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
@@ -278,7 +277,6 @@
* {@hide}
*/
@SystemApi
- @TestApi
public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT =
"android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
@@ -356,7 +354,7 @@
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final String ACTION_TETHER_STATE_CHANGED =
TetheringManager.ACTION_TETHER_STATE_CHANGED;
@@ -365,7 +363,7 @@
* gives a String[] listing all the interfaces configured for
* tethering and currently available for tethering.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final String EXTRA_AVAILABLE_TETHER = TetheringManager.EXTRA_AVAILABLE_TETHER;
/**
@@ -380,7 +378,7 @@
* gives a String[] listing all the interfaces currently tethered
* (ie, has DHCPv4 support and packets potentially forwarded/NATed)
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final String EXTRA_ACTIVE_TETHER = TetheringManager.EXTRA_ACTIVE_TETHER;
/**
@@ -389,7 +387,7 @@
* failed. Use {@link #getLastTetherError} to find the error code
* for any interfaces listed here.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final String EXTRA_ERRORED_TETHER = TetheringManager.EXTRA_ERRORED_TETHER;
/**
@@ -852,7 +850,7 @@
* {@hide}
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static String getNetworkTypeName(int type) {
switch (type) {
case TYPE_NONE:
@@ -899,6 +897,18 @@
}
/**
+ * @hide
+ * TODO: Expose for SystemServer when becomes a module.
+ */
+ public void systemReady() {
+ try {
+ mService.systemReady();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Checks if a given type uses the cellular data connection.
* This should be replaced in the future by a network property.
* @param networkType the type to check
@@ -1163,7 +1173,7 @@
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.NETWORK_STACK)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public NetworkInfo getActiveNetworkInfoForUid(int uid) {
return getActiveNetworkInfoForUid(uid, false);
}
@@ -1510,7 +1520,7 @@
return 1;
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) {
if (networkType == TYPE_MOBILE) {
switch (feature) {
@@ -1596,7 +1606,7 @@
};
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private static final HashMap<NetworkCapabilities, LegacyRequest> sLegacyRequests =
new HashMap<>();
@@ -1625,7 +1635,7 @@
Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum);
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) {
int delay = -1;
int type = legacyTypeForNetworkCapabilities(netCap);
@@ -1655,7 +1665,7 @@
}
}
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private boolean removeRequestForFeature(NetworkCapabilities netCap) {
final LegacyRequest l;
synchronized (sLegacyRequests) {
@@ -1722,17 +1732,17 @@
/** @hide */
public static class PacketKeepaliveCallback {
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public PacketKeepaliveCallback() {
}
/** The requested keepalive was successfully started. */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void onStarted() {}
/** The keepalive was successfully stopped. */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void onStopped() {}
/** An error occurred. */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void onError(int error) {}
}
@@ -1796,7 +1806,7 @@
private volatile Integer mSlot;
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public void stop() {
try {
mExecutor.execute(() -> {
@@ -1865,7 +1875,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public PacketKeepalive startNattKeepalive(
Network network, int intervalSeconds, PacketKeepaliveCallback callback,
InetAddress srcAddr, int srcPort, InetAddress dstAddr) {
@@ -2100,7 +2110,7 @@
/** {@hide} */
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public NetworkQuotaInfo getActiveNetworkQuotaInfo() {
try {
return mService.getActiveNetworkQuotaInfo();
@@ -2398,7 +2408,7 @@
*
* {@hide}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Deprecated
public int tether(String iface) {
return mTetheringManager.tether(iface);
@@ -2839,7 +2849,7 @@
* {@hide}
*/
@RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE)
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Deprecated
public int getLastTetherError(String iface) {
int error = mTetheringManager.getLastTetherError(iface);
@@ -4401,7 +4411,6 @@
* @hide
*/
@SystemApi
- @TestApi
@RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
public void startCaptivePortalApp(@NonNull Network network, @NonNull Bundle appExtras) {
try {
@@ -4650,7 +4659,7 @@
* @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}.
*/
@Deprecated
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static boolean setProcessDefaultNetworkForHostResolution(Network network) {
return NetworkUtils.bindProcessToNetworkForHostResolution(
(network == null) ? NETID_UNSET : network.getNetIdForResolv());
@@ -4807,4 +4816,9 @@
e.rethrowFromSystemServer();
}
}
+
+ private void setOemNetworkPreference(@NonNull OemNetworkPreferences preference) {
+ Log.d(TAG, "setOemNetworkPreference called with preference: "
+ + preference.toString());
+ }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d7f178c..4173200 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -73,7 +73,7 @@
NetworkCapabilities getNetworkCapabilities(in Network network, String callingPackageName);
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
NetworkState[] getAllNetworkState();
NetworkQuotaInfo getActiveNetworkQuotaInfo();
@@ -134,7 +134,7 @@
VpnConfig getVpnConfig(int userId);
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553)
void startLegacyVpn(in VpnProfile profile);
LegacyVpnInfo getLegacyVpnInfo(int userId);
@@ -233,4 +233,6 @@
void simulateDataStall(int detectionMethod, long timestampMillis, in Network network,
in PersistableBundle extras);
+
+ void systemReady();
}
diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java
index 23d5ff7..0b20564 100644
--- a/core/java/android/net/IpConfiguration.java
+++ b/core/java/android/net/IpConfiguration.java
@@ -21,6 +21,7 @@
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -98,7 +99,7 @@
}
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public IpConfiguration(IpAssignment ipAssignment,
ProxySettings proxySettings,
StaticIpConfiguration staticIpConfiguration,
diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java
index 8cfe6df..e7c8014 100644
--- a/core/java/android/net/IpPrefix.java
+++ b/core/java/android/net/IpPrefix.java
@@ -19,7 +19,6 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
@@ -88,7 +87,6 @@
* @hide
*/
@SystemApi
- @TestApi
public IpPrefix(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength) {
// We don't reuse the (byte[], int) constructor because it calls clone() on the byte array,
// which is unnecessary because getAddress() already returns a clone.
@@ -107,7 +105,6 @@
* @hide
*/
@SystemApi
- @TestApi
public IpPrefix(@NonNull String prefix) {
// We don't reuse the (InetAddress, int) constructor because "error: call to this must be
// first statement in constructor". We could factor out setting the member variables to an
diff --git a/core/java/android/net/KeepalivePacketData.java b/core/java/android/net/KeepalivePacketData.java
index e21cb44..5877f1f 100644
--- a/core/java/android/net/KeepalivePacketData.java
+++ b/core/java/android/net/KeepalivePacketData.java
@@ -22,9 +22,10 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.net.util.IpUtils;
import android.util.Log;
+import com.android.net.module.util.IpUtils;
+
import java.net.InetAddress;
/**
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index a9d7f17..44d25a1 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -30,7 +30,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.os.Build;
import android.os.Parcel;
@@ -158,7 +157,6 @@
* @return true if the address is IPv6.
* @hide
*/
- @TestApi
@SystemApi
public boolean isIpv6() {
return address instanceof Inet6Address;
@@ -180,7 +178,6 @@
* @return true if the address is IPv4 or is a mapped IPv4 address.
* @hide
*/
- @TestApi
@SystemApi
public boolean isIpv4() {
return address instanceof Inet4Address;
@@ -243,7 +240,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
int flags, int scope) {
init(address, prefixLength, flags, scope, LIFETIME_UNKNOWN, LIFETIME_UNKNOWN);
@@ -275,7 +271,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkAddress(@NonNull InetAddress address, @IntRange(from = 0, to = 128) int prefixLength,
int flags, int scope, long deprecationTime, long expirationTime) {
init(address, prefixLength, flags, scope, deprecationTime, expirationTime);
@@ -289,7 +284,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkAddress(@NonNull InetAddress address,
@IntRange(from = 0, to = 128) int prefixLength) {
this(address, prefixLength, 0, 0);
@@ -314,7 +308,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkAddress(@NonNull String address) {
this(address, 0, 0);
this.scope = scopeForUnicastAddress(this.address);
@@ -329,7 +322,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkAddress(@NonNull String address, int flags, int scope) {
// This may throw an IllegalArgumentException; catching it is the caller's responsibility.
// TODO: consider rejecting mapped IPv4 addresses such as "::ffff:192.0.2.5/24".
@@ -389,7 +381,6 @@
* otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean isSameAddressAs(@Nullable LinkAddress other) {
if (other == null) {
@@ -469,7 +460,6 @@
* @hide
*/
@SystemApi
- @TestApi
public long getDeprecationTime() {
return deprecationTime;
}
@@ -485,7 +475,6 @@
* @hide
*/
@SystemApi
- @TestApi
public long getExpirationTime() {
return expirationTime;
}
@@ -496,7 +485,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public boolean isGlobalPreferred() {
/**
diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java
index 651494d..06046f7 100644
--- a/core/java/android/net/LinkProperties.java
+++ b/core/java/android/net/LinkProperties.java
@@ -19,10 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.util.LinkPropertiesUtils;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -82,8 +80,10 @@
private final transient boolean mParcelSensitiveFields;
private static final int MIN_MTU = 68;
- /* package-visibility - Used in other files (such as Ikev2VpnProfile) as minimum iface MTU. */
- static final int MIN_MTU_V6 = 1280;
+
+ /** @hide */
+ public static final int MIN_MTU_V6 = 1280;
+
private static final int MAX_MTU = 10000;
private static final int INET6_ADDR_LENGTH = 16;
@@ -113,7 +113,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static ProvisioningChange compareProvisioning(
LinkProperties before, LinkProperties after) {
if (before.isProvisioned() && after.isProvisioned()) {
@@ -162,7 +162,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkProperties(@Nullable LinkProperties source) {
this(source, false /* parcelSensitiveFields */);
}
@@ -178,7 +177,6 @@
* @hide
*/
@SystemApi
- @TestApi
public LinkProperties(@Nullable LinkProperties source, boolean parcelSensitiveFields) {
mParcelSensitiveFields = parcelSensitiveFields;
if (source == null) return;
@@ -293,7 +291,6 @@
* @hide
*/
@SystemApi
- @TestApi
public boolean addLinkAddress(@NonNull LinkAddress address) {
if (address == null) {
return false;
@@ -322,7 +319,6 @@
* @hide
*/
@SystemApi
- @TestApi
public boolean removeLinkAddress(@NonNull LinkAddress toRemove) {
int i = findLinkAddressIndex(toRemove);
if (i >= 0) {
@@ -376,7 +372,6 @@
* @return true if the DNS server was added, false if it was already present.
* @hide
*/
- @TestApi
@SystemApi
public boolean addDnsServer(@NonNull InetAddress dnsServer) {
if (dnsServer != null && !mDnses.contains(dnsServer)) {
@@ -393,7 +388,6 @@
* @return true if the DNS server was removed, false if it did not exist.
* @hide
*/
- @TestApi
@SystemApi
public boolean removeDnsServer(@NonNull InetAddress dnsServer) {
return mDnses.remove(dnsServer);
@@ -428,7 +422,6 @@
* @param usePrivateDns The private DNS state.
* @hide
*/
- @TestApi
@SystemApi
public void setUsePrivateDns(boolean usePrivateDns) {
mUsePrivateDns = usePrivateDns;
@@ -455,7 +448,6 @@
* @param privateDnsServerName The private DNS server name.
* @hide
*/
- @TestApi
@SystemApi
public void setPrivateDnsServerName(@Nullable String privateDnsServerName) {
mPrivateDnsServerName = privateDnsServerName;
@@ -534,7 +526,6 @@
* object.
* @hide
*/
- @TestApi
@SystemApi
public void setValidatedPrivateDnsServers(@NonNull Collection<InetAddress> dnsServers) {
mValidatedPrivateDnses.clear();
@@ -551,7 +542,6 @@
* DNS servers on this link.
* @hide
*/
- @TestApi
@SystemApi
public @NonNull List<InetAddress> getValidatedPrivateDnsServers() {
return Collections.unmodifiableList(mValidatedPrivateDnses);
@@ -592,7 +582,6 @@
* @hide
*/
@SystemApi
- @TestApi
public void setPcscfServers(@NonNull Collection<InetAddress> pcscfServers) {
mPcscfs.clear();
for (InetAddress pcscfServer: pcscfServers) {
@@ -608,7 +597,6 @@
* @hide
*/
@SystemApi
- @TestApi
public @NonNull List<InetAddress> getPcscfServers() {
return Collections.unmodifiableList(mPcscfs);
}
@@ -662,7 +650,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public void setTcpBufferSizes(@Nullable String tcpBufferSizes) {
mTcpBufferSizes = tcpBufferSizes;
@@ -675,7 +662,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public @Nullable String getTcpBufferSizes() {
return mTcpBufferSizes;
@@ -744,7 +730,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public boolean removeRoute(@NonNull RouteInfo route) {
return Objects.equals(mIfaceName, route.getInterface()) && mRoutes.remove(route);
@@ -866,7 +851,7 @@
* Returns all the links stacked on top of this link.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public @NonNull List<LinkProperties> getStackedLinks() {
if (mStackedLinks.isEmpty()) {
return Collections.emptyList();
@@ -1021,7 +1006,6 @@
* @return {@code true} if there is an IPv4 address, {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean hasIpv4Address() {
for (LinkAddress address : mLinkAddresses) {
@@ -1062,7 +1046,6 @@
* @return {@code true} if there is a global preferred IPv6 address, {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean hasGlobalIpv6Address() {
for (LinkAddress address : mLinkAddresses) {
@@ -1149,7 +1132,6 @@
* @return {@code true} if there is an IPv6 default route, {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean hasIpv6DefaultRoute() {
for (RouteInfo r : mRoutes) {
@@ -1265,7 +1247,6 @@
* @return {@code true} if the link is provisioned, {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean isIpv4Provisioned() {
return (hasIpv4Address()
@@ -1280,7 +1261,6 @@
* @return {@code true} if the link is provisioned, {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean isIpv6Provisioned() {
return (hasGlobalIpv6Address()
@@ -1308,7 +1288,6 @@
* @return {@code true} if the link is provisioned, {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean isProvisioned() {
return (isIpv4Provisioned() || isIpv6Provisioned());
@@ -1321,7 +1300,6 @@
* {@code false} otherwise.
* @hide
*/
- @TestApi
@SystemApi
public boolean isReachable(@NonNull InetAddress ip) {
final List<RouteInfo> allRoutes = getAllRoutes();
@@ -1472,7 +1450,7 @@
* @return {@code true} if both are identical, {@code false} otherwise.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean isIdenticalStackedLinks(@NonNull LinkProperties target) {
if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) {
return false;
@@ -1578,7 +1556,6 @@
* @hide
*/
@SystemApi
- @TestApi
public void setCaptivePortalApiUrl(@Nullable Uri url) {
mCaptivePortalApiUrl = url;
}
@@ -1593,7 +1570,6 @@
* @hide
*/
@SystemApi
- @TestApi
@Nullable
public Uri getCaptivePortalApiUrl() {
return mCaptivePortalApiUrl;
@@ -1604,7 +1580,6 @@
* @hide
*/
@SystemApi
- @TestApi
public void setCaptivePortalData(@Nullable CaptivePortalData data) {
mCaptivePortalData = data;
}
@@ -1618,7 +1593,6 @@
* @hide
*/
@SystemApi
- @TestApi
@Nullable
public CaptivePortalData getCaptivePortalData() {
return mCaptivePortalData;
@@ -1669,78 +1643,6 @@
}
/**
- * Compares the DNS addresses in this LinkProperties with another
- * LinkProperties, examining only DNS addresses on the base link.
- *
- * @param target a LinkProperties with the new list of dns addresses
- * @return the differences between the DNS addresses.
- * @hide
- */
- public @NonNull CompareResult<InetAddress> compareDnses(@Nullable LinkProperties target) {
- /*
- * Duplicate the InetAddresses into removed, we will be removing
- * dns address which are common between mDnses and target
- * leaving the addresses that are different. And dns address which
- * are in target but not in mDnses are placed in the
- * addedAddresses.
- */
- return new CompareResult<>(mDnses, target != null ? target.getDnsServers() : null);
- }
-
- /**
- * Compares the validated private DNS addresses in this LinkProperties with another
- * LinkProperties.
- *
- * @param target a LinkProperties with the new list of validated private dns addresses
- * @return the differences between the DNS addresses.
- * @hide
- */
- public @NonNull CompareResult<InetAddress> compareValidatedPrivateDnses(
- @Nullable LinkProperties target) {
- return new CompareResult<>(mValidatedPrivateDnses,
- target != null ? target.getValidatedPrivateDnsServers() : null);
- }
-
- /**
- * Compares all routes in this LinkProperties with another LinkProperties,
- * examining both the the base link and all stacked links.
- *
- * @param target a LinkProperties with the new list of routes
- * @return the differences between the routes.
- * @hide
- */
- public @NonNull CompareResult<RouteInfo> compareAllRoutes(@Nullable LinkProperties target) {
- /*
- * Duplicate the RouteInfos into removed, we will be removing
- * routes which are common between mRoutes and target
- * leaving the routes that are different. And route address which
- * are in target but not in mRoutes are placed in added.
- */
- return new CompareResult<>(getAllRoutes(), target != null ? target.getAllRoutes() : null);
- }
-
- /**
- * Compares all interface names in this LinkProperties with another
- * LinkProperties, examining both the the base link and all stacked links.
- *
- * @param target a LinkProperties with the new list of interface names
- * @return the differences between the interface names.
- * @hide
- */
- public @NonNull CompareResult<String> compareAllInterfaceNames(
- @Nullable LinkProperties target) {
- /*
- * Duplicate the interface names into removed, we will be removing
- * interface names which are common between this and target
- * leaving the interface names that are different. And interface names which
- * are in target but not in this are placed in added.
- */
- return new CompareResult<>(getAllInterfaceNames(),
- target != null ? target.getAllInterfaceNames() : null);
- }
-
-
- /**
* Generate hashcode based on significant fields
*
* Equal objects must produce the same hash code, while unequal objects
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 0eb3c1e..178183d 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -22,6 +22,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.net.util.MacAddressUtils;
import android.net.wifi.WifiInfo;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -58,7 +59,7 @@
* <p>Not publicly exposed or treated specially since the OUI 00:00:00 is registered.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final MacAddress ALL_ZEROS_ADDRESS = new MacAddress(0);
/** @hide */
diff --git a/core/java/android/net/NattKeepalivePacketData.java b/core/java/android/net/NattKeepalivePacketData.java
index 22288b6..c4f8fc2 100644
--- a/core/java/android/net/NattKeepalivePacketData.java
+++ b/core/java/android/net/NattKeepalivePacketData.java
@@ -22,11 +22,12 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.net.util.IpUtils;
import android.os.Parcel;
import android.os.Parcelable;
import android.system.OsConstants;
+import com.android.net.module.util.IpUtils;
+
import java.net.Inet4Address;
import java.net.InetAddress;
import java.nio.ByteBuffer;
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index b872617..f98a1f8 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -18,8 +18,8 @@
import android.annotation.NonNull;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.system.ErrnoException;
@@ -110,7 +110,7 @@
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public Network(int netId) {
this(netId, false);
}
@@ -127,7 +127,6 @@
* @hide
*/
@SystemApi
- @TestApi
public Network(@NonNull Network that) {
this(that.netId, that.mPrivateDnsBypass);
}
@@ -164,7 +163,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public @NonNull Network getPrivateDnsBypassingCopy() {
return new Network(netId, true);
@@ -175,7 +173,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public int getNetId() {
return netId;
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 327e42b..0676ad4 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -40,6 +40,7 @@
import java.lang.annotation.RetentionPolicy;
import java.time.Duration;
import java.util.ArrayList;
+import java.util.List;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -174,6 +175,14 @@
public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4;
/**
+ * Sent by the NetworkAgent to ConnectivityService to pass the current
+ * list of underlying networks.
+ * obj = array of Network objects
+ * @hide
+ */
+ public static final int EVENT_UNDERLYING_NETWORKS_CHANGED = BASE + 5;
+
+ /**
* Sent by ConnectivityService to the NetworkAgent to inform the agent of the
* networks status - whether we could use the network or could not, due to
* either a bad network configuration (no internet link) or captive portal.
@@ -217,7 +226,13 @@
* The key for the redirect URL in the Bundle argument of {@code CMD_REPORT_NETWORK_STATUS}.
* @hide
*/
- public static String REDIRECT_URL_KEY = "redirect URL";
+ public static final String REDIRECT_URL_KEY = "redirect URL";
+
+ /**
+ * Bundle key for the underlying networks in {@code EVENT_UNDERLYING_NETWORKS_CHANGED}.
+ * @hide
+ */
+ public static final String UNDERLYING_NETWORKS_KEY = "underlyingNetworks";
/**
* Sent by the NetworkAgent to ConnectivityService to indicate this network was
@@ -353,10 +368,11 @@
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
// The subtype can be changed with (TODO) setLegacySubtype, but it starts
- // with the type and an empty description.
+ // with 0 (TelephonyManager.NETWORK_TYPE_UNKNOWN) and an empty description.
final NetworkInfo ni = new NetworkInfo(config.legacyType, 0, config.legacyTypeName, "");
ni.setIsAvailable(true);
- ni.setExtraInfo(config.getLegacyExtraInfo());
+ ni.setDetailedState(NetworkInfo.DetailedState.CONNECTING, null /* reason */,
+ config.getLegacyExtraInfo());
return ni;
}
@@ -649,6 +665,33 @@
}
/**
+ * Must be called by the agent when the network's underlying networks change.
+ *
+ * <p>{@code networks} is one of the following:
+ * <ul>
+ * <li><strong>a non-empty array</strong>: an array of one or more {@link Network}s, in
+ * decreasing preference order. For example, if this VPN uses both wifi and mobile (cellular)
+ * networks to carry app traffic, but prefers or uses wifi more than mobile, wifi should appear
+ * first in the array.</li>
+ * <li><strong>an empty array</strong>: a zero-element array, meaning that the VPN has no
+ * underlying network connection, and thus, app traffic will not be sent or received.</li>
+ * <li><strong>null</strong>: (default) signifies that the VPN uses whatever is the system's
+ * default network. I.e., it doesn't use the {@code bindSocket} or {@code bindDatagramSocket}
+ * APIs mentioned above to send traffic over specific channels.</li>
+ * </ul>
+ *
+ * @param underlyingNetworks the new list of underlying networks.
+ * @see {@link VpnService.Builder#setUnderlyingNetworks(Network[])}
+ */
+ public final void setUnderlyingNetworks(@Nullable List<Network> underlyingNetworks) {
+ final ArrayList<Network> underlyingArray = (underlyingNetworks != null)
+ ? new ArrayList<>(underlyingNetworks) : null;
+ final Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(UNDERLYING_NETWORKS_KEY, underlyingArray);
+ queueOrSendMessage(EVENT_UNDERLYING_NETWORKS_CHANGED, bundle);
+ }
+
+ /**
* Inform ConnectivityService that this agent has now connected.
* Call {@link #unregister} to disconnect.
*/
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 004f844..8dad11f 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -133,7 +133,7 @@
* Represents the network's capabilities. If any are specified they will be satisfied
* by any Network that matches all of them.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
private long mNetworkCapabilities;
/**
@@ -170,6 +170,7 @@
NET_CAPABILITY_MCX,
NET_CAPABILITY_PARTIAL_CONNECTIVITY,
NET_CAPABILITY_TEMPORARILY_NOT_METERED,
+ NET_CAPABILITY_OEM_PRIVATE,
})
public @interface NetCapability { }
@@ -338,15 +339,26 @@
public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24;
/**
+ * Indicates that this network is temporarily unmetered.
+ * <p>
* This capability will be set for networks that are generally metered, but are currently
* unmetered, e.g., because the user is in a particular area. This capability can be changed at
* any time. When it is removed, applications are responsible for stopping any data transfer
* that should not occur on a metered network.
+ * Note that most apps should use {@link #NET_CAPABILITY_NOT_METERED} instead. For more
+ * information, see https://developer.android.com/about/versions/11/features/5g#meteredness.
*/
public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25;
+ /**
+ * Indicates that this network is private to the OEM and meant only for OEM use.
+ * @hide
+ */
+ @SystemApi
+ public static final int NET_CAPABILITY_OEM_PRIVATE = 26;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_TEMPORARILY_NOT_METERED;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_OEM_PRIVATE;
/**
* Network capabilities that are expected to be mutable, i.e., can change while a particular
@@ -362,8 +374,8 @@
| (1 << NET_CAPABILITY_FOREGROUND)
| (1 << NET_CAPABILITY_NOT_CONGESTED)
| (1 << NET_CAPABILITY_NOT_SUSPENDED)
- | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY
- | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED));
+ | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY)
+ | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED);
/**
* Network capabilities that are not allowed in NetworkRequests. This exists because the
@@ -404,7 +416,8 @@
* {@see #maybeMarkCapabilitiesRestricted}.
*/
private static final long FORCE_RESTRICTED_CAPABILITIES =
- (1 << NET_CAPABILITY_OEM_PAID);
+ (1 << NET_CAPABILITY_OEM_PAID)
+ | (1 << NET_CAPABILITY_OEM_PRIVATE);
/**
* Capabilities that suggest that a network is unrestricted.
@@ -699,6 +712,7 @@
if (ArrayUtils.contains(originalAdministratorUids, creatorUid)) {
setAdministratorUids(new int[] {creatorUid});
}
+ // There is no need to clear the UIDs, they have already been cleared by clearAll() above.
}
/**
@@ -792,7 +806,9 @@
*/
private static final int TEST_NETWORKS_ALLOWED_TRANSPORTS = 1 << TRANSPORT_TEST
// Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces
- | 1 << TRANSPORT_ETHERNET;
+ | 1 << TRANSPORT_ETHERNET
+ // Test VPN networks can be created but their UID ranges must be empty.
+ | 1 << TRANSPORT_VPN;
/**
* Adds the given transport type to this {@code NetworkCapability} instance.
@@ -850,7 +866,6 @@
* @return an array of transport type values for this instance.
* @hide
*/
- @TestApi
@SystemApi
@NonNull public @Transport int[] getTransportTypes() {
return BitUtils.unpackBits(mTransportTypes);
@@ -1025,7 +1040,6 @@
*/
@NonNull
@SystemApi
- @TestApi
public int[] getAdministratorUids() {
return Arrays.copyOf(mAdministratorUids, mAdministratorUids.length);
}
@@ -1281,7 +1295,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean hasSignalStrength() {
return mSignalStrength > SIGNAL_STRENGTH_UNSPECIFIED;
}
@@ -1506,7 +1520,6 @@
* @hide
*/
@SystemApi
- @TestApi
public @Nullable String getSsid() {
return mSSID;
}
@@ -1590,7 +1603,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
public boolean satisfiedByNetworkCapabilities(@Nullable NetworkCapabilities nc) {
return satisfiedByNetworkCapabilities(nc, false);
@@ -1797,20 +1809,26 @@
sb.append(" OwnerUid: ").append(mOwnerUid);
}
- if (mAdministratorUids.length == 0) {
- sb.append(" AdministratorUids: ").append(Arrays.toString(mAdministratorUids));
+ if (!ArrayUtils.isEmpty(mAdministratorUids)) {
+ sb.append(" AdminUids: ").append(Arrays.toString(mAdministratorUids));
+ }
+
+ if (mRequestorUid != Process.INVALID_UID) {
+ sb.append(" RequestorUid: ").append(mRequestorUid);
+ }
+
+ if (mRequestorPackageName != null) {
+ sb.append(" RequestorPkg: ").append(mRequestorPackageName);
}
if (null != mSSID) {
sb.append(" SSID: ").append(mSSID);
}
- if (mPrivateDnsBroken) {
- sb.append(" Private DNS is broken");
- }
- sb.append(" RequestorUid: ").append(mRequestorUid);
- sb.append(" RequestorPackageName: ").append(mRequestorPackageName);
+ if (mPrivateDnsBroken) {
+ sb.append(" PrivateDnsBroken");
+ }
sb.append("]");
return sb.toString();
@@ -1914,6 +1932,7 @@
case NET_CAPABILITY_MCX: return "MCX";
case NET_CAPABILITY_PARTIAL_CONNECTIVITY: return "PARTIAL_CONNECTIVITY";
case NET_CAPABILITY_TEMPORARILY_NOT_METERED: return "TEMPORARILY_NOT_METERED";
+ case NET_CAPABILITY_OEM_PRIVATE: return "OEM_PRIVATE";
default: return Integer.toString(capability);
}
}
@@ -1921,7 +1940,7 @@
/**
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static @NonNull String transportNamesOf(@Nullable @Transport int[] types) {
StringJoiner joiner = new StringJoiner("|");
if (types != null) {
@@ -2136,7 +2155,6 @@
* @hide
*/
@SystemApi
- @TestApi
public static final class Builder {
private final NetworkCapabilities mCaps;
diff --git a/core/java/android/net/NetworkProvider.java b/core/java/android/net/NetworkProvider.java
index 75086cf..a17a498 100644
--- a/core/java/android/net/NetworkProvider.java
+++ b/core/java/android/net/NetworkProvider.java
@@ -30,7 +30,7 @@
/**
* Base class for network providers such as telephony or Wi-Fi. NetworkProviders connect the device
- * to networks and makes them available to to the core network stack by creating
+ * to networks and makes them available to the core network stack by creating
* {@link NetworkAgent}s. The networks can then provide connectivity to apps and can be interacted
* with via networking APIs such as {@link ConnectivityManager}.
*
@@ -51,13 +51,6 @@
public static final int ID_NONE = -1;
/**
- * A hardcoded ID for NetworkAgents representing VPNs. These agents are not created by any
- * provider, so they use this constant for clarity instead of NONE.
- * @hide only used by ConnectivityService.
- */
- public static final int ID_VPN = -2;
-
- /**
* The first providerId value that will be allocated.
* @hide only used by ConnectivityService.
*/
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 473e6c5..dc16d74 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -43,7 +43,7 @@
* The {@link NetworkCapabilities} that define this request.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public final @NonNull NetworkCapabilities networkCapabilities;
/**
@@ -52,7 +52,7 @@
* the request.
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public final int requestId;
/**
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 1e5b6d5..a0faafa 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -98,7 +98,7 @@
* this socket will go directly to the underlying network, so its traffic will not be
* forwarded through the VPN.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static boolean protectFromVpn(FileDescriptor fd) {
return protectFromVpn(fd.getInt$());
}
@@ -223,7 +223,7 @@
* @hide
* @deprecated use {@link Inet4AddressUtils#netmaskToPrefixLength(Inet4Address)}
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Deprecated
public static int netmaskToPrefixLength(Inet4Address netmask) {
// This is only here because some apps seem to be using it (@UnsupportedAppUsage).
@@ -290,7 +290,7 @@
/**
* Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static int getImplicitNetmask(Inet4Address address) {
// Only here because it seems to be used by apps
return Inet4AddressUtils.getImplicitNetmask(address);
diff --git a/core/java/android/net/OemNetworkPreferences.java b/core/java/android/net/OemNetworkPreferences.java
new file mode 100644
index 0000000..6a8e3f9
--- /dev/null
+++ b/core/java/android/net/OemNetworkPreferences.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/** @hide */
+public final class OemNetworkPreferences implements Parcelable {
+ /**
+ * Use default behavior requesting networks. Equivalent to not setting any preference at all.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_DEFAULT = 0;
+
+ /**
+ * If an unmetered network is available, use it.
+ * Otherwise, if a network with the OEM_PAID capability is available, use it.
+ * Otherwise, use the general default network.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1;
+
+ /**
+ * If an unmetered network is available, use it.
+ * Otherwise, if a network with the OEM_PAID capability is available, use it.
+ * Otherwise, the app doesn't get a network.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2;
+
+ /**
+ * Prefer only NET_CAPABILITY_OEM_PAID networks.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3;
+
+ /**
+ * Prefer only NET_CAPABILITY_OEM_PRIVATE networks.
+ */
+ public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4;
+
+ @NonNull
+ private final SparseArray<List<String>> mNetworkMappings;
+
+ @NonNull
+ public SparseArray<List<String>> getNetworkPreferences() {
+ return mNetworkMappings.clone();
+ }
+
+ private OemNetworkPreferences(@NonNull SparseArray<List<String>> networkMappings) {
+ Objects.requireNonNull(networkMappings);
+ mNetworkMappings = networkMappings.clone();
+ }
+
+ @Override
+ public String toString() {
+ return "OemNetworkPreferences{" + "mNetworkMappings=" + mNetworkMappings + '}';
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ OemNetworkPreferences that = (OemNetworkPreferences) o;
+
+ return mNetworkMappings.size() == that.mNetworkMappings.size()
+ && mNetworkMappings.toString().equals(that.mNetworkMappings.toString());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mNetworkMappings);
+ }
+
+ /**
+ * Builder used to create {@link OemNetworkPreferences} objects. Specify the preferred Network
+ * to package name mappings.
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private final SparseArray<List<String>> mNetworkMappings;
+
+ public Builder() {
+ mNetworkMappings = new SparseArray<>();
+ }
+
+ /**
+ * Add a network preference for a list of packages.
+ *
+ * @param preference the desired network preference to use
+ * @param packages full package names (e.g.: "com.google.apps.contacts") for apps to use
+ * the given preference
+ * @return The builder to facilitate chaining.
+ */
+ @NonNull
+ public Builder addNetworkPreference(@OemNetworkPreference final int preference,
+ @NonNull List<String> packages) {
+ Objects.requireNonNull(packages);
+ mNetworkMappings.put(preference,
+ Collections.unmodifiableList(new ArrayList<>(packages)));
+ return this;
+ }
+
+ /**
+ * Build {@link OemNetworkPreferences} return the current OEM network preferences.
+ */
+ @NonNull
+ public OemNetworkPreferences build() {
+ return new OemNetworkPreferences(mNetworkMappings);
+ }
+ }
+
+ /** @hide */
+ @IntDef(prefix = "OEM_NETWORK_PREFERENCE_", value = {
+ OEM_NETWORK_PREFERENCE_DEFAULT,
+ OEM_NETWORK_PREFERENCE_OEM_PAID,
+ OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK,
+ OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY,
+ OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface OemNetworkPreference {}
+
+ /**
+ * Return the string value for OemNetworkPreference
+ *
+ * @param value int value of OemNetworkPreference
+ * @return string version of OemNetworkPreference
+ */
+ @NonNull
+ public static String oemNetworkPreferenceToString(@OemNetworkPreference int value) {
+ switch (value) {
+ case OEM_NETWORK_PREFERENCE_DEFAULT:
+ return "OEM_NETWORK_PREFERENCE_DEFAULT";
+ case OEM_NETWORK_PREFERENCE_OEM_PAID:
+ return "OEM_NETWORK_PREFERENCE_OEM_PAID";
+ case OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK:
+ return "OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK";
+ case OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY:
+ return "OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY";
+ case OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY:
+ return "OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY";
+ default:
+ return Integer.toHexString(value);
+ }
+ }
+
+ @Override
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ dest.writeSparseArray(mNetworkMappings);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<OemNetworkPreferences> CREATOR =
+ new Parcelable.Creator<OemNetworkPreferences>() {
+ @Override
+ public OemNetworkPreferences[] newArray(int size) {
+ return new OemNetworkPreferences[size];
+ }
+
+ @Override
+ public OemNetworkPreferences createFromParcel(@NonNull android.os.Parcel in) {
+ return new OemNetworkPreferences(
+ in.readSparseArray(getClass().getClassLoader()));
+ }
+ };
+}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
index 9876076..6166a75 100644
--- a/core/java/android/net/RouteInfo.java
+++ b/core/java/android/net/RouteInfo.java
@@ -20,7 +20,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.net.util.NetUtils;
import android.os.Build;
@@ -87,17 +86,14 @@
/** Unicast route. @hide */
@SystemApi
- @TestApi
public static final int RTN_UNICAST = 1;
/** Unreachable route. @hide */
@SystemApi
- @TestApi
public static final int RTN_UNREACHABLE = 7;
/** Throw route. @hide */
@SystemApi
- @TestApi
public static final int RTN_THROW = 9;
/**
@@ -135,7 +131,6 @@
* @hide
*/
@SystemApi
- @TestApi
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
@Nullable String iface, @RouteType int type) {
this(destination, gateway, iface, type, 0);
@@ -237,7 +232,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public RouteInfo(@Nullable IpPrefix destination, @Nullable InetAddress gateway,
@Nullable String iface) {
this(destination, gateway, iface, RTN_UNICAST);
@@ -397,7 +392,6 @@
*
* @hide
*/
- @TestApi
@SystemApi
@RouteType
public int getType() {
@@ -507,7 +501,7 @@
*
* @hide
*/
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Nullable
public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
return NetUtils.selectBestRoute(routes, dest);
diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java
index a973455..ce54597 100644
--- a/core/java/android/net/StaticIpConfiguration.java
+++ b/core/java/android/net/StaticIpConfiguration.java
@@ -19,8 +19,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
+import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
@@ -52,22 +52,21 @@
* @hide
*/
@SystemApi
-@TestApi
public final class StaticIpConfiguration implements Parcelable {
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Nullable
public LinkAddress ipAddress;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Nullable
public InetAddress gateway;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@NonNull
public final ArrayList<InetAddress> dnsServers;
/** @hide */
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
@Nullable
public String domains;
diff --git a/core/java/android/net/apf/ApfCapabilities.java b/core/java/android/net/apf/ApfCapabilities.java
index 92c5432..bf5b26e 100644
--- a/core/java/android/net/apf/ApfCapabilities.java
+++ b/core/java/android/net/apf/ApfCapabilities.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.content.res.Resources;
import android.os.Parcel;
import android.os.Parcelable;
@@ -36,7 +35,6 @@
* @hide
*/
@SystemApi
-@TestApi
public final class ApfCapabilities implements Parcelable {
/**
* Version of APF instruction set supported for packet filtering. 0 indicates no support for
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 8a1baf2..9b006d0 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -41,6 +41,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_FOREGROUND;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
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;
@@ -65,7 +66,6 @@
import android.annotation.Nullable;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
-import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -156,11 +156,8 @@
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
-import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.os.ShellCallback;
-import android.os.ShellCommand;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -195,6 +192,7 @@
import com.android.internal.util.LocationPermissionChecker;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.BasicShellCommandHandler;
import com.android.server.am.BatteryStatsService;
import com.android.server.connectivity.AutodestructReference;
import com.android.server.connectivity.DataConnectionStats;
@@ -932,13 +930,6 @@
}
/**
- * @see ServiceManager#checkService(String)
- */
- public boolean hasService(@NonNull String name) {
- return ServiceManager.checkService(name) != null;
- }
-
- /**
* @see IpConnectivityMetrics.Logger
*/
public IpConnectivityMetrics.Logger getMetricsLogger() {
@@ -1081,7 +1072,8 @@
// Do the same for Ethernet, since it's often not specified in the configs, although many
// devices can use it via USB host adapters.
- if (mNetConfigs[TYPE_ETHERNET] == null && mDeps.hasService(Context.ETHERNET_SERVICE)) {
+ if (mNetConfigs[TYPE_ETHERNET] == null
+ && mContext.getSystemService(Context.ETHERNET_SERVICE) != null) {
mLegacyTypeTracker.addSupportedType(TYPE_ETHERNET);
mNetworksDefined++;
}
@@ -1115,24 +1107,26 @@
intentFilter.addAction(Intent.ACTION_USER_ADDED);
intentFilter.addAction(Intent.ACTION_USER_REMOVED);
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
- mContext.registerReceiverAsUser(
+
+ final Context userAllContext = mContext.createContextAsUser(UserHandle.ALL, 0 /* flags */);
+ userAllContext.registerReceiver(
mIntentReceiver,
- UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
- mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
- new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
+ mContext.createContextAsUser(UserHandle.SYSTEM, 0 /* flags */).registerReceiver(
+ mUserPresentReceiver,
+ new IntentFilter(Intent.ACTION_USER_PRESENT),
+ null /* broadcastPermission */,
+ null /* scheduler */);
// Listen to package add and removal events for all users.
intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
intentFilter.addDataScheme("package");
- mContext.registerReceiverAsUser(
+ userAllContext.registerReceiver(
mIntentReceiver,
- UserHandle.ALL,
intentFilter,
null /* broadcastPermission */,
mHandler);
@@ -1140,8 +1134,8 @@
// Listen to lockdown VPN reset.
intentFilter = new IntentFilter();
intentFilter.addAction(LockdownVpnTracker.ACTION_LOCKDOWN_RESET);
- mContext.registerReceiverAsUser(
- mIntentReceiver, UserHandle.ALL, intentFilter, NETWORK_STACK, mHandler);
+ userAllContext.registerReceiver(
+ mIntentReceiver, intentFilter, NETWORK_STACK, mHandler);
try {
mNMS.registerObserver(mDataActivityObserver);
@@ -1156,8 +1150,7 @@
dataConnectionStats.startMonitoring();
mKeepaliveTracker = new KeepaliveTracker(mContext, mHandler);
- mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager,
- mContext.getSystemService(NotificationManager.class));
+ mNotifier = new NetworkNotificationManager(mContext, mTelephonyManager);
final int dailyLimit = Settings.Global.getInt(mContext.getContentResolver(),
Settings.Global.NETWORK_SWITCH_NOTIFICATION_DAILY_LIMIT,
@@ -1173,7 +1166,7 @@
mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
- mDnsManager = new DnsManager(mContext, mDnsResolver, mSystemProperties);
+ mDnsManager = new DnsManager(mContext, mDnsResolver);
registerPrivateDnsSettingsCallbacks();
}
@@ -1925,10 +1918,13 @@
}
if (DBG) log("Adding legacy route " + bestRoute +
" for UID/PID " + uid + "/" + Binder.getCallingPid());
+
+ final String dst = bestRoute.getDestinationLinkAddress().toString();
+ final String nextHop = bestRoute.hasGateway()
+ ? bestRoute.getGateway().getHostAddress() : "";
try {
- mNMS.addLegacyRouteForNetId(netId, bestRoute, uid);
- } catch (Exception e) {
- // never crash - catch them all
+ mNetd.networkAddLegacyRoute(netId, bestRoute.getInterface(), dst, nextHop , uid);
+ } catch (RemoteException | ServiceSpecificException e) {
if (DBG) loge("Exception trying to add a route: " + e);
return false;
}
@@ -2304,10 +2300,21 @@
}
/**
- * Called when the system is ready and ConnectivityService can initialize remaining components.
+ * Called by SystemServer through ConnectivityManager when the system is ready.
+ */
+ @Override
+ public void systemReady() {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Calling Uid is not system uid.");
+ }
+ systemReadyInternal();
+ }
+
+ /**
+ * Called when ConnectivityService can initialize remaining components.
*/
@VisibleForTesting
- public void systemReady() {
+ public void systemReadyInternal() {
// Let PermissionMonitor#startMonitoring() running in the beginning of the systemReady
// before MultipathPolicyTracker.start(). Since mApps in PermissionMonitor needs to be
// populated first to ensure that listening network request which is sent by
@@ -2430,9 +2437,9 @@
try {
if (VDBG || DDBG) log("Setting MTU size: " + iface + ", " + mtu);
- mNMS.setMtu(iface, mtu);
- } catch (Exception e) {
- Slog.e(TAG, "exception in setMtu()" + e);
+ mNetd.interfaceSetMtu(iface, mtu);
+ } catch (RemoteException | ServiceSpecificException e) {
+ Slog.e(TAG, "exception in interfaceSetMtu()" + e);
}
}
@@ -2464,12 +2471,11 @@
loge("Can't set TCP buffer sizes:" + e);
}
- Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TCP_DEFAULT_INIT_RWND,
+ final Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TCP_DEFAULT_INIT_RWND,
mSystemProperties.getInt("net.tcp.default_init_rwnd", 0));
- final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd";
if (rwndValue != 0) {
- mSystemProperties.set(sysctlKey, rwndValue.toString());
+ mSystemProperties.setTcpInitRwnd(rwndValue);
}
}
@@ -2692,10 +2698,16 @@
/**
* Return an array of all current NetworkRequest sorted by request id.
*/
- private NetworkRequestInfo[] requestsSortedById() {
+ @VisibleForTesting
+ protected NetworkRequestInfo[] requestsSortedById() {
NetworkRequestInfo[] requests = new NetworkRequestInfo[0];
requests = mNetworkRequests.values().toArray(requests);
- Arrays.sort(requests, Comparator.comparingInt(nri -> nri.request.requestId));
+ // Sort the array based off the NRI containing the min requestId in its requests.
+ Arrays.sort(requests,
+ Comparator.comparingInt(nri -> Collections.min(nri.mRequests,
+ Comparator.comparingInt(req -> req.requestId)).requestId
+ )
+ );
return requests;
}
@@ -2760,6 +2772,7 @@
networkCapabilities = new NetworkCapabilities(networkCapabilities);
networkCapabilities.restrictCapabilitesForTestNetwork(nai.creatorUid);
}
+ processCapabilitiesFromAgent(nai, networkCapabilities);
updateCapabilities(nai.getCurrentScore(), nai, networkCapabilities);
break;
}
@@ -2798,6 +2811,31 @@
mKeepaliveTracker.handleEventSocketKeepalive(nai, msg);
break;
}
+ case NetworkAgent.EVENT_UNDERLYING_NETWORKS_CHANGED: {
+ if (!nai.supportsUnderlyingNetworks()) {
+ Log.wtf(TAG, "Non-virtual networks cannot have underlying networks");
+ break;
+ }
+ final ArrayList<Network> underlying;
+ try {
+ underlying = ((Bundle) msg.obj).getParcelableArrayList(
+ NetworkAgent.UNDERLYING_NETWORKS_KEY);
+ } catch (NullPointerException | ClassCastException e) {
+ break;
+ }
+ final Network[] oldUnderlying = nai.declaredUnderlyingNetworks;
+ nai.declaredUnderlyingNetworks = (underlying != null)
+ ? underlying.toArray(new Network[0]) : null;
+
+ if (!Arrays.equals(oldUnderlying, nai.declaredUnderlyingNetworks)) {
+ if (DBG) {
+ log(nai.toShortString() + " changed underlying networks to "
+ + Arrays.toString(nai.declaredUnderlyingNetworks));
+ }
+ updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
+ notifyIfacesChangedForNetworkStats();
+ }
+ }
}
}
@@ -3383,7 +3421,7 @@
}
mLegacyTypeTracker.remove(nai, wasDefault);
if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
rematchAllNetworksAndRequests();
mLingerMonitor.noteDisconnect(nai);
@@ -3998,13 +4036,11 @@
settingsPkgName + ".wifi.WifiNoInternetDialog");
}
- PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
- mContext,
+ PendingIntent pendingIntent = PendingIntent.getActivity(
+ mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
0 /* requestCode */,
intent,
- PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
- null /* options */,
- UserHandle.CURRENT);
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, highPriority);
}
@@ -4695,10 +4731,9 @@
if (mLockdownEnabled) {
return new VpnInfo[0];
}
-
List<VpnInfo> infoList = new ArrayList<>();
- for (int i = 0; i < mVpns.size(); i++) {
- VpnInfo info = createVpnInfo(mVpns.valueAt(i));
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ VpnInfo info = createVpnInfo(nai);
if (info != null) {
infoList.add(info);
}
@@ -4711,13 +4746,10 @@
* @return VPN information for accounting, or null if we can't retrieve all required
* information, e.g underlying ifaces.
*/
- @Nullable
- private VpnInfo createVpnInfo(Vpn vpn) {
- VpnInfo info = vpn.getVpnInfo();
- if (info == null) {
- return null;
- }
- Network[] underlyingNetworks = vpn.getUnderlyingNetworks();
+ private VpnInfo createVpnInfo(NetworkAgentInfo nai) {
+ if (!nai.isVPN()) return null;
+
+ Network[] underlyingNetworks = nai.declaredUnderlyingNetworks;
// see VpnService.setUnderlyingNetworks()'s javadoc about how to interpret
// the underlyingNetworks list.
if (underlyingNetworks == null) {
@@ -4726,23 +4758,33 @@
underlyingNetworks = new Network[] { defaultNai.network };
}
}
- if (underlyingNetworks != null && underlyingNetworks.length > 0) {
- List<String> interfaces = new ArrayList<>();
- for (Network network : underlyingNetworks) {
- LinkProperties lp = getLinkProperties(network);
- if (lp != null) {
- for (String iface : lp.getAllInterfaceNames()) {
- if (!TextUtils.isEmpty(iface)) {
- interfaces.add(iface);
- }
- }
+
+ if (ArrayUtils.isEmpty(underlyingNetworks)) return null;
+
+ List<String> interfaces = new ArrayList<>();
+ for (Network network : underlyingNetworks) {
+ NetworkAgentInfo underlyingNai = getNetworkAgentInfoForNetwork(network);
+ if (underlyingNai == null) continue;
+ LinkProperties lp = underlyingNai.linkProperties;
+ for (String iface : lp.getAllInterfaceNames()) {
+ if (!TextUtils.isEmpty(iface)) {
+ interfaces.add(iface);
}
}
- if (!interfaces.isEmpty()) {
- info.underlyingIfaces = interfaces.toArray(new String[interfaces.size()]);
- }
}
- return info.underlyingIfaces == null ? null : info;
+
+ if (interfaces.isEmpty()) return null;
+
+ VpnInfo info = new VpnInfo();
+ info.ownerUid = nai.networkCapabilities.getOwnerUid();
+ info.vpnIface = nai.linkProperties.getInterfaceName();
+ // Must be non-null or NetworkStatsService will crash.
+ // Cannot happen in production code because Vpn only registers the NetworkAgent after the
+ // tun or ipsec interface is created.
+ if (info.vpnIface == null) return null;
+ info.underlyingIfaces = interfaces.toArray(new String[0]);
+
+ return info;
}
/**
@@ -4765,35 +4807,21 @@
}
/**
- * Ask all VPN objects to recompute and update their capabilities.
+ * Ask all networks with underlying networks to recompute and update their capabilities.
*
- * When underlying networks change, VPNs may have to update capabilities to reflect things
- * like the metered bit, their transports, and so on. This asks the VPN objects to update
- * their capabilities, and as this will cause them to send messages to the ConnectivityService
- * handler thread through their agent, this is asynchronous. When the capabilities objects
- * are computed they will be up-to-date as they are computed synchronously from here and
- * this is running on the ConnectivityService thread.
+ * When underlying networks change, such networks may have to update capabilities to reflect
+ * things like the metered bit, their transports, and so on. The capabilities are calculated
+ * immediately. This method runs on the ConnectivityService thread.
*/
- private void updateAllVpnsCapabilities() {
- Network defaultNetwork = getNetwork(getDefaultNetwork());
- synchronized (mVpns) {
- for (int i = 0; i < mVpns.size(); i++) {
- final Vpn vpn = mVpns.valueAt(i);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
+ private void propagateUnderlyingNetworkCapabilities() {
+ ensureRunningOnConnectivityServiceThread();
+ for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+ if (nai.supportsUnderlyingNetworks()) {
+ updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
}
}
}
- private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) {
- ensureRunningOnConnectivityServiceThread();
- NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId());
- if (vpnNai == null || nc == null) {
- return;
- }
- updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc);
- }
-
@Override
public boolean updateLockdownVpn() {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
@@ -5104,7 +5132,7 @@
}
}
- private void onUserStart(int userId) {
+ private void onUserStarted(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn != null) {
@@ -5119,7 +5147,7 @@
}
}
- private void onUserStop(int userId) {
+ private void onUserStopped(int userId) {
synchronized (mVpns) {
Vpn userVpn = mVpns.get(userId);
if (userVpn == null) {
@@ -5133,28 +5161,22 @@
private void onUserAdded(int userId) {
mPermissionMonitor.onUserAdded(userId);
- Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserAdded(userId);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
}
}
}
private void onUserRemoved(int userId) {
mPermissionMonitor.onUserRemoved(userId);
- Network defaultNetwork = getNetwork(getDefaultNetwork());
synchronized (mVpns) {
final int vpnsSize = mVpns.size();
for (int i = 0; i < vpnsSize; i++) {
Vpn vpn = mVpns.valueAt(i);
vpn.onUserRemoved(userId);
- NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork);
- updateVpnCapabilities(vpn, nc);
}
}
}
@@ -5236,9 +5258,9 @@
if (userId == UserHandle.USER_NULL) return;
if (Intent.ACTION_USER_STARTED.equals(action)) {
- onUserStart(userId);
+ onUserStarted(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
- onUserStop(userId);
+ onUserStopped(userId);
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
onUserAdded(userId);
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
@@ -5263,7 +5285,9 @@
// Try creating lockdown tracker, since user present usually means
// unlocked keystore.
updateLockdownVpn();
- mContext.unregisterReceiver(this);
+ // Use the same context that registered receiver before to unregister it. Because use
+ // different context to unregister receiver will cause exception.
+ context.unregisterReceiver(this);
}
};
@@ -5345,6 +5369,12 @@
}
}
+ private void ensureAllNetworkRequestsHaveType(List<NetworkRequest> requests) {
+ for (int i = 0; i < requests.size(); i++) {
+ ensureNetworkRequestHasType(requests.get(i));
+ }
+ }
+
private void ensureNetworkRequestHasType(NetworkRequest request) {
if (request.type == NetworkRequest.Type.NONE) {
throw new IllegalArgumentException(
@@ -5356,8 +5386,11 @@
* Tracks info about the requester.
* Also used to notice when the calling process dies so we can self-expire
*/
- private class NetworkRequestInfo implements IBinder.DeathRecipient {
+ @VisibleForTesting
+ protected class NetworkRequestInfo implements IBinder.DeathRecipient {
+ final List<NetworkRequest> mRequests;
final NetworkRequest request;
+
// The network currently satisfying this request, or null if none. Must only be touched
// on the handler thread. This only makes sense for network requests and not for listens,
// as defined by NetworkRequest#isRequest(). For listens, this is always null.
@@ -5372,7 +5405,8 @@
NetworkRequestInfo(NetworkRequest r, PendingIntent pi) {
request = r;
- ensureNetworkRequestHasType(request);
+ mRequests = initializeRequests(r);
+ ensureAllNetworkRequestsHaveType(mRequests);
mPendingIntent = pi;
messenger = null;
mBinder = null;
@@ -5385,7 +5419,8 @@
super();
messenger = m;
request = r;
- ensureNetworkRequestHasType(request);
+ mRequests = initializeRequests(r);
+ ensureAllNetworkRequestsHaveType(mRequests);
mBinder = binder;
mPid = getCallingPid();
mUid = getCallingUid();
@@ -5403,6 +5438,26 @@
this(r, null);
}
+ private List<NetworkRequest> initializeRequests(NetworkRequest r) {
+ final ArrayList<NetworkRequest> tempRequests = new ArrayList<>();
+ tempRequests.add(new NetworkRequest(r));
+ return Collections.unmodifiableList(tempRequests);
+ }
+
+ private NetworkRequest getSatisfiedRequest() {
+ if (mSatisfier == null) {
+ return null;
+ }
+
+ for (NetworkRequest req : mRequests) {
+ if (mSatisfier.isSatisfyingRequest(req.requestId)) {
+ return req;
+ }
+ }
+
+ return null;
+ }
+
private void enforceRequestCountLimit() {
synchronized (mUidToNetworkRequestCount) {
int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
@@ -5420,14 +5475,16 @@
}
}
+ @Override
public void binderDied() {
log("ConnectivityService NetworkRequestInfo binderDied(" +
- request + ", " + mBinder + ")");
- releaseNetworkRequest(request);
+ mRequests + ", " + mBinder + ")");
+ releaseNetworkRequest(mRequests);
}
+ @Override
public String toString() {
- return "uid/pid:" + mUid + "/" + mPid + " " + request
+ return "uid/pid:" + mUid + "/" + mPid + " " + mRequests
+ (mPendingIntent == null ? "" : " to trigger " + mPendingIntent);
}
}
@@ -5747,6 +5804,12 @@
return mNextNetworkProviderId.getAndIncrement();
}
+ private void releaseNetworkRequest(List<NetworkRequest> networkRequests) {
+ for (int i = 0; i < networkRequests.size(); i++) {
+ releaseNetworkRequest(networkRequests.get(i));
+ }
+ }
+
@Override
public void releaseNetworkRequest(NetworkRequest networkRequest) {
ensureNetworkRequestHasType(networkRequest);
@@ -5838,7 +5901,6 @@
@GuardedBy("mBlockedAppUids")
private final HashSet<Integer> mBlockedAppUids = new HashSet<>();
- // Note: if mDefaultRequest is changed, NetworkMonitor needs to be updated.
@NonNull
private final NetworkRequest mDefaultRequest;
// The NetworkAgentInfo currently satisfying the default request, if any.
@@ -5910,13 +5972,29 @@
int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
enforceAnyPermissionOf(Manifest.permission.MANAGE_TEST_NETWORKS);
+ } else {
+ enforceNetworkFactoryPermission();
+ }
+
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return registerNetworkAgentInternal(messenger, networkInfo, linkProperties,
+ networkCapabilities, currentScore, networkAgentConfig, providerId, uid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ private Network registerNetworkAgentInternal(Messenger messenger, NetworkInfo networkInfo,
+ LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
+ int currentScore, NetworkAgentConfig networkAgentConfig, int providerId, int uid) {
+ if (networkCapabilities.hasTransport(TRANSPORT_TEST)) {
// Strictly, sanitizing here is unnecessary as the capabilities will be sanitized in
// the call to mixInCapabilities below anyway, but sanitizing here means the NAI never
// sees capabilities that may be malicious, which might prevent mistakes in the future.
networkCapabilities = new NetworkCapabilities(networkCapabilities);
- networkCapabilities.restrictCapabilitesForTestNetwork(Binder.getCallingUid());
- } else {
- enforceNetworkFactoryPermission();
+ networkCapabilities.restrictCapabilitesForTestNetwork(uid);
}
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5927,9 +6005,10 @@
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
- this, mNetd, mDnsResolver, mNMS, providerId, Binder.getCallingUid());
+ this, mNetd, mDnsResolver, mNMS, providerId, uid);
// Make sure the LinkProperties and NetworkCapabilities reflect what the agent info says.
+ processCapabilitiesFromAgent(nai, nc);
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
processLinkPropertiesFromAgent(nai, nai.linkProperties);
@@ -5937,13 +6016,8 @@
final String name = TextUtils.isEmpty(extraInfo)
? nai.networkCapabilities.getSsid() : extraInfo;
if (DBG) log("registerNetworkAgent " + nai);
- final long token = Binder.clearCallingIdentity();
- try {
- mDeps.getNetworkStack().makeNetworkMonitor(
- nai.network, name, new NetworkMonitorCallbacks(nai));
- } finally {
- Binder.restoreCallingIdentity(token);
- }
+ mDeps.getNetworkStack().makeNetworkMonitor(
+ nai.network, name, new NetworkMonitorCallbacks(nai));
// NetworkAgentInfo registration will finish when the NetworkMonitor is created.
// If the network disconnects or sends any other event before that, messages are deferred by
// NetworkAgent until nai.asyncChannel.connect(), which will be called when finalizing the
@@ -5970,6 +6044,12 @@
updateUids(nai, null, nai.networkCapabilities);
}
+ /**
+ * Called when receiving LinkProperties directly from a NetworkAgent.
+ * Stores into |nai| any data coming from the agent that might also be written to the network's
+ * LinkProperties by ConnectivityService itself. This ensures that the data provided by the
+ * agent is not lost when updateLinkProperties is called.
+ */
private void processLinkPropertiesFromAgent(NetworkAgentInfo nai, LinkProperties lp) {
lp.ensureDirectlyConnectedRoutes();
nai.clatd.setNat64PrefixFromRa(lp.getNat64Prefix());
@@ -6080,7 +6160,7 @@
for (final String iface : interfaceDiff.added) {
try {
if (DBG) log("Adding iface " + iface + " to network " + netId);
- mNMS.addInterfaceToNetwork(iface, netId);
+ mNetd.networkAddInterface(netId, iface);
wakeupModifyInterface(iface, caps, true);
bs.noteNetworkInterfaceType(iface, legacyType);
} catch (Exception e) {
@@ -6092,7 +6172,7 @@
try {
if (DBG) log("Removing iface " + iface + " from network " + netId);
wakeupModifyInterface(iface, caps, false);
- mNMS.removeInterfaceFromNetwork(iface, netId);
+ mNetd.networkRemoveInterface(netId, iface);
} catch (Exception e) {
loge("Exception removing interface: " + e);
}
@@ -6195,20 +6275,12 @@
return; // no updating necessary
}
- final NetworkAgentInfo defaultNai = getDefaultNetwork();
- final boolean isDefaultNetwork = (defaultNai != null && defaultNai.network.netId == netId);
-
if (DBG) {
final Collection<InetAddress> dnses = newLp.getDnsServers();
log("Setting DNS servers for network " + netId + " to " + dnses);
}
try {
mDnsManager.noteDnsServersForNetwork(netId, newLp);
- // TODO: netd should listen on [::1]:53 and proxy queries to the current
- // default network, and we should just set net.dns1 to ::1, not least
- // because applications attempting to use net.dns resolvers will bypass
- // the privacy protections of things like DNS-over-TLS.
- if (isDefaultNetwork) mDnsManager.setDefaultDnsSystemProperties(newLp.getDnsServers());
mDnsManager.flushVmDnsCache();
} catch (Exception e) {
loge("Exception in setDnsConfigurationForNetwork: " + e);
@@ -6266,14 +6338,91 @@
final int newPermission = getNetworkPermission(newNc);
if (oldPermission != newPermission && nai.created && !nai.isVPN()) {
try {
- mNMS.setNetworkPermission(nai.network.netId, newPermission);
- } catch (RemoteException e) {
- loge("Exception in setNetworkPermission: " + e);
+ mNetd.networkSetPermissionForNetwork(nai.network.netId, newPermission);
+ } catch (RemoteException | ServiceSpecificException e) {
+ loge("Exception in networkSetPermissionForNetwork: " + e);
}
}
}
/**
+ * Called when receiving NetworkCapabilities directly from a NetworkAgent.
+ * Stores into |nai| any data coming from the agent that might also be written to the network's
+ * NetworkCapabilities by ConnectivityService itself. This ensures that the data provided by the
+ * agent is not lost when updateCapabilities is called.
+ */
+ private void processCapabilitiesFromAgent(NetworkAgentInfo nai, NetworkCapabilities nc) {
+ nai.declaredMetered = !nc.hasCapability(NET_CAPABILITY_NOT_METERED);
+ }
+
+ /** Modifies |caps| based on the capabilities of the specified underlying networks. */
+ @VisibleForTesting
+ void applyUnderlyingCapabilities(@Nullable Network[] underlyingNetworks,
+ @NonNull NetworkCapabilities caps, boolean declaredMetered) {
+ final Network defaultNetwork = getNetwork(getDefaultNetwork());
+ if (underlyingNetworks == null && defaultNetwork != null) {
+ // null underlying networks means to track the default.
+ underlyingNetworks = new Network[] { defaultNetwork };
+ }
+ int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN };
+ int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ int upKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
+ boolean metered = declaredMetered; // metered if any underlying is metered, or agentMetered
+ boolean roaming = false; // roaming if any underlying is roaming
+ boolean congested = false; // congested if any underlying is congested
+ boolean suspended = true; // suspended if all underlying are suspended
+
+ boolean hadUnderlyingNetworks = false;
+ if (null != underlyingNetworks) {
+ for (Network underlyingNetwork : underlyingNetworks) {
+ final NetworkAgentInfo underlying =
+ getNetworkAgentInfoForNetwork(underlyingNetwork);
+ if (underlying == null) continue;
+
+ final NetworkCapabilities underlyingCaps = underlying.networkCapabilities;
+ hadUnderlyingNetworks = true;
+ for (int underlyingType : underlyingCaps.getTransportTypes()) {
+ transportTypes = ArrayUtils.appendInt(transportTypes, underlyingType);
+ }
+
+ // Merge capabilities of this underlying network. For bandwidth, assume the
+ // worst case.
+ downKbps = NetworkCapabilities.minBandwidth(downKbps,
+ underlyingCaps.getLinkDownstreamBandwidthKbps());
+ upKbps = NetworkCapabilities.minBandwidth(upKbps,
+ underlyingCaps.getLinkUpstreamBandwidthKbps());
+ // If this underlying network is metered, the VPN is metered (it may cost money
+ // to send packets on this network).
+ metered |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_METERED);
+ // If this underlying network is roaming, the VPN is roaming (the billing structure
+ // is different than the usual, local one).
+ roaming |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_ROAMING);
+ // If this underlying network is congested, the VPN is congested (the current
+ // condition of the network affects the performance of this network).
+ congested |= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_CONGESTED);
+ // If this network is not suspended, the VPN is not suspended (the VPN
+ // is able to transfer some data).
+ suspended &= !underlyingCaps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ }
+ }
+ if (!hadUnderlyingNetworks) {
+ // No idea what the underlying networks are; assume reasonable defaults
+ metered = true;
+ roaming = false;
+ congested = false;
+ suspended = false;
+ }
+
+ caps.setTransportTypes(transportTypes);
+ caps.setLinkDownstreamBandwidthKbps(downKbps);
+ caps.setLinkUpstreamBandwidthKbps(upKbps);
+ caps.setCapability(NET_CAPABILITY_NOT_METERED, !metered);
+ caps.setCapability(NET_CAPABILITY_NOT_ROAMING, !roaming);
+ caps.setCapability(NET_CAPABILITY_NOT_CONGESTED, !congested);
+ caps.setCapability(NET_CAPABILITY_NOT_SUSPENDED, !suspended);
+ }
+
+ /**
* Augments the NetworkCapabilities passed in by a NetworkAgent with capabilities that are
* maintained here that the NetworkAgent is not aware of (e.g., validated, captive portal,
* and foreground status).
@@ -6326,6 +6475,10 @@
newNc.addCapability(NET_CAPABILITY_NOT_ROAMING);
}
+ if (nai.supportsUnderlyingNetworks()) {
+ applyUnderlyingCapabilities(nai.declaredUnderlyingNetworks, newNc, nai.declaredMetered);
+ }
+
return newNc;
}
@@ -6405,7 +6558,7 @@
if (!newNc.hasTransport(TRANSPORT_VPN)) {
// Tell VPNs about updated capabilities, since they may need to
// bubble those changes through.
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
if (!newNc.equalsTransportTypes(prevNc)) {
@@ -6438,8 +6591,8 @@
&& !nai.networkAgentConfig.allowBypass
&& nc.getOwnerUid() != Process.SYSTEM_UID
&& lp.getInterfaceName() != null
- && (lp.hasIPv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
- && (lp.hasIPv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
+ && (lp.hasIpv4DefaultRoute() || lp.hasIpv4UnreachableDefaultRoute())
+ && (lp.hasIpv6DefaultRoute() || lp.hasIpv6UnreachableDefaultRoute());
}
private void updateUids(NetworkAgentInfo nai, NetworkCapabilities prevNc,
@@ -6710,11 +6863,11 @@
try {
if (null != newNetwork) {
- mNMS.setDefaultNetId(newNetwork.network.netId);
+ mNetd.networkSetDefault(newNetwork.network.netId);
} else {
- mNMS.clearDefaultNetId();
+ mNetd.networkClearDefault();
}
- } catch (Exception e) {
+ } catch (RemoteException | ServiceSpecificException e) {
loge("Exception setting default network :" + e);
}
@@ -6723,11 +6876,9 @@
? 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();
+ propagateUnderlyingNetworkCapabilities();
}
private void processListenRequests(@NonNull final NetworkAgentInfo nai) {
@@ -6774,7 +6925,7 @@
}
public String toString() {
- return mRequest.request.requestId + " : "
+ return mRequest.mRequests.get(0).requestId + " : "
+ (null != mOldNetwork ? mOldNetwork.network.netId : "null")
+ " → " + (null != mNewNetwork ? mNewNetwork.network.netId : "null");
}
@@ -7189,7 +7340,7 @@
// onCapabilitiesUpdated being sent in updateAllVpnCapabilities below as
// the VPN would switch from its default, blank capabilities to those
// that reflect the capabilities of its underlying networks.
- updateAllVpnsCapabilities();
+ propagateUnderlyingNetworkCapabilities();
}
networkAgent.created = true;
}
@@ -7231,8 +7382,8 @@
// doing.
updateSignalStrengthThresholds(networkAgent, "CONNECT", null);
- if (networkAgent.isVPN()) {
- updateAllVpnsCapabilities();
+ if (networkAgent.supportsUnderlyingNetworks()) {
+ propagateUnderlyingNetworkCapabilities();
}
// Consider network even though it is not yet validated.
@@ -7489,13 +7640,6 @@
throwIfLockdownEnabled();
success = mVpns.get(user).setUnderlyingNetworks(networks);
}
- if (success) {
- mHandler.post(() -> {
- // Update VPN's capabilities based on updated underlying network set.
- updateAllVpnsCapabilities();
- notifyIfacesChangedForNetworkStats();
- });
- }
return success;
}
@@ -7659,14 +7803,14 @@
}
@Override
- public void onShellCommand(@NonNull FileDescriptor in, @NonNull FileDescriptor out,
- FileDescriptor err, @NonNull String[] args, ShellCallback callback,
- @NonNull ResultReceiver resultReceiver) {
- (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return new ShellCmd().exec(this, in.getFileDescriptor(), out.getFileDescriptor(),
+ err.getFileDescriptor(), args);
}
- private class ShellCmd extends ShellCommand {
-
+ private class ShellCmd extends BasicShellCommandHandler {
@Override
public int onCommand(String cmd) {
if (cmd == null) {
@@ -8171,13 +8315,12 @@
return false;
}
- final Network[] underlyingNetworks;
- synchronized (mVpns) {
- final Vpn vpn = getVpnIfOwner(callbackUid);
- underlyingNetworks = (vpn == null) ? null : vpn.getUnderlyingNetworks();
- }
- if (underlyingNetworks != null) {
- if (Arrays.asList(underlyingNetworks).contains(nai.network)) return true;
+ for (NetworkAgentInfo virtual : mNetworkAgentInfos.values()) {
+ if (virtual.supportsUnderlyingNetworks()
+ && virtual.networkCapabilities.getOwnerUid() == callbackUid
+ && ArrayUtils.contains(virtual.declaredUnderlyingNetworks, nai.network)) {
+ return true;
+ }
}
// Administrator UIDs also contains the Owner UID
diff --git a/services/core/java/com/android/server/ConnectivityServiceInitializer.java b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
new file mode 100644
index 0000000..2bc8925
--- /dev/null
+++ b/services/core/java/com/android/server/ConnectivityServiceInitializer.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_HIGH;
+import static android.os.IServiceManager.DUMP_FLAG_PRIORITY_NORMAL;
+
+import android.content.Context;
+import android.net.INetworkPolicyManager;
+import android.net.INetworkStatsService;
+import android.os.INetworkManagementService;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * Connectivity service initializer for core networking. This is called by system server to create
+ * a new instance of ConnectivityService.
+ */
+public final class ConnectivityServiceInitializer extends SystemService {
+ private static final String TAG = ConnectivityServiceInitializer.class.getSimpleName();
+ private final ConnectivityService mConnectivity;
+
+ public ConnectivityServiceInitializer(Context context) {
+ super(context);
+ // TODO: Define formal APIs to get the needed services.
+ mConnectivity = new ConnectivityService(context, getNetworkManagementService(),
+ getNetworkStatsService(), getNetworkPolicyManager());
+ }
+
+ @Override
+ public void onStart() {
+ Log.i(TAG, "Registering " + Context.CONNECTIVITY_SERVICE);
+ publishBinderService(Context.CONNECTIVITY_SERVICE, mConnectivity,
+ /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL);
+ }
+
+ private INetworkManagementService getNetworkManagementService() {
+ return INetworkManagementService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+ }
+
+ private INetworkStatsService getNetworkStatsService() {
+ return INetworkStatsService.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_STATS_SERVICE));
+ }
+
+ private INetworkPolicyManager getNetworkPolicyManager() {
+ return INetworkPolicyManager.Stub.asInterface(
+ ServiceManager.getService(Context.NETWORK_POLICY_SERVICE));
+ }
+
+}
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index d6bd5a1..a45466d 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -29,9 +29,9 @@
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.NetworkAgent;
+import android.net.NetworkAgentConfig;
import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.NetworkInfo.DetailedState;
+import android.net.NetworkProvider;
import android.net.RouteInfo;
import android.net.StringNetworkSpecifier;
import android.net.TestNetworkInterface;
@@ -62,7 +62,8 @@
/** @hide */
class TestNetworkService extends ITestNetworkManager.Stub {
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
- @NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
+ @NonNull private static final String TEST_NETWORK_LOGTAG = "TestNetworkAgent";
+ @NonNull private static final String TEST_NETWORK_PROVIDER_NAME = TAG;
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -72,6 +73,9 @@
@NonNull private final HandlerThread mHandlerThread;
@NonNull private final Handler mHandler;
+ @NonNull private final ConnectivityManager mCm;
+ @NonNull private final NetworkProvider mNetworkProvider;
+
// Native method stubs
private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
@@ -85,6 +89,10 @@
mContext = Objects.requireNonNull(context, "missing Context");
mNMS = Objects.requireNonNull(netManager, "missing INetworkManagementService");
mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance");
+ mCm = mContext.getSystemService(ConnectivityManager.class);
+ mNetworkProvider = new NetworkProvider(mContext, mHandler.getLooper(),
+ TEST_NETWORK_PROVIDER_NAME);
+ mCm.registerNetworkProvider(mNetworkProvider);
}
/**
@@ -150,9 +158,6 @@
private static final int NETWORK_SCORE = 1; // Use a low, non-zero score.
private final int mUid;
- @NonNull private final NetworkInfo mNi;
- @NonNull private final NetworkCapabilities mNc;
- @NonNull private final LinkProperties mLp;
@GuardedBy("mBinderLock")
@NonNull
@@ -161,20 +166,18 @@
@NonNull private final Object mBinderLock = new Object();
private TestNetworkAgent(
- @NonNull Looper looper,
@NonNull Context context,
- @NonNull NetworkInfo ni,
+ @NonNull Looper looper,
+ @NonNull NetworkAgentConfig config,
@NonNull NetworkCapabilities nc,
@NonNull LinkProperties lp,
int uid,
- @NonNull IBinder binder)
+ @NonNull IBinder binder,
+ @NonNull NetworkProvider np)
throws RemoteException {
- super(looper, context, TEST_NETWORK_TYPE, ni, nc, lp, NETWORK_SCORE);
+ super(context, looper, TEST_NETWORK_LOGTAG, nc, lp, NETWORK_SCORE, config, np);
mUid = uid;
- mNi = ni;
- mNc = nc;
- mLp = lp;
synchronized (mBinderLock) {
mBinder = binder; // Binder null-checks in create()
@@ -203,9 +206,7 @@
}
private void teardown() {
- mNi.setDetailedState(DetailedState.DISCONNECTED, null, null);
- mNi.setIsAvailable(false);
- sendNetworkInfo(mNi);
+ unregister();
// Synchronize on mBinderLock to ensure that unlinkToDeath is never called more than
// once (otherwise it could throw an exception)
@@ -238,11 +239,6 @@
Objects.requireNonNull(context, "missing Context");
// iface and binder validity checked by caller
- // Build network info with special testing type
- NetworkInfo ni = new NetworkInfo(ConnectivityManager.TYPE_TEST, 0, TEST_NETWORK_TYPE, "");
- ni.setDetailedState(DetailedState.CONNECTED, null, null);
- ni.setIsAvailable(true);
-
// Build narrow set of NetworkCapabilities, useful only for testing
NetworkCapabilities nc = new NetworkCapabilities();
nc.clearAll(); // Remove default capabilities.
@@ -290,7 +286,12 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null, iface));
}
- return new TestNetworkAgent(looper, context, ni, nc, lp, callingUid, binder);
+ final TestNetworkAgent agent = new TestNetworkAgent(context, looper,
+ new NetworkAgentConfig.Builder().build(), nc, lp, callingUid, binder,
+ mNetworkProvider);
+ agent.register();
+ agent.markConnected();
+ return agent;
}
/**
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index cf6a7f6..c789186 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -50,7 +50,6 @@
import java.net.InetAddress;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -238,24 +237,21 @@
private final Context mContext;
private final ContentResolver mContentResolver;
private final IDnsResolver mDnsResolver;
- private final MockableSystemProperties mSystemProperties;
private final ConcurrentHashMap<Integer, PrivateDnsConfig> mPrivateDnsMap;
// TODO: Replace the Map with SparseArrays.
private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap;
private final Map<Integer, LinkProperties> mLinkPropertiesMap;
private final Map<Integer, int[]> mTransportsMap;
- private int mNumDnsEntries;
private int mSampleValidity;
private int mSuccessThreshold;
private int mMinSamples;
private int mMaxSamples;
- public DnsManager(Context ctx, IDnsResolver dnsResolver, MockableSystemProperties sp) {
+ public DnsManager(Context ctx, IDnsResolver dnsResolver) {
mContext = ctx;
mContentResolver = mContext.getContentResolver();
mDnsResolver = dnsResolver;
- mSystemProperties = sp;
mPrivateDnsMap = new ConcurrentHashMap<>();
mPrivateDnsValidationMap = new HashMap<>();
mLinkPropertiesMap = new HashMap<>();
@@ -409,18 +405,6 @@
}
}
- public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) {
- int last = 0;
- for (InetAddress dns : dnses) {
- ++last;
- setNetDnsProperty(last, dns.getHostAddress());
- }
- for (int i = last + 1; i <= mNumDnsEntries; ++i) {
- setNetDnsProperty(i, "");
- }
- mNumDnsEntries = last;
- }
-
/**
* Flush DNS caches and events work before boot has completed.
*/
@@ -476,16 +460,6 @@
return Settings.Global.getInt(mContentResolver, which, dflt);
}
- private void setNetDnsProperty(int which, String value) {
- final String key = "net.dns" + which;
- // Log and forget errors setting unsupported properties.
- try {
- mSystemProperties.set(key, value);
- } catch (Exception e) {
- Slog.e(TAG, "Error setting unsupported net.dns property: ", e);
- }
- }
-
private static String getPrivateDnsMode(ContentResolver cr) {
String mode = getStringSetting(cr, PRIVATE_DNS_MODE);
if (TextUtils.isEmpty(mode)) mode = getStringSetting(cr, PRIVATE_DNS_DEFAULT_MODE);
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index 01fa9e7..8625a6f 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -47,7 +47,6 @@
import android.net.NetworkUtils;
import android.net.SocketKeepalive.InvalidSocketException;
import android.net.TcpKeepalivePacketData;
-import android.net.util.IpUtils;
import android.net.util.KeepaliveUtils;
import android.os.Binder;
import android.os.Handler;
@@ -63,6 +62,7 @@
import com.android.internal.R;
import com.android.internal.util.HexDump;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.net.module.util.IpUtils;
import java.io.FileDescriptor;
import java.net.InetAddress;
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index 04c000f..f99f4c6 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -159,8 +159,11 @@
@VisibleForTesting
protected PendingIntent createNotificationIntent() {
- return PendingIntent.getActivityAsUser(mContext, 0, CELLULAR_SETTINGS,
- PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
+ return PendingIntent.getActivity(
+ mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
+ 0 /* requestCode */,
+ CELLULAR_SETTINGS,
+ PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
// Removes any notification that was put up as a result of switching to nai.
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 3091a71..163788f 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -21,7 +21,7 @@
import android.net.IDnsResolver;
import android.net.INetd;
import android.net.InetAddresses;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -447,9 +447,10 @@
private LinkAddress getLinkAddress(String iface) {
try {
- InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
- return config.getLinkAddress();
- } catch (RemoteException | IllegalStateException e) {
+ final InterfaceConfigurationParcel config = mNetd.interfaceGetCfg(iface);
+ return new LinkAddress(
+ InetAddresses.parseNumericAddress(config.ipv4Addr), config.prefixLength);
+ } catch (IllegalArgumentException | RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error getting link properties: " + e);
return null;
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index a9f62d9..3270dd5 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -132,6 +132,16 @@
// TODO: make this private with a getter.
public NetworkCapabilities networkCapabilities;
public final NetworkAgentConfig networkAgentConfig;
+
+ // Underlying networks declared by the agent. Only set if supportsUnderlyingNetworks is true.
+ // The networks in this list might be declared by a VPN app using setUnderlyingNetworks and are
+ // not guaranteed to be current or correct, or even to exist.
+ public @Nullable Network[] declaredUnderlyingNetworks;
+
+ // Whether this network is always metered even if its underlying networks are unmetered.
+ // Only relevant if #supportsUnderlyingNetworks is true.
+ public boolean declaredMetered;
+
// Indicates if netd has been told to create this Network. From this point on the appropriate
// routing rules are setup and routes are added so packets can begin flowing over the Network.
// This is a sticky bit; once set it is never cleared.
@@ -474,10 +484,16 @@
networkCapabilities);
}
+ /** Whether this network is a VPN. */
public boolean isVPN() {
return networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_VPN);
}
+ /** Whether this network might have underlying networks. Currently only true for VPNs. */
+ public boolean supportsUnderlyingNetworks() {
+ return isVPN();
+ }
+
private int getCurrentScore(boolean pretendValidated) {
// TODO: We may want to refactor this into a NetworkScore class that takes a base score from
// the NetworkAgent and signals from the NetworkAgent and uses those signals to modify the
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 34b0aa2..7f4fb40 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -21,6 +21,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import android.annotation.NonNull;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -42,7 +43,6 @@
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
public class NetworkNotificationManager {
@@ -73,18 +73,29 @@
private static final String TAG = NetworkNotificationManager.class.getSimpleName();
private static final boolean DBG = true;
- private static final boolean VDBG = false;
+ // Notification channels used by ConnectivityService mainline module, it should be aligned with
+ // SystemNotificationChannels so the channels are the same as the ones used as the system
+ // server.
+ public static final String NOTIFICATION_CHANNEL_NETWORK_STATUS = "NETWORK_STATUS";
+ public static final String NOTIFICATION_CHANNEL_NETWORK_ALERTS = "NETWORK_ALERTS";
+ public static final String NOTIFICATION_CHANNEL_VPN = "VPN";
+
+ // The context is for the current user (system server)
private final Context mContext;
private final TelephonyManager mTelephonyManager;
+ // The notification manager is created from a context for User.ALL, so notifications
+ // will be sent to all users.
private final NotificationManager mNotificationManager;
// Tracks the types of notifications managed by this instance, from creation to cancellation.
private final SparseIntArray mNotificationTypeMap;
- public NetworkNotificationManager(Context c, TelephonyManager t, NotificationManager n) {
+ public NetworkNotificationManager(@NonNull final Context c, @NonNull final TelephonyManager t) {
mContext = c;
mTelephonyManager = t;
- mNotificationManager = n;
+ mNotificationManager =
+ (NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
+ .getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationTypeMap = new SparseIntArray();
}
@@ -253,8 +264,7 @@
// the tag.
final boolean hasPreviousNotification = previousNotifyType != null;
final String channelId = (highPriority && !hasPreviousNotification)
- ? SystemNotificationChannels.NETWORK_ALERTS
- : SystemNotificationChannels.NETWORK_STATUS;
+ ? NOTIFICATION_CHANNEL_NETWORK_ALERTS : NOTIFICATION_CHANNEL_NETWORK_STATUS;
Notification.Builder builder = new Notification.Builder(mContext, channelId)
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
@@ -282,7 +292,7 @@
mNotificationTypeMap.put(id, eventId);
try {
- mNotificationManager.notifyAsUser(tag, eventId, notification, UserHandle.ALL);
+ mNotificationManager.notify(tag, eventId, notification);
} catch (NullPointerException npe) {
Slog.d(TAG, "setNotificationVisible: visible notificationManager error", npe);
}
@@ -311,7 +321,7 @@
nameOf(eventId)));
}
try {
- mNotificationManager.cancelAsUser(tag, eventId, UserHandle.ALL);
+ mNotificationManager.cancel(tag, eventId);
} catch (NullPointerException npe) {
Slog.d(TAG, String.format(
"failed to clear notification tag=%s event=%s", tag, nameOf(eventId)), npe);
@@ -325,7 +335,8 @@
public void setProvNotificationVisible(boolean visible, int id, String action) {
if (visible) {
Intent intent = new Intent(action);
- PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, intent, PendingIntent.FLAG_IMMUTABLE);
showNotification(id, NotificationType.SIGN_IN, null, null, pendingIntent, false);
} else {
clearNotification(id);
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index a75a80a..4c63eb4 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -174,7 +174,7 @@
netdPermsUids.put(uid, netdPermsUids.get(uid) | otherNetdPerms);
}
- List<UserInfo> users = mUserManager.getUsers(true); // exclude dying users
+ List<UserInfo> users = mUserManager.getAliveUsers();
if (users != null) {
for (UserInfo user : users) {
mUsers.add(user.id);
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 0fe84ab..a762219 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -50,6 +50,7 @@
platform_apis: true,
test_suites: ["device-tests"],
certificate: "platform",
+ jarjar_rules: "jarjar-rules.txt",
static_libs: [
"androidx.test.rules",
"FrameworksNetCommonTests",
@@ -59,6 +60,7 @@
"mockito-target-minus-junit4",
"net-tests-utils",
"platform-test-annotations",
+ "service-connectivity",
"services.core",
"services.net",
],
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
index 005cbe9..89fc6ea 100644
--- a/tests/net/TEST_MAPPING
+++ b/tests/net/TEST_MAPPING
@@ -8,5 +8,10 @@
{
"name": "FrameworksNetDeflakeTest"
}
+ ],
+ "imports": [
+ {
+ "path": "cts/tests/tests/net"
+ }
]
}
\ No newline at end of file
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
index 46d680f..373aac6 100644
--- a/tests/net/common/Android.bp
+++ b/tests/net/common/Android.bp
@@ -25,6 +25,7 @@
"junit",
"mockito-target-minus-junit4",
"net-tests-utils",
+ "net-utils-framework-common",
"platform-test-annotations",
],
libs: [
diff --git a/tests/net/common/java/android/net/LinkPropertiesTest.java b/tests/net/common/java/android/net/LinkPropertiesTest.java
index 3c3076f..550953d 100644
--- a/tests/net/common/java/android/net/LinkPropertiesTest.java
+++ b/tests/net/common/java/android/net/LinkPropertiesTest.java
@@ -32,7 +32,6 @@
import static org.junit.Assert.fail;
import android.net.LinkProperties.ProvisioningChange;
-import android.net.util.LinkPropertiesUtils.CompareResult;
import android.os.Build;
import android.system.OsConstants;
import android.util.ArraySet;
@@ -41,6 +40,7 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter;
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
@@ -52,7 +52,6 @@
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
-import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -447,23 +446,21 @@
assertEquals(3, lp.getRoutes().size());
assertAllRoutesHaveInterface("wlan0", lp);
- // Check comparisons work.
+ // Check routes are updated correctly when calling setInterfaceName.
LinkProperties lp2 = new LinkProperties(lp);
assertAllRoutesHaveInterface("wlan0", lp2);
- // LinkProperties#compareAllRoutes exists both in R and before R, but the return type
- // changed in R, so a test compiled with the R version of LinkProperties cannot run on Q.
- if (isAtLeastR()) {
- assertEquals(0, lp.compareAllRoutes(lp2).added.size());
- assertEquals(0, lp.compareAllRoutes(lp2).removed.size());
- }
+ final CompareResult<RouteInfo> cr1 =
+ new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes());
+ assertEquals(0, cr1.added.size());
+ assertEquals(0, cr1.removed.size());
lp2.setInterfaceName("p2p0");
assertAllRoutesHaveInterface("p2p0", lp2);
assertAllRoutesNotHaveInterface("wlan0", lp2);
- if (isAtLeastR()) {
- assertEquals(3, lp.compareAllRoutes(lp2).added.size());
- assertEquals(3, lp.compareAllRoutes(lp2).removed.size());
- }
+ final CompareResult<RouteInfo> cr2 =
+ new CompareResult<>(lp.getAllRoutes(), lp2.getAllRoutes());
+ assertEquals(3, cr2.added.size());
+ assertEquals(3, cr2.removed.size());
// Remove route with incorrect interface, no route removed.
lp.removeRoute(new RouteInfo(prefix2, null, null));
@@ -954,28 +951,6 @@
assertTrue(rmnet3.getAllRoutes().isEmpty());
rmnet3.ensureDirectlyConnectedRoutes();
assertEqualRoutes(Collections.singletonList(directRoute3), rmnet3.getAllRoutes());
-
- }
-
- @Test @IgnoreUpTo(Build.VERSION_CODES.Q)
- public void testCompareResult() {
- // Either adding or removing items
- compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(1),
- Arrays.asList(2, 3, 4), new ArrayList<>());
- compareResult(Arrays.asList(1, 2), Arrays.asList(3, 2, 1, 4),
- new ArrayList<>(), Arrays.asList(3, 4));
-
-
- // adding and removing items at the same time
- compareResult(Arrays.asList(1, 2, 3, 4), Arrays.asList(2, 3, 4, 5),
- Arrays.asList(1), Arrays.asList(5));
- compareResult(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6),
- Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));
-
- // null cases
- compareResult(Arrays.asList(1, 2, 3), null, Arrays.asList(1, 2, 3), new ArrayList<>());
- compareResult(null, Arrays.asList(3, 2, 1), new ArrayList<>(), Arrays.asList(1, 2, 3));
- compareResult(null, null, new ArrayList<>(), new ArrayList<>());
}
private void assertEqualRoutes(Collection<RouteInfo> expected, Collection<RouteInfo> actual) {
@@ -987,13 +962,6 @@
assertEquals(expectedSet, actualSet);
}
- private <T> void compareResult(List<T> oldItems, List<T> newItems, List<T> expectRemoved,
- List<T> expectAdded) {
- CompareResult<T> result = new CompareResult<>(oldItems, newItems);
- assertEquals(new ArraySet<>(expectAdded), new ArraySet<>(result.added));
- assertEquals(new ArraySet<>(expectRemoved), (new ArraySet<>(result.removed)));
- }
-
private static LinkProperties makeLinkPropertiesForParceling() {
LinkProperties source = new LinkProperties();
source.setInterfaceName(NAME);
diff --git a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
index a50f046..a5e44d5 100644
--- a/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
+++ b/tests/net/common/java/android/net/MatchAllNetworkSpecifierTest.kt
@@ -19,13 +19,19 @@
import android.net.wifi.aware.DiscoverySession
import android.net.wifi.aware.PeerHandle
import android.net.wifi.aware.WifiAwareNetworkSpecifier
+import android.os.Build
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import java.lang.IllegalStateException
+import org.junit.Assert.assertFalse
+import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
@@ -33,18 +39,37 @@
@RunWith(AndroidJUnit4::class)
@SmallTest
class MatchAllNetworkSpecifierTest {
+ @Rule @JvmField
+ val ignoreRule: DevSdkIgnoreRule = DevSdkIgnoreRule()
+
+ private val specifier = MatchAllNetworkSpecifier()
+ private val discoverySession = Mockito.mock(DiscoverySession::class.java)
+ private val peerHandle = Mockito.mock(PeerHandle::class.java)
+ private val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
+ peerHandle).build()
+
@Test
fun testParcel() {
assertParcelSane(MatchAllNetworkSpecifier(), 0)
}
+ @Test
+ @IgnoreUpTo(Build.VERSION_CODES.Q)
+ @IgnoreAfter(Build.VERSION_CODES.R)
+ // Only run this test on Android R.
+ // The method - satisfiedBy() has changed to canBeSatisfiedBy() starting from Android R, so the
+ // method - canBeSatisfiedBy() cannot be found when running this test on Android Q.
+ fun testCanBeSatisfiedBy_OnlyForR() {
+ // MatchAllNetworkSpecifier didn't follow its parent class to change the satisfiedBy() to
+ // canBeSatisfiedBy(), so if a caller calls MatchAllNetworkSpecifier#canBeSatisfiedBy(), the
+ // NetworkSpecifier#canBeSatisfiedBy() will be called actually, and false will be returned.
+ // Although it's not meeting the expectation, the behavior still needs to be verified.
+ assertFalse(specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier))
+ }
+
@Test(expected = IllegalStateException::class)
+ @IgnoreUpTo(Build.VERSION_CODES.R)
fun testCanBeSatisfiedBy() {
- val specifier = MatchAllNetworkSpecifier()
- val discoverySession = Mockito.mock(DiscoverySession::class.java)
- val peerHandle = Mockito.mock(PeerHandle::class.java)
- val wifiAwareNetworkSpecifier = WifiAwareNetworkSpecifier.Builder(discoverySession,
- peerHandle).build()
specifier.canBeSatisfiedBy(wifiAwareNetworkSpecifier)
}
}
diff --git a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
index e169312..6b7ea66 100644
--- a/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
+++ b/tests/net/common/java/android/net/NetworkCapabilitiesTest.java
@@ -30,6 +30,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PRIVATE;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_WIFI_P2P;
@@ -358,6 +359,33 @@
assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
}
+ @Test @IgnoreUpTo(Build.VERSION_CODES.R)
+ public void testOemPrivate() {
+ NetworkCapabilities nc = new NetworkCapabilities();
+ // By default OEM_PRIVATE is neither in the unwanted or required lists and the network is
+ // not restricted.
+ assertFalse(nc.hasUnwantedCapability(NET_CAPABILITY_OEM_PRIVATE));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE));
+ nc.maybeMarkCapabilitiesRestricted();
+ assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // Adding OEM_PRIVATE to capability list should make network restricted.
+ nc.addCapability(NET_CAPABILITY_OEM_PRIVATE);
+ nc.addCapability(NET_CAPABILITY_INTERNET); // Combine with unrestricted capability.
+ nc.maybeMarkCapabilitiesRestricted();
+ assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PRIVATE));
+ assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // Now let's make request for OEM_PRIVATE network.
+ NetworkCapabilities nr = new NetworkCapabilities();
+ nr.addCapability(NET_CAPABILITY_OEM_PRIVATE);
+ nr.maybeMarkCapabilitiesRestricted();
+ assertTrue(nr.satisfiedByNetworkCapabilities(nc));
+
+ // Request fails for network with the default capabilities.
+ assertFalse(nr.satisfiedByNetworkCapabilities(new NetworkCapabilities()));
+ }
+
@Test
public void testUnwantedCapabilities() {
NetworkCapabilities network = new NetworkCapabilities();
diff --git a/tests/net/common/java/android/net/OemNetworkPreferencesTest.java b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
new file mode 100644
index 0000000..cade5ba
--- /dev/null
+++ b/tests/net/common/java/android/net/OemNetworkPreferencesTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import static com.android.testutils.MiscAsserts.assertThrows;
+import static com.android.testutils.ParcelUtils.assertParcelSane;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Build;
+import android.util.SparseArray;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@IgnoreUpTo(Build.VERSION_CODES.R)
+@RunWith(DevSdkIgnoreRunner.class)
+@SmallTest
+public class OemNetworkPreferencesTest {
+
+ private static final int TEST_PREF = OemNetworkPreferences.OEM_NETWORK_PREFERENCE_DEFAULT;
+ private static final String TEST_PACKAGE = "com.google.apps.contacts";
+
+ private final List<String> mPackages = new ArrayList<>();
+ private final OemNetworkPreferences.Builder mBuilder = new OemNetworkPreferences.Builder();
+
+ @Before
+ public void beforeEachTestMethod() {
+ mPackages.add(TEST_PACKAGE);
+ }
+
+ @Test
+ public void builderAddNetworkPreferenceRequiresNonNullPackages() {
+ assertThrows(NullPointerException.class,
+ () -> mBuilder.addNetworkPreference(TEST_PREF, null));
+ }
+
+ @Test
+ public void getNetworkPreferencesReturnsCorrectValue() {
+ final int expectedNumberOfMappings = 1;
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final SparseArray<List<String>> networkPreferences =
+ mBuilder.build().getNetworkPreferences();
+
+ assertEquals(expectedNumberOfMappings, networkPreferences.size());
+ assertEquals(mPackages.size(), networkPreferences.get(TEST_PREF).size());
+ assertEquals(mPackages.get(0), networkPreferences.get(TEST_PREF).get(0));
+ }
+
+ @Test
+ public void getNetworkPreferencesReturnsUnmodifiableValue() {
+ final String newPackage = "new.com.google.apps.contacts";
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final SparseArray<List<String>> networkPreferences =
+ mBuilder.build().getNetworkPreferences();
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> networkPreferences.get(TEST_PREF).set(mPackages.size() - 1, newPackage));
+
+ assertThrows(UnsupportedOperationException.class,
+ () -> networkPreferences.get(TEST_PREF).add(newPackage));
+ }
+
+ @Test
+ public void toStringReturnsCorrectValue() {
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final String networkPreferencesString = mBuilder.build().getNetworkPreferences().toString();
+
+ assertTrue(networkPreferencesString.contains(Integer.toString(TEST_PREF)));
+ assertTrue(networkPreferencesString.contains(TEST_PACKAGE));
+ }
+
+ @Test
+ public void testOemNetworkPreferencesParcelable() {
+ mBuilder.addNetworkPreference(TEST_PREF, mPackages);
+
+ final OemNetworkPreferences prefs = mBuilder.build();
+
+ assertParcelSane(prefs, 1 /* fieldCount */);
+ }
+}
diff --git a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
index bc069e1..70f6386 100644
--- a/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
+++ b/tests/net/integration/src/com/android/server/net/integrationtests/ConnectivityServiceIntegrationTest.kt
@@ -167,7 +167,7 @@
cm = ConnectivityManager(context, service)
context.addMockSystemService(Context.CONNECTIVITY_SERVICE, cm)
- service.systemReady()
+ service.systemReadyInternal()
}
private inner class TestConnectivityService(deps: Dependencies) : ConnectivityService(
@@ -200,7 +200,8 @@
nsInstrumentation.addHttpResponse(HttpResponse(httpProbeUrl, responseCode = 204))
nsInstrumentation.addHttpResponse(HttpResponse(httpsProbeUrl, responseCode = 204))
- val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), context)
+ val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, LinkProperties(), null /* ncTemplate */,
+ context)
networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
na.addCapability(NET_CAPABILITY_INTERNET)
@@ -238,7 +239,7 @@
val lp = LinkProperties()
lp.captivePortalApiUrl = Uri.parse(apiUrl)
- val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, context)
+ val na = NetworkAgentWrapper(TRANSPORT_CELLULAR, lp, null /* ncTemplate */, context)
networkStackClient.verifyNetworkMonitorCreated(na.network, TEST_TIMEOUT_MS)
na.addCapability(NET_CAPABILITY_INTERNET)
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index c895420..2a24d1a 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -72,12 +72,12 @@
private long mKeepaliveResponseDelay = 0L;
private Integer mExpectedKeepaliveSlot = null;
- public NetworkAgentWrapper(int transport, LinkProperties linkProperties, Context context)
- throws Exception {
+ public NetworkAgentWrapper(int transport, LinkProperties linkProperties,
+ NetworkCapabilities ncTemplate, Context context) throws Exception {
final int type = transportToLegacyType(transport);
final String typeName = ConnectivityManager.getNetworkTypeName(type);
mNetworkInfo = new NetworkInfo(type, 0, typeName, "Mock");
- mNetworkCapabilities = new NetworkCapabilities();
+ mNetworkCapabilities = (ncTemplate != null) ? ncTemplate : new NetworkCapabilities();
mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mNetworkCapabilities.addTransportType(transport);
switch (transport) {
@@ -213,7 +213,7 @@
public void connect() {
assertNotEquals("MockNetworkAgents can only be connected once",
- getNetworkInfo().getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
+ mNetworkInfo.getDetailedState(), NetworkInfo.DetailedState.CONNECTED);
mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
}
@@ -268,10 +268,6 @@
return mNetworkAgent;
}
- public NetworkInfo getNetworkInfo() {
- return mNetworkInfo;
- }
-
public NetworkCapabilities getNetworkCapabilities() {
return mNetworkCapabilities;
}
diff --git a/tests/net/integration/util/com/android/server/TestNetIdManager.kt b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
index eb290dc..938a694 100644
--- a/tests/net/integration/util/com/android/server/TestNetIdManager.kt
+++ b/tests/net/integration/util/com/android/server/TestNetIdManager.kt
@@ -35,4 +35,5 @@
private val nextId = AtomicInteger(MAX_NET_ID)
override fun reserveNetId() = nextId.decrementAndGet()
override fun releaseNetId(id: Int) = Unit
+ fun peekNextNetId() = nextId.get() - 1
}
diff --git a/tests/net/jarjar-rules.txt b/tests/net/jarjar-rules.txt
new file mode 100644
index 0000000..ca88672
--- /dev/null
+++ b/tests/net/jarjar-rules.txt
@@ -0,0 +1,2 @@
+# Module library in frameworks/libs/net
+rule com.android.net.module.util.** android.net.frameworktests.util.@1
diff --git a/tests/net/java/android/net/IpSecAlgorithmTest.java b/tests/net/java/android/net/IpSecAlgorithmTest.java
index 8e9d08c..2e1c29a 100644
--- a/tests/net/java/android/net/IpSecAlgorithmTest.java
+++ b/tests/net/java/android/net/IpSecAlgorithmTest.java
@@ -16,34 +16,50 @@
package android.net;
+import static android.net.IpSecAlgorithm.ALGO_TO_REQUIRED_FIRST_SDK;
+
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import android.content.res.Resources;
+import android.os.Build;
import android.os.Parcel;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
+import com.android.internal.util.CollectionUtils;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import java.util.AbstractMap.SimpleEntry;
import java.util.Arrays;
+import java.util.HashSet;
import java.util.Map.Entry;
import java.util.Random;
+import java.util.Set;
/** Unit tests for {@link IpSecAlgorithm}. */
@SmallTest
@RunWith(AndroidJUnit4.class)
public class IpSecAlgorithmTest {
-
private static final byte[] KEY_MATERIAL;
+ private final Resources mMockResources = mock(Resources.class);
+
static {
KEY_MATERIAL = new byte[128];
new Random().nextBytes(KEY_MATERIAL);
};
+ private static byte[] generateKey(int keyLenInBits) {
+ return Arrays.copyOf(KEY_MATERIAL, keyLenInBits / 8);
+ }
+
@Test
public void testNoTruncLen() throws Exception {
Entry<String, Integer>[] authAndAeadList =
@@ -53,7 +69,7 @@
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA256, 256),
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA384, 384),
new SimpleEntry<>(IpSecAlgorithm.AUTH_HMAC_SHA512, 512),
- new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224)
+ new SimpleEntry<>(IpSecAlgorithm.AUTH_CRYPT_AES_GCM, 224),
};
// Expect auth and aead algorithms to throw errors if trunclen is omitted.
@@ -70,6 +86,52 @@
new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, Arrays.copyOf(KEY_MATERIAL, 256 / 8));
}
+ private void checkAuthKeyAndTruncLenValidation(String algoName, int keyLen, int truncLen)
+ throws Exception {
+ new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen);
+
+ try {
+ new IpSecAlgorithm(algoName, generateKey(keyLen));
+ fail("Expected exception on unprovided auth trunclen");
+ } catch (IllegalArgumentException pass) {
+ }
+
+ try {
+ new IpSecAlgorithm(algoName, generateKey(keyLen + 8), truncLen);
+ fail("Invalid key length not validated");
+ } catch (IllegalArgumentException pass) {
+ }
+
+ try {
+ new IpSecAlgorithm(algoName, generateKey(keyLen), truncLen + 1);
+ fail("Invalid truncation length not validated");
+ } catch (IllegalArgumentException pass) {
+ }
+ }
+
+ private void checkCryptKeyLenValidation(String algoName, int keyLen) throws Exception {
+ new IpSecAlgorithm(algoName, generateKey(keyLen));
+
+ try {
+ new IpSecAlgorithm(algoName, generateKey(keyLen + 8));
+ fail("Invalid key length not validated");
+ } catch (IllegalArgumentException pass) {
+ }
+ }
+
+ @Test
+ public void testValidationForAlgosAddedInS() throws Exception {
+ if (Build.VERSION.FIRST_SDK_INT <= Build.VERSION_CODES.R) {
+ return;
+ }
+
+ for (int len : new int[] {160, 224, 288}) {
+ checkCryptKeyLenValidation(IpSecAlgorithm.CRYPT_AES_CTR, len);
+ }
+ checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_AES_XCBC, 128, 96);
+ checkAuthKeyAndTruncLenValidation(IpSecAlgorithm.AUTH_CRYPT_CHACHA20_POLY1305, 288, 128);
+ }
+
@Test
public void testTruncLenValidation() throws Exception {
for (int truncLen : new int[] {256, 512}) {
@@ -127,4 +189,37 @@
assertTrue("Parcel/Unparcel failed!", IpSecAlgorithm.equals(init, fin));
p.recycle();
}
+
+ private static Set<String> getMandatoryAlgos() {
+ return CollectionUtils.filter(
+ ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
+ i -> Build.VERSION.FIRST_SDK_INT >= ALGO_TO_REQUIRED_FIRST_SDK.get(i));
+ }
+
+ private static Set<String> getOptionalAlgos() {
+ return CollectionUtils.filter(
+ ALGO_TO_REQUIRED_FIRST_SDK.keySet(),
+ i -> Build.VERSION.FIRST_SDK_INT < ALGO_TO_REQUIRED_FIRST_SDK.get(i));
+ }
+
+ @Test
+ public void testGetSupportedAlgorithms() throws Exception {
+ assertTrue(IpSecAlgorithm.getSupportedAlgorithms().containsAll(getMandatoryAlgos()));
+ assertTrue(ALGO_TO_REQUIRED_FIRST_SDK.keySet().containsAll(
+ IpSecAlgorithm.getSupportedAlgorithms()));
+ }
+
+ @Test
+ public void testLoadAlgos() throws Exception {
+ final Set<String> optionalAlgoSet = getOptionalAlgos();
+ final String[] optionalAlgos = optionalAlgoSet.toArray(new String[0]);
+
+ doReturn(optionalAlgos).when(mMockResources)
+ .getStringArray(com.android.internal.R.array.config_optionalIpSecAlgorithms);
+
+ final Set<String> enabledAlgos = new HashSet<>(IpSecAlgorithm.loadAlgos(mMockResources));
+ final Set<String> expectedAlgos = ALGO_TO_REQUIRED_FIRST_SDK.keySet();
+
+ assertEquals(expectedAlgos, enabledAlgos);
+ }
}
diff --git a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
index 02f5286..603c875 100644
--- a/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
+++ b/tests/net/java/android/net/ipmemorystore/ParcelableTests.java
@@ -19,6 +19,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk;
+import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirkParcelable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -46,7 +48,7 @@
builder.setAssignedV4Address((Inet4Address) Inet4Address.getByName("1.2.3.4"));
// lease will expire in two hours
builder.setAssignedV4AddressExpiry(System.currentTimeMillis() + 7_200_000);
- // groupHint stays null this time around
+ // cluster stays null this time around
builder.setDnsAddresses(Collections.emptyList());
builder.setMtu(18);
in = builder.build();
@@ -69,7 +71,7 @@
// Verify that this test does not miss any new field added later.
// If any field is added to NetworkAttributes it must be tested here for parceling
// roundtrip.
- assertEquals(5, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
+ assertEquals(6, Arrays.stream(NetworkAttributes.class.getDeclaredFields())
.filter(f -> !Modifier.isStatic(f.getModifiers())).count());
}
@@ -104,6 +106,22 @@
assertEquals(in.confidence, out.confidence, 0.01f /* delta */);
}
+ @Test
+ public void testIPv6ProvisioningLossQuirkParceling() throws Exception {
+ final NetworkAttributes.Builder builder = new NetworkAttributes.Builder();
+ final IPv6ProvisioningLossQuirkParcelable parcelable =
+ new IPv6ProvisioningLossQuirkParcelable();
+ final long expiry = System.currentTimeMillis() + 7_200_000;
+
+ parcelable.detectionCount = 3;
+ parcelable.quirkExpiry = expiry; // quirk info will expire in two hours
+ builder.setIpv6ProvLossQuirk(IPv6ProvisioningLossQuirk.fromStableParcelable(parcelable));
+ final NetworkAttributes in = builder.build();
+
+ final NetworkAttributes out = new NetworkAttributes(parcelingRoundTrip(in.toParcelable()));
+ assertEquals(out.ipv6ProvisioningLossQuirk, in.ipv6ProvisioningLossQuirk);
+ }
+
private <T extends Parcelable> T parcelingRoundTrip(final T in) throws Exception {
final Parcel p = Parcel.obtain();
in.writeToParcel(p, /* flags */ 0);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 862e552..7a1cb25 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.content.Intent.ACTION_USER_ADDED;
+import static android.content.Intent.ACTION_USER_REMOVED;
import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
import static android.content.pm.PackageManager.GET_PERMISSIONS;
import static android.content.pm.PackageManager.MATCH_ANY_USER;
@@ -54,8 +56,10 @@
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_CONGESTED;
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_NOT_SUSPENDED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
@@ -147,6 +151,7 @@
import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread;
import android.net.DataStallReportParcelable;
+import android.net.EthernetManager;
import android.net.IConnectivityDiagnosticsCallback;
import android.net.IDnsResolver;
import android.net.IIpConnectivityMetrics;
@@ -157,7 +162,7 @@
import android.net.INetworkPolicyManager;
import android.net.INetworkStatsService;
import android.net.InetAddresses;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.IpSecManager;
import android.net.IpSecManager.UdpEncapsulationSocket;
@@ -250,6 +255,7 @@
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -257,7 +263,10 @@
import org.mockito.Spy;
import org.mockito.stubbing.Answer;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -313,11 +322,14 @@
private static final long TIMESTAMP = 1234L;
private static final int NET_ID = 110;
+ // Set a non-zero value to verify the flow to set tcp init rwnd value.
+ private static final int TEST_TCP_INIT_RWND = 60;
private static final String CLAT_PREFIX = "v4-";
private static final String MOBILE_IFNAME = "test_rmnet_data0";
private static final String WIFI_IFNAME = "test_wlan0";
private static final String WIFI_WOL_IFNAME = "test_wlan_wol";
+ private static final String VPN_IFNAME = "tun10042";
private static final String TEST_PACKAGE_NAME = "com.android.test.package";
private static final String[] EMPTY_STRING_ARRAY = new String[0];
@@ -335,6 +347,7 @@
private INetworkPolicyListener mPolicyListener;
private WrappedMultinetworkPolicyTracker mPolicyTracker;
private HandlerThread mAlarmManagerThread;
+ private TestNetIdManager mNetIdManager;
@Mock IIpConnectivityMetrics mIpConnectivityMetrics;
@Mock IpConnectivityMetrics.Logger mMetricsService;
@@ -355,6 +368,8 @@
@Mock LocationManager mLocationManager;
@Mock AppOpsManager mAppOpsManager;
@Mock TelephonyManager mTelephonyManager;
+ @Mock MockableSystemProperties mSystemProperties;
+ @Mock EthernetManager mEthernetManager;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -442,10 +457,18 @@
if (Context.LOCATION_SERVICE.equals(name)) return mLocationManager;
if (Context.APP_OPS_SERVICE.equals(name)) return mAppOpsManager;
if (Context.TELEPHONY_SERVICE.equals(name)) return mTelephonyManager;
+ if (Context.ETHERNET_SERVICE.equals(name)) return mEthernetManager;
return super.getSystemService(name);
}
@Override
+ public Context createContextAsUser(UserHandle user, int flags) {
+ final Context asUser = mock(Context.class, AdditionalAnswers.delegatesTo(this));
+ doReturn(user).when(asUser).getUser();
+ return asUser;
+ }
+
+ @Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
@@ -603,12 +626,17 @@
private String mRedirectUrl;
TestNetworkAgentWrapper(int transport) throws Exception {
- this(transport, new LinkProperties());
+ this(transport, new LinkProperties(), null);
}
TestNetworkAgentWrapper(int transport, LinkProperties linkProperties)
throws Exception {
- super(transport, linkProperties, mServiceContext);
+ this(transport, linkProperties, null);
+ }
+
+ private TestNetworkAgentWrapper(int transport, LinkProperties linkProperties,
+ NetworkCapabilities ncTemplate) throws Exception {
+ super(transport, linkProperties, ncTemplate, mServiceContext);
// Waits for the NetworkAgent to be registered, which includes the creation of the
// NetworkMonitor.
@@ -1003,46 +1031,38 @@
}
}
+ private Set<UidRange> uidRangesForUid(int uid) {
+ final ArraySet<UidRange> ranges = new ArraySet<>();
+ ranges.add(new UidRange(uid, uid));
+ return ranges;
+ }
+
private static Looper startHandlerThreadAndReturnLooper() {
final HandlerThread handlerThread = new HandlerThread("MockVpnThread");
handlerThread.start();
return handlerThread.getLooper();
}
- private class MockVpn extends Vpn {
- // TODO : the interactions between this mock and the mock network agent are too
- // hard to get right at this moment, because it's unclear in which case which
- // target needs to get a method call or both, and in what order. It's because
- // MockNetworkAgent wants to manage its own NetworkCapabilities, but the Vpn
- // parent class of MockVpn agent wants that responsibility.
- // That being said inside the test it should be possible to make the interactions
- // harder to get wrong with precise speccing, judicious comments, helper methods
- // and a few sprinkled assertions.
-
- private boolean mConnected = false;
+ private class MockVpn extends Vpn implements TestableNetworkCallback.HasNetwork {
// Careful ! This is different from mNetworkAgent, because MockNetworkAgent does
// not inherit from NetworkAgent.
private TestNetworkAgentWrapper mMockNetworkAgent;
- private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
+ private boolean mAgentRegistered = false;
+ private int mVpnType = VpnManager.TYPE_VPN_SERVICE;
private VpnInfo mVpnInfo;
- private Network[] mUnderlyingNetworks;
public MockVpn(int userId) {
super(startHandlerThreadAndReturnLooper(), mServiceContext, mNetworkManagementService,
userId, mock(KeyStore.class));
- }
-
- public void setNetworkAgent(TestNetworkAgentWrapper agent) {
- agent.waitForIdle(TIMEOUT_MS);
- mMockNetworkAgent = agent;
- mNetworkAgent = agent.getNetworkAgent();
- mNetworkCapabilities.set(agent.getNetworkCapabilities());
+ mConfig = new VpnConfig();
}
public void setUids(Set<UidRange> uids) {
mNetworkCapabilities.setUids(uids);
- updateCapabilities(null /* defaultNetwork */);
+ if (mAgentRegistered) {
+ mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities, true);
+ }
}
public void setVpnType(int vpnType) {
@@ -1050,21 +1070,13 @@
}
@Override
+ public Network getNetwork() {
+ return (mMockNetworkAgent == null) ? null : mMockNetworkAgent.getNetwork();
+ }
+
+ @Override
public int getNetId() {
- if (mMockNetworkAgent == null) {
- return NETID_UNSET;
- }
- return mMockNetworkAgent.getNetwork().netId;
- }
-
- @Override
- public boolean appliesToUid(int uid) {
- return mConnected; // Trickery to simplify testing.
- }
-
- @Override
- protected boolean isCallerEstablishedOwnerLocked() {
- return mConnected; // Similar trickery
+ return (mMockNetworkAgent == null) ? NETID_UNSET : mMockNetworkAgent.getNetwork().netId;
}
@Override
@@ -1072,41 +1084,76 @@
return mVpnType;
}
- private void connect(boolean isAlwaysMetered) {
+ private void registerAgent(boolean isAlwaysMetered, Set<UidRange> uids, LinkProperties lp)
+ throws Exception {
+ if (mAgentRegistered) throw new IllegalStateException("already registered");
+ setUids(uids);
+ if (!isAlwaysMetered) mNetworkCapabilities.addCapability(NET_CAPABILITY_NOT_METERED);
+ mInterface = VPN_IFNAME;
+ mMockNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp,
+ mNetworkCapabilities);
+ mMockNetworkAgent.waitForIdle(TIMEOUT_MS);
+ verify(mNetworkManagementService, times(1))
+ .addVpnUidRanges(eq(mMockVpn.getNetId()), eq(uids.toArray(new UidRange[0])));
+ verify(mNetworkManagementService, never())
+ .removeVpnUidRanges(eq(mMockVpn.getNetId()), any());
+ mAgentRegistered = true;
mNetworkCapabilities.set(mMockNetworkAgent.getNetworkCapabilities());
- mConnected = true;
- mConfig = new VpnConfig();
- mConfig.isMetered = isAlwaysMetered;
+ mNetworkAgent = mMockNetworkAgent.getNetworkAgent();
}
- public void connectAsAlwaysMetered() {
- connect(true /* isAlwaysMetered */);
+ private void registerAgent(Set<UidRange> uids) throws Exception {
+ registerAgent(false /* isAlwaysMetered */, uids, new LinkProperties());
}
- public void connect() {
- connect(false /* isAlwaysMetered */);
+ private void connect(boolean validated, boolean hasInternet, boolean isStrictMode) {
+ mMockNetworkAgent.connect(validated, hasInternet, isStrictMode);
}
- @Override
- public NetworkCapabilities updateCapabilities(Network defaultNetwork) {
- if (!mConnected) return null;
- super.updateCapabilities(defaultNetwork);
- // Because super.updateCapabilities will update the capabilities of the agent but
- // not the mock agent, the mock agent needs to know about them.
- copyCapabilitiesToNetworkAgent();
- return new NetworkCapabilities(mNetworkCapabilities);
+ private void connect(boolean validated) {
+ mMockNetworkAgent.connect(validated);
}
- private void copyCapabilitiesToNetworkAgent() {
- if (null != mMockNetworkAgent) {
- mMockNetworkAgent.setNetworkCapabilities(mNetworkCapabilities,
- false /* sendToConnectivityService */);
- }
+ private TestNetworkAgentWrapper getAgent() {
+ return mMockNetworkAgent;
+ }
+
+ public void establish(LinkProperties lp, int uid, Set<UidRange> ranges, boolean validated,
+ boolean hasInternet, boolean isStrictMode) throws Exception {
+ mNetworkCapabilities.setOwnerUid(uid);
+ mNetworkCapabilities.setAdministratorUids(new int[]{uid});
+ registerAgent(false, ranges, lp);
+ connect(validated, hasInternet, isStrictMode);
+ waitForIdle();
+ }
+
+ public void establish(LinkProperties lp, int uid, Set<UidRange> ranges) throws Exception {
+ establish(lp, uid, ranges, true, true, false);
+ }
+
+ public void establishForMyUid(LinkProperties lp) throws Exception {
+ final int uid = Process.myUid();
+ establish(lp, uid, uidRangesForUid(uid), true, true, false);
+ }
+
+ public void establishForMyUid(boolean validated, boolean hasInternet, boolean isStrictMode)
+ throws Exception {
+ final int uid = Process.myUid();
+ establish(new LinkProperties(), uid, uidRangesForUid(uid), validated, hasInternet,
+ isStrictMode);
+ }
+
+ public void establishForMyUid() throws Exception {
+ establishForMyUid(new LinkProperties());
+ }
+
+ public void sendLinkProperties(LinkProperties lp) {
+ mMockNetworkAgent.sendLinkProperties(lp);
}
public void disconnect() {
- mConnected = false;
- mConfig = null;
+ if (mMockNetworkAgent != null) mMockNetworkAgent.disconnect();
+ mAgentRegistered = false;
}
@Override
@@ -1119,18 +1166,6 @@
private synchronized void setVpnInfo(VpnInfo vpnInfo) {
mVpnInfo = vpnInfo;
}
-
- @Override
- public synchronized Network[] getUnderlyingNetworks() {
- if (mUnderlyingNetworks != null) return mUnderlyingNetworks;
-
- return super.getUnderlyingNetworks();
- }
-
- /** Don't override behavior for {@link Vpn#setUnderlyingNetworks}. */
- private synchronized void overrideUnderlyingNetworks(Network[] underlyingNetworks) {
- mUnderlyingNetworks = underlyingNetworks;
- }
}
private void mockVpn(int uid) {
@@ -1193,12 +1228,14 @@
@Before
public void setUp() throws Exception {
+ mNetIdManager = new TestNetIdManager();
+
mContext = InstrumentationRegistry.getContext();
MockitoAnnotations.initMocks(this);
when(mMetricsService.defaultNetworkMetrics()).thenReturn(mDefaultNetworkMetrics);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(VPN_USER, "", 0),
}));
@@ -1246,7 +1283,7 @@
// Create local CM before sending system ready so that we can answer
// getSystemService() correctly.
mCm = new WrappedConnectivityManager(InstrumentationRegistry.getContext(), mService);
- mService.systemReady();
+ mService.systemReadyInternal();
mockVpn(Process.myUid());
mCm.bindProcessToNetwork(null);
@@ -1257,21 +1294,20 @@
}
private ConnectivityService.Dependencies makeDependencies() {
- final MockableSystemProperties systemProperties = spy(new MockableSystemProperties());
- when(systemProperties.getInt("net.tcp.default_init_rwnd", 0)).thenReturn(0);
- when(systemProperties.getBoolean("ro.radio.noril", false)).thenReturn(false);
-
+ doReturn(TEST_TCP_INIT_RWND).when(mSystemProperties)
+ .getInt("net.tcp.default_init_rwnd", 0);
+ doReturn(false).when(mSystemProperties).getBoolean("ro.radio.noril", false);
+ doNothing().when(mSystemProperties).setTcpInitRwnd(anyInt());
final ConnectivityService.Dependencies deps = mock(ConnectivityService.Dependencies.class);
doReturn(mCsHandlerThread).when(deps).makeHandlerThread();
- doReturn(new TestNetIdManager()).when(deps).makeNetIdManager();
+ doReturn(mNetIdManager).when(deps).makeNetIdManager();
doReturn(mNetworkStack).when(deps).getNetworkStack();
- doReturn(systemProperties).when(deps).getSystemProperties();
+ doReturn(mSystemProperties).when(deps).getSystemProperties();
doReturn(mock(ProxyTracker.class)).when(deps).makeProxyTracker(any(), any());
doReturn(mMetricsService).when(deps).getMetricsLogger();
doReturn(true).when(deps).queryUserAccess(anyInt(), anyInt());
doReturn(mIpConnectivityMetrics).when(deps).getIpConnectivityMetrics();
doReturn(mBatteryStatsService).when(deps).getBatteryStatsService();
- doReturn(true).when(deps).hasService(Context.ETHERNET_SERVICE);
doAnswer(inv -> {
mPolicyTracker = new WrappedMultinetworkPolicyTracker(
inv.getArgument(0), inv.getArgument(1), inv.getArgument(2));
@@ -1322,6 +1358,9 @@
mEthernetNetworkAgent.disconnect();
mEthernetNetworkAgent = null;
}
+ mMockVpn.disconnect();
+ waitForIdle();
+
FakeSettingsProvider.clearSettingsProvider();
mCsHandlerThread.quitSafely();
@@ -3205,20 +3244,12 @@
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
- final int uid = Process.myUid();
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true);
- mMockVpn.connect();
- defaultNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ mMockVpn.establishForMyUid();
+ defaultNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
assertEquals(defaultNetworkCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- vpnNetworkAgent.disconnect();
- defaultNetworkCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ mMockVpn.disconnect();
+ defaultNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
waitForIdle();
assertEquals(null, mCm.getActiveNetwork());
}
@@ -4795,13 +4826,52 @@
mCm.unregisterNetworkCallback(networkCallback);
}
+ private <T> void assertSameElementsNoDuplicates(T[] expected, T[] actual) {
+ // Easier to implement than a proper "assertSameElements" method that also correctly deals
+ // with duplicates.
+ final String msg = Arrays.toString(expected) + " != " + Arrays.toString(actual);
+ assertEquals(msg, expected.length, actual.length);
+ Set expectedSet = new ArraySet<>(Arrays.asList(expected));
+ assertEquals("expected contains duplicates", expectedSet.size(), expected.length);
+ // actual cannot have duplicates because it's the same length and has the same elements.
+ Set actualSet = new ArraySet<>(Arrays.asList(actual));
+ assertEquals(expectedSet, actualSet);
+ }
+
+ private void expectForceUpdateIfaces(Network[] networks, String defaultIface,
+ Integer vpnUid, String vpnIfname, String[] underlyingIfaces) throws Exception {
+ ArgumentCaptor<Network[]> networksCaptor = ArgumentCaptor.forClass(Network[].class);
+ ArgumentCaptor<VpnInfo[]> vpnInfosCaptor = ArgumentCaptor.forClass(VpnInfo[].class);
+
+ verify(mStatsService, atLeastOnce()).forceUpdateIfaces(networksCaptor.capture(),
+ any(NetworkState[].class), eq(defaultIface), vpnInfosCaptor.capture());
+
+ assertSameElementsNoDuplicates(networksCaptor.getValue(), networks);
+
+ VpnInfo[] infos = vpnInfosCaptor.getValue();
+ if (vpnUid != null) {
+ assertEquals("Should have exactly one VPN:", 1, infos.length);
+ VpnInfo info = infos[0];
+ assertEquals("Unexpected VPN owner:", (int) vpnUid, info.ownerUid);
+ assertEquals("Unexpected VPN interface:", vpnIfname, info.vpnIface);
+ assertSameElementsNoDuplicates(underlyingIfaces, info.underlyingIfaces);
+ } else {
+ assertEquals(0, infos.length);
+ return;
+ }
+ }
+
+ private void expectForceUpdateIfaces(Network[] networks, String defaultIface) throws Exception {
+ expectForceUpdateIfaces(networks, defaultIface, null, null, new String[0]);
+ }
+
@Test
public void testStatsIfacesChanged() throws Exception {
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
- Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
- Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
+ final Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()};
+ final Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()};
LinkProperties cellLp = new LinkProperties();
cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4812,9 +4882,7 @@
mCellNetworkAgent.connect(false);
mCellNetworkAgent.sendLinkProperties(cellLp);
waitForIdle();
- verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
+ expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
reset(mStatsService);
// Default network switch should update ifaces.
@@ -4822,32 +4890,24 @@
mWiFiNetworkAgent.sendLinkProperties(wifiLp);
waitForIdle();
assertEquals(wifiLp, mService.getActiveLinkProperties());
- verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(eq(onlyWifi), any(NetworkState[].class), eq(WIFI_IFNAME),
- eq(new VpnInfo[0]));
+ expectForceUpdateIfaces(onlyWifi, WIFI_IFNAME);
reset(mStatsService);
// Disconnect should update ifaces.
mWiFiNetworkAgent.disconnect();
waitForIdle();
- verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class),
- eq(MOBILE_IFNAME), eq(new VpnInfo[0]));
+ expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
reset(mStatsService);
// Metered change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
+ expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
reset(mStatsService);
mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED);
waitForIdle();
- verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
+ expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
reset(mStatsService);
// Captive portal change shouldn't update ifaces
@@ -4861,9 +4921,130 @@
// Roaming change should update ifaces
mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING);
waitForIdle();
- verify(mStatsService, atLeastOnce())
- .forceUpdateIfaces(eq(onlyCell), any(NetworkState[].class), eq(MOBILE_IFNAME),
- eq(new VpnInfo[0]));
+ expectForceUpdateIfaces(onlyCell, MOBILE_IFNAME);
+ reset(mStatsService);
+
+ // Test VPNs.
+ final LinkProperties lp = new LinkProperties();
+ lp.setInterfaceName(VPN_IFNAME);
+
+ mMockVpn.establishForMyUid(lp);
+
+ final Network[] cellAndVpn = new Network[] {
+ mCellNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
+
+ // A VPN with default (null) underlying networks sets the underlying network's interfaces...
+ expectForceUpdateIfaces(cellAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{MOBILE_IFNAME});
+
+ // ...and updates them as the default network switches.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+ mWiFiNetworkAgent.sendLinkProperties(wifiLp);
+ final Network[] onlyNull = new Network[]{null};
+ final Network[] wifiAndVpn = new Network[] {
+ mWiFiNetworkAgent.getNetwork(), mMockVpn.getNetwork()};
+ final Network[] cellAndWifi = new Network[] {
+ mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork()};
+ final Network[] cellNullAndWifi = new Network[] {
+ mCellNetworkAgent.getNetwork(), null, mWiFiNetworkAgent.getNetwork()};
+
+ waitForIdle();
+ assertEquals(wifiLp, mService.getActiveLinkProperties());
+ expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{WIFI_IFNAME});
+ reset(mStatsService);
+
+ // A VPN that sets its underlying networks passes the underlying interfaces, and influences
+ // the default interface sent to NetworkStatsService by virtue of applying to the system
+ // server UID (or, in this test, to the test's UID). This is the reason for sending
+ // MOBILE_IFNAME even though the default network is wifi.
+ // TODO: fix this to pass in the actual default network interface. Whether or not the VPN
+ // applies to the system server UID should not have any bearing on network stats.
+ mService.setUnderlyingNetworksForVpn(onlyCell);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{MOBILE_IFNAME});
+ reset(mStatsService);
+
+ mService.setUnderlyingNetworksForVpn(cellAndWifi);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+ reset(mStatsService);
+
+ // Null underlying networks are ignored.
+ mService.setUnderlyingNetworksForVpn(cellNullAndWifi);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+ reset(mStatsService);
+
+ // If an underlying network disconnects, that interface should no longer be underlying.
+ // This doesn't actually work because disconnectAndDestroyNetwork only notifies
+ // NetworkStatsService before the underlying network is actually removed. So the underlying
+ // network will only be removed if notifyIfacesChangedForNetworkStats is called again. This
+ // could result in incorrect data usage measurements if the interface used by the
+ // disconnected network is reused by a system component that does not register an agent for
+ // it (e.g., tethering).
+ mCellNetworkAgent.disconnect();
+ waitForIdle();
+ assertNull(mService.getLinkProperties(mCellNetworkAgent.getNetwork()));
+ expectForceUpdateIfaces(wifiAndVpn, MOBILE_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{MOBILE_IFNAME, WIFI_IFNAME});
+
+ // Confirm that we never tell NetworkStatsService that cell is no longer the underlying
+ // network for the VPN...
+ verify(mStatsService, never()).forceUpdateIfaces(any(Network[].class),
+ any(NetworkState[].class), any() /* anyString() doesn't match null */,
+ argThat(infos -> infos[0].underlyingIfaces.length == 1
+ && WIFI_IFNAME.equals(infos[0].underlyingIfaces[0])));
+ verifyNoMoreInteractions(mStatsService);
+ reset(mStatsService);
+
+ // ... but if something else happens that causes notifyIfacesChangedForNetworkStats to be
+ // called again, it does. For example, connect Ethernet, but with a low score, such that it
+ // does not become the default network.
+ mEthernetNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_ETHERNET);
+ mEthernetNetworkAgent.adjustScore(-40);
+ mEthernetNetworkAgent.connect(false);
+ waitForIdle();
+ verify(mStatsService).forceUpdateIfaces(any(Network[].class),
+ any(NetworkState[].class), any() /* anyString() doesn't match null */,
+ argThat(vpnInfos -> vpnInfos[0].underlyingIfaces.length == 1
+ && WIFI_IFNAME.equals(vpnInfos[0].underlyingIfaces[0])));
+ mEthernetNetworkAgent.disconnect();
+ waitForIdle();
+ reset(mStatsService);
+
+ // When a VPN declares no underlying networks (i.e., no connectivity), getAllVpnInfo
+ // does not return the VPN, so CS does not pass it to NetworkStatsService. This causes
+ // NetworkStatsFactory#adjustForTunAnd464Xlat not to attempt any VPN data migration, which
+ // is probably a performance improvement (though it's very unlikely that a VPN would declare
+ // no underlying networks).
+ // Also, for the same reason as above, the active interface passed in is null.
+ mService.setUnderlyingNetworksForVpn(new Network[0]);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, null);
+ reset(mStatsService);
+
+ // Specifying only a null underlying network is the same as no networks.
+ mService.setUnderlyingNetworksForVpn(onlyNull);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, null);
+ reset(mStatsService);
+
+ // Specifying networks that are all disconnected is the same as specifying no networks.
+ mService.setUnderlyingNetworksForVpn(onlyCell);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, null);
+ reset(mStatsService);
+
+ // Passing in null again means follow the default network again.
+ mService.setUnderlyingNetworksForVpn(null);
+ waitForIdle();
+ expectForceUpdateIfaces(wifiAndVpn, WIFI_IFNAME, Process.myUid(), VPN_IFNAME,
+ new String[]{WIFI_IFNAME});
reset(mStatsService);
}
@@ -4987,22 +5168,22 @@
// simulate that situation and check if ConnectivityService could filter that case.
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notifyAsUser(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
+ verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).notify(anyString(),
+ eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
// If private DNS resolution successful, the PRIVATE_DNS_BROKEN notification shouldn't be
// shown.
mWiFiNetworkAgent.setNetworkValid(true /* isStrictMode */);
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancelAsUser(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), eq(UserHandle.ALL));
+ verify(mNotificationManager, timeout(TIMEOUT_MS).times(1)).cancel(anyString(),
+ eq(NotificationType.PRIVATE_DNS_BROKEN.eventId));
// If private DNS resolution failed again, the PRIVATE_DNS_BROKEN notification should be
// shown again.
mWiFiNetworkAgent.setNetworkInvalid(true /* isStrictMode */);
mWiFiNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
waitForIdle();
- verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notifyAsUser(anyString(),
- eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any(), eq(UserHandle.ALL));
+ verify(mNotificationManager, timeout(TIMEOUT_MS).times(2)).notify(anyString(),
+ eq(NotificationType.PRIVATE_DNS_BROKEN.eventId), any());
}
@Test
@@ -5219,6 +5400,158 @@
}
@Test
+ public void testApplyUnderlyingCapabilities() throws Exception {
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mCellNetworkAgent.connect(false /* validated */);
+ mWiFiNetworkAgent.connect(false /* validated */);
+
+ final NetworkCapabilities cellNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .setLinkDownstreamBandwidthKbps(10);
+ final NetworkCapabilities wifiNc = new NetworkCapabilities()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_METERED)
+ .addCapability(NET_CAPABILITY_NOT_ROAMING)
+ .addCapability(NET_CAPABILITY_NOT_CONGESTED)
+ .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
+ .setLinkUpstreamBandwidthKbps(20);
+ mCellNetworkAgent.setNetworkCapabilities(cellNc, true /* sendToConnectivityService */);
+ mWiFiNetworkAgent.setNetworkCapabilities(wifiNc, true /* sendToConnectivityService */);
+ waitForIdle();
+
+ final Network mobile = mCellNetworkAgent.getNetwork();
+ final Network wifi = mWiFiNetworkAgent.getNetwork();
+
+ final NetworkCapabilities initialCaps = new NetworkCapabilities();
+ initialCaps.addCapability(NET_CAPABILITY_INTERNET);
+ initialCaps.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withNoUnderlying = new NetworkCapabilities();
+ withNoUnderlying.addCapability(NET_CAPABILITY_INTERNET);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_CONGESTED);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_ROAMING);
+ withNoUnderlying.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withNoUnderlying.addTransportType(TRANSPORT_VPN);
+ withNoUnderlying.removeCapability(NET_CAPABILITY_NOT_VPN);
+
+ final NetworkCapabilities withMobileUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
+ withMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+
+ final NetworkCapabilities withWifiUnderlying = new NetworkCapabilities(withNoUnderlying);
+ withWifiUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ final NetworkCapabilities withWifiAndMobileUnderlying =
+ new NetworkCapabilities(withNoUnderlying);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_CELLULAR);
+ withWifiAndMobileUnderlying.addTransportType(TRANSPORT_WIFI);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ withWifiAndMobileUnderlying.removeCapability(NET_CAPABILITY_NOT_ROAMING);
+ withWifiAndMobileUnderlying.setLinkDownstreamBandwidthKbps(10);
+ withWifiAndMobileUnderlying.setLinkUpstreamBandwidthKbps(20);
+
+ NetworkCapabilities caps = new NetworkCapabilities(initialCaps);
+ final boolean notDeclaredMetered = false;
+ mService.applyUnderlyingCapabilities(new Network[]{}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null}, caps, notDeclaredMetered);
+ assertEquals(withNoUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile}, caps, notDeclaredMetered);
+ assertEquals(withMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ final boolean isDeclaredMetered = true;
+ withWifiUnderlying.removeCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{mobile, wifi}, caps, isDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ withWifiUnderlying.addCapability(NET_CAPABILITY_NOT_METERED);
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ caps = new NetworkCapabilities(initialCaps);
+ mService.applyUnderlyingCapabilities(new Network[]{null, mobile, null, wifi},
+ caps, notDeclaredMetered);
+ assertEquals(withWifiAndMobileUnderlying, caps);
+
+ mService.applyUnderlyingCapabilities(null, caps, notDeclaredMetered);
+ assertEquals(withWifiUnderlying, caps);
+ }
+
+ @Test
+ public void testVpnConnectDisconnectUnderlyingNetwork() throws Exception {
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN).build();
+
+ mCm.registerNetworkCallback(request, callback);
+
+ // Bring up a VPN that specifies an underlying network that does not exist yet.
+ // Note: it's sort of meaningless for a VPN app to declare a network that doesn't exist yet,
+ // (and doing so is difficult without using reflection) but it's good to test that the code
+ // behaves approximately correctly.
+ mMockVpn.establishForMyUid(false, true, false);
+ final Network wifiNetwork = new Network(mNetIdManager.peekNextNetId());
+ mService.setUnderlyingNetworksForVpn(new Network[]{wifiNetwork});
+ callback.expectAvailableCallbacksUnvalidated(mMockVpn);
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasTransport(TRANSPORT_VPN));
+ assertFalse(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasTransport(TRANSPORT_WIFI));
+
+ // Make that underlying network connect, and expect to see its capabilities immediately
+ // reflected in the VPN's capabilities.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ assertEquals(wifiNetwork, mWiFiNetworkAgent.getNetwork());
+ mWiFiNetworkAgent.connect(false);
+ // TODO: the callback for the VPN happens before any callbacks are called for the wifi
+ // network that has just connected. There appear to be two issues here:
+ // 1. The VPN code will accept an underlying network as soon as getNetworkCapabilities() for
+ // it returns non-null (which happens very early, during handleRegisterNetworkAgent).
+ // This is not correct because that that point the network is not connected and cannot
+ // pass any traffic.
+ // 2. When a network connects, updateNetworkInfo propagates underlying network capabilities
+ // before rematching networks.
+ // Given that this scenario can't really happen, this is probably fine for now.
+ callback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasTransport(TRANSPORT_VPN));
+ assertTrue(mCm.getNetworkCapabilities(mMockVpn.getNetwork())
+ .hasTransport(TRANSPORT_WIFI));
+
+ // Disconnect the network, and expect to see the VPN capabilities change accordingly.
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (nc) ->
+ nc.getTransportTypes().length == 1 && nc.hasTransport(TRANSPORT_VPN));
+
+ mMockVpn.disconnect();
+ mCm.unregisterNetworkCallback(callback);
+ }
+
+ @Test
public void testVpnNetworkActive() throws Exception {
final int uid = Process.myUid();
@@ -5252,42 +5585,32 @@
vpnNetworkCallback.assertNoCallback();
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
+ final Set<UidRange> ranges = uidRangesForUid(uid);
+ mMockVpn.registerAgent(ranges);
+ mService.setUnderlyingNetworksForVpn(new Network[0]);
+
// VPN networks do not satisfy the default request and are automatically validated
// by NetworkMonitor
assertFalse(NetworkMonitorUtils.isValidationRequired(
- vpnNetworkAgent.getNetworkCapabilities()));
- vpnNetworkAgent.setNetworkValid(false /* isStrictMode */);
+ mMockVpn.getAgent().getNetworkCapabilities()));
+ mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
- vpnNetworkAgent.connect(false);
- mMockVpn.connect();
- mMockVpn.setUnderlyingNetworks(new Network[0]);
+ mMockVpn.connect(false);
- genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ genericNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
- defaultCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
- assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
-
- genericNetworkCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
- genericNotVpnNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent, nc -> null == nc.getUids());
- defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
+ vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
ranges.clear();
- vpnNetworkAgent.setUids(ranges);
+ mMockVpn.setUids(ranges);
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
// 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
@@ -5295,19 +5618,18 @@
// 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(CallbackEntry.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
ranges.add(new UidRange(uid, uid));
mMockVpn.setUids(ranges);
- vpnNetworkAgent.setUids(ranges);
- genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent);
+ vpnNetworkCallback.expectAvailableCallbacksValidated(mMockVpn);
// 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(CallbackEntry.NETWORK_CAPS_UPDATED, vpnNetworkAgent);
+ defaultCallback.expectCallback(CallbackEntry.NETWORK_CAPS_UPDATED, mMockVpn);
mWiFiNetworkAgent.disconnect();
@@ -5317,13 +5639,13 @@
vpnNetworkCallback.assertNoCallback();
defaultCallback.assertNoCallback();
- vpnNetworkAgent.disconnect();
+ mMockVpn.disconnect();
- genericNetworkCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ genericNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
genericNotVpnNetworkCallback.assertNoCallback();
wifiNetworkCallback.assertNoCallback();
- vpnNetworkCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
- defaultCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
+ defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
assertEquals(null, mCm.getActiveNetwork());
mCm.unregisterNetworkCallback(genericNetworkCallback);
@@ -5345,20 +5667,13 @@
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
false /* isStrictMode */);
- mMockVpn.connect();
defaultCallback.assertNoCallback();
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- vpnNetworkAgent.disconnect();
+ mMockVpn.disconnect();
defaultCallback.assertNoCallback();
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5377,21 +5692,14 @@
defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */,
+ mMockVpn.establishForMyUid(true /* validated */, true /* hasInternet */,
false /* isStrictMode */);
- mMockVpn.connect();
- defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
+ defaultCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork());
- vpnNetworkAgent.disconnect();
- defaultCallback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ mMockVpn.disconnect();
+ defaultCallback.expectCallback(CallbackEntry.LOST, mMockVpn);
defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent);
mCm.unregisterNetworkCallback(defaultCallback);
@@ -5409,44 +5717,36 @@
callback.assertNoCallback();
// Bring up a VPN that has the INTERNET capability, initially unvalidated.
- final int uid = Process.myUid();
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */,
+ mMockVpn.establishForMyUid(false /* validated */, true /* hasInternet */,
false /* isStrictMode */);
- mMockVpn.connect();
// Even though the VPN is unvalidated, it becomes the default network for our app.
- callback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent);
+ callback.expectAvailableCallbacksUnvalidated(mMockVpn);
callback.assertNoCallback();
- assertTrue(vpnNetworkAgent.getScore() > mEthernetNetworkAgent.getScore());
- assertEquals(ConnectivityConstants.VPN_DEFAULT_SCORE, vpnNetworkAgent.getScore());
- assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertTrue(mMockVpn.getAgent().getScore() > mEthernetNetworkAgent.getScore());
+ assertEquals(ConnectivityConstants.VPN_DEFAULT_SCORE, mMockVpn.getAgent().getScore());
+ assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
- NetworkCapabilities nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+ NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertFalse(nc.hasCapability(NET_CAPABILITY_VALIDATED));
assertTrue(nc.hasCapability(NET_CAPABILITY_INTERNET));
assertFalse(NetworkMonitorUtils.isValidationRequired(
- vpnNetworkAgent.getNetworkCapabilities()));
+ mMockVpn.getAgent().getNetworkCapabilities()));
assertTrue(NetworkMonitorUtils.isPrivateDnsValidationRequired(
- vpnNetworkAgent.getNetworkCapabilities()));
+ mMockVpn.getAgent().getNetworkCapabilities()));
// Pretend that the VPN network validates.
- vpnNetworkAgent.setNetworkValid(false /* isStrictMode */);
- vpnNetworkAgent.mNetworkMonitor.forceReevaluation(Process.myUid());
+ mMockVpn.getAgent().setNetworkValid(false /* isStrictMode */);
+ mMockVpn.getAgent().mNetworkMonitor.forceReevaluation(Process.myUid());
// Expect to see the validated capability, but no other changes, because the VPN is already
// the default network for the app.
- callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, vpnNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mMockVpn);
callback.assertNoCallback();
- vpnNetworkAgent.disconnect();
- callback.expectCallback(CallbackEntry.LOST, vpnNetworkAgent);
+ mMockVpn.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mMockVpn);
callback.expectAvailableCallbacksValidated(mEthernetNetworkAgent);
}
@@ -5468,21 +5768,15 @@
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
mCellNetworkAgent.connect(true);
- final TestNetworkAgentWrapper vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.connect();
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
false /* isStrictMode */);
- vpnNetworkCallback.expectAvailableCallbacks(vpnNetworkAgent.getNetwork(),
+ vpnNetworkCallback.expectAvailableCallbacks(mMockVpn.getNetwork(),
false /* suspended */, false /* validated */, false /* blocked */, TIMEOUT_MS);
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent.getNetwork(), TIMEOUT_MS,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn.getNetwork(), TIMEOUT_MS,
nc -> nc.hasCapability(NET_CAPABILITY_VALIDATED));
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertTrue(nc.hasTransport(TRANSPORT_VPN));
assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(nc.hasTransport(TRANSPORT_WIFI));
@@ -5504,18 +5798,11 @@
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
vpnNetworkCallback.assertNoCallback();
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.connect();
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
false /* isStrictMode */);
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
- nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+ vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertTrue(nc.hasTransport(TRANSPORT_VPN));
assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(nc.hasTransport(TRANSPORT_WIFI));
@@ -5532,7 +5819,7 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5546,7 +5833,7 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5556,7 +5843,7 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5564,27 +5851,27 @@
// Remove NOT_SUSPENDED from the only network and observe VPN is now suspended.
mCellNetworkAgent.removeCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& !caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mMockVpn);
// Add NOT_SUSPENDED again and observe VPN is no longer suspended.
mCellNetworkAgent.addCapability(NET_CAPABILITY_NOT_SUSPENDED);
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
&& caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
- vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, vpnNetworkAgent);
+ vpnNetworkCallback.expectCallback(CallbackEntry.RESUMED, mMockVpn);
// Use Wifi but not cell. Note the VPN is now unmetered and not suspended.
mService.setUnderlyingNetworksForVpn(
new Network[] { mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5594,7 +5881,7 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5607,7 +5894,7 @@
// Stop using WiFi. The VPN is suspended again.
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5621,7 +5908,7 @@
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork(), mWiFiNetworkAgent.getNetwork() });
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED)
@@ -5632,14 +5919,14 @@
// Disconnect cell. Receive update without even removing the dead network from the
// underlying networks – it's dead anyway. Not metered any more.
mCellNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& caps.hasCapability(NET_CAPABILITY_NOT_METERED));
// Disconnect wifi too. No underlying networks means this is now metered.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
@@ -5660,18 +5947,11 @@
mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback);
vpnNetworkCallback.assertNoCallback();
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.connect();
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */,
+ mMockVpn.establishForMyUid(true /* validated */, false /* hasInternet */,
false /* isStrictMode */);
- vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent);
- nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork());
+ vpnNetworkCallback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
assertTrue(nc.hasTransport(TRANSPORT_VPN));
assertFalse(nc.hasTransport(TRANSPORT_CELLULAR));
assertFalse(nc.hasTransport(TRANSPORT_WIFI));
@@ -5683,7 +5963,7 @@
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
@@ -5693,7 +5973,7 @@
mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mWiFiNetworkAgent.connect(true);
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI)
&& caps.hasCapability(NET_CAPABILITY_NOT_METERED));
@@ -5705,7 +5985,7 @@
// Disconnect wifi too. Now we have no default network.
mWiFiNetworkAgent.disconnect();
- vpnNetworkCallback.expectCapabilitiesThat(vpnNetworkAgent,
+ vpnNetworkCallback.expectCapabilitiesThat(mMockVpn,
(caps) -> caps.hasTransport(TRANSPORT_VPN)
&& !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI)
&& !caps.hasCapability(NET_CAPABILITY_NOT_METERED));
@@ -5714,6 +5994,86 @@
}
@Test
+ public void testVpnRestrictedUsers() throws Exception {
+ // NETWORK_SETTINGS is necessary to see the UID ranges in NetworkCapabilities.
+ mServiceContext.setPermission(Manifest.permission.NETWORK_SETTINGS,
+ PERMISSION_GRANTED);
+
+ final NetworkRequest request = new NetworkRequest.Builder()
+ .removeCapability(NET_CAPABILITY_NOT_VPN)
+ .build();
+ final TestNetworkCallback callback = new TestNetworkCallback();
+ mCm.registerNetworkCallback(request, callback);
+
+ // Bring up a VPN
+ mMockVpn.establishForMyUid();
+ callback.expectAvailableThenValidatedCallbacks(mMockVpn);
+ callback.assertNoCallback();
+
+ final int uid = Process.myUid();
+ NetworkCapabilities nc = mCm.getNetworkCapabilities(mMockVpn.getNetwork());
+ assertNotNull("nc=" + nc, nc.getUids());
+ assertEquals(nc.getUids(), uidRangesForUid(uid));
+
+ // Set an underlying network and expect to see the VPN transports change.
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_WIFI));
+ callback.expectCapabilitiesThat(mWiFiNetworkAgent, (caps)
+ -> caps.hasCapability(NET_CAPABILITY_VALIDATED));
+
+ // Create a fake restricted profile whose parent is our user ID.
+ final int userId = UserHandle.getUserId(uid);
+ final int restrictedUserId = userId + 1;
+ final UserInfo info = new UserInfo(restrictedUserId, "user", UserInfo.FLAG_RESTRICTED);
+ info.restrictedProfileParentId = userId;
+ assertTrue(info.isRestricted());
+ when(mUserManager.getUserInfo(restrictedUserId)).thenReturn(info);
+ final Intent addedIntent = new Intent(ACTION_USER_ADDED);
+ addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+
+ // Send a USER_ADDED broadcast for it.
+ // The BroadcastReceiver for this broadcast checks that is being run on the handler thread.
+ final Handler handler = new Handler(mCsHandlerThread.getLooper());
+ handler.post(() -> mServiceContext.sendBroadcast(addedIntent));
+
+ // Expect that the VPN UID ranges contain both |uid| and the UID range for the newly-added
+ // restricted user.
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 2
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && caps.hasTransport(TRANSPORT_WIFI));
+
+ // Change the VPN's capabilities somehow (specifically, disconnect wifi).
+ mWiFiNetworkAgent.disconnect();
+ callback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 2
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.getUids().contains(UidRange.createForUser(restrictedUserId))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_WIFI));
+
+ // Send a USER_REMOVED broadcast and expect to lose the UID range for the restricted user.
+ final Intent removedIntent = new Intent(ACTION_USER_REMOVED);
+ removedIntent.putExtra(Intent.EXTRA_USER_HANDLE, restrictedUserId);
+ handler.post(() -> mServiceContext.sendBroadcast(removedIntent));
+
+ // Expect that the VPN gains the UID range for the restricted user, and that the capability
+ // change made just before that (i.e., loss of TRANSPORT_WIFI) is preserved.
+ callback.expectCapabilitiesThat(mMockVpn, (caps)
+ -> caps.getUids().size() == 1
+ && caps.getUids().contains(new UidRange(uid, uid))
+ && caps.hasTransport(TRANSPORT_VPN)
+ && !caps.hasTransport(TRANSPORT_WIFI));
+ }
+
+ @Test
public void testIsActiveNetworkMeteredOverWifi() throws Exception {
// Returns true by default when no network is available.
assertTrue(mCm.isActiveNetworkMetered());
@@ -5748,18 +6108,10 @@
assertTrue(mCm.isActiveNetworkMetered());
// Connect VPN network. By default it is using current default network (Cell).
- TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- final int uid = Process.myUid();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true);
- mMockVpn.connect();
- waitForIdle();
+ mMockVpn.establishForMyUid();
+
// Ensure VPN is now the active network.
- assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
// Expect VPN to be metered.
assertTrue(mCm.isActiveNetworkMetered());
@@ -5770,7 +6122,7 @@
mWiFiNetworkAgent.connect(true);
waitForIdle();
// VPN should still be the active network.
- assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
// Expect VPN to be unmetered as it should now be using WiFi (new default).
assertFalse(mCm.isActiveNetworkMetered());
@@ -5788,7 +6140,6 @@
// VPN without any underlying networks is treated as metered.
assertTrue(mCm.isActiveNetworkMetered());
- vpnNetworkAgent.disconnect();
mMockVpn.disconnect();
}
@@ -5809,18 +6160,10 @@
assertFalse(mCm.isActiveNetworkMetered());
// Connect VPN network.
- TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- final int uid = Process.myUid();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true);
- mMockVpn.connect();
- waitForIdle();
+ mMockVpn.establishForMyUid();
+
// Ensure VPN is now the active network.
- assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
// VPN is using Cell
mService.setUnderlyingNetworksForVpn(
new Network[] { mCellNetworkAgent.getNetwork() });
@@ -5860,7 +6203,6 @@
// VPN without underlying networks is treated as metered.
assertTrue(mCm.isActiveNetworkMetered());
- vpnNetworkAgent.disconnect();
mMockVpn.disconnect();
}
@@ -5875,17 +6217,11 @@
assertFalse(mCm.isActiveNetworkMetered());
// Connect VPN network.
- TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- final int uid = Process.myUid();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.setUids(ranges);
- vpnNetworkAgent.connect(true);
- mMockVpn.connectAsAlwaysMetered();
+ mMockVpn.registerAgent(true /* isAlwaysMetered */, uidRangesForUid(Process.myUid()),
+ new LinkProperties());
+ mMockVpn.connect(true);
waitForIdle();
- assertEquals(vpnNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+ assertEquals(mMockVpn.getNetwork(), mCm.getActiveNetwork());
// VPN is tracking current platform default (WiFi).
mService.setUnderlyingNetworksForVpn(null);
@@ -5909,7 +6245,7 @@
assertTrue(mCm.isActiveNetworkMetered());
- vpnNetworkAgent.disconnect();
+ mMockVpn.disconnect();
}
@Test
@@ -6018,23 +6354,23 @@
mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
- verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mNetworkManagementService);
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
- verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
- reset(mNetworkManagementService);
+ verify(mMockNetd).networkSetDefault(eq(mWiFiNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
- verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
- reset(mNetworkManagementService);
+ verify(mMockNetd).networkSetDefault(eq(mCellNetworkAgent.getNetwork().netId));
+ reset(mMockNetd);
mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
- verify(mNetworkManagementService).clearDefaultNetId();
+ verify(mMockNetd).networkClearDefault();
mCm.unregisterNetworkCallback(trustedCallback);
}
@@ -6071,12 +6407,13 @@
}
/**
- * Make simulated InterfaceConfig for Nat464Xlat to query clat lower layer info.
+ * Make simulated InterfaceConfigParcel for Nat464Xlat to query clat lower layer info.
*/
- private InterfaceConfiguration getClatInterfaceConfig(LinkAddress la) {
- InterfaceConfiguration cfg = new InterfaceConfiguration();
- cfg.setHardwareAddress("11:22:33:44:55:66");
- cfg.setLinkAddress(la);
+ private InterfaceConfigurationParcel getClatInterfaceConfigParcel(LinkAddress la) {
+ final InterfaceConfigurationParcel cfg = new InterfaceConfigurationParcel();
+ cfg.hwAddr = "11:22:33:44:55:66";
+ cfg.ipv4Addr = la.getAddress().getHostAddress();
+ cfg.prefixLength = la.getPrefixLength();
return cfg;
}
@@ -6138,6 +6475,7 @@
verify(mMockNetd, times(1)).networkCreatePhysical(eq(cellNetId), anyInt());
assertRoutesAdded(cellNetId, ipv6Subnet, defaultRoute);
verify(mMockDnsResolver, times(1)).createNetworkCache(eq(cellNetId));
+ verify(mMockNetd, times(1)).networkAddInterface(cellNetId, MOBILE_IFNAME);
verify(mBatteryStatsService).noteNetworkInterfaceType(cellLp.getInterfaceName(),
TYPE_MOBILE);
@@ -6146,7 +6484,7 @@
// Switching default network updates TCP buffer sizes.
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
-
+ verify(mSystemProperties, times(1)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Add an IPv4 address. Expect prefix discovery to be stopped. Netd doesn't tell us that
// the NAT64 prefix was removed because one was never discovered.
cellLp.addLinkAddress(myIpv4);
@@ -6166,8 +6504,8 @@
reset(mNetworkManagementService);
reset(mMockNetd);
reset(mMockDnsResolver);
- when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfig(myIpv4));
+ when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfigParcel(myIpv4));
// Remove IPv4 address. Expect prefix discovery to be started again.
cellLp.removeLinkAddress(myIpv4);
@@ -6194,7 +6532,7 @@
.getStackedLinks();
assertEquals(makeClatLinkProperties(myIpv4), stackedLps.get(0));
assertRoutesAdded(cellNetId, stackedDefault);
-
+ verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
// Change trivial linkproperties and see if stacked link is preserved.
cellLp.addDnsServer(InetAddress.getByName("8.8.8.8"));
mCellNetworkAgent.sendLinkProperties(cellLp);
@@ -6216,7 +6554,8 @@
TYPE_MOBILE);
}
reset(mMockNetd);
-
+ when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfigParcel(myIpv4));
// Change the NAT64 prefix without first removing it.
// Expect clatd to be stopped and started with the new prefix.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
@@ -6225,6 +6564,7 @@
(lp) -> lp.getStackedLinks().size() == 0);
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
assertRoutesRemoved(cellNetId, stackedDefault);
+ verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
verify(mMockNetd, times(1)).clatdStart(MOBILE_IFNAME, kOtherNat64Prefix.toString());
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
@@ -6233,6 +6573,7 @@
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
(lp) -> lp.getStackedLinks().size() == 1);
assertRoutesAdded(cellNetId, stackedDefault);
+ verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
reset(mMockNetd);
// Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
@@ -6257,14 +6598,14 @@
// The interface removed callback happens but has no effect after stop is called.
clat.interfaceRemoved(CLAT_PREFIX + MOBILE_IFNAME);
networkCallback.assertNoCallback();
-
+ verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
verifyNoMoreInteractions(mMockNetd);
verifyNoMoreInteractions(mMockDnsResolver);
reset(mNetworkManagementService);
reset(mMockNetd);
reset(mMockDnsResolver);
- when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
- .thenReturn(getClatInterfaceConfig(myIpv4));
+ when(mMockNetd.interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME))
+ .thenReturn(getClatInterfaceConfigParcel(myIpv4));
// Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -6290,6 +6631,7 @@
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
(lp) -> lp.getStackedLinks().size() == 1 && lp.getNat64Prefix() != null);
assertRoutesAdded(cellNetId, stackedDefault);
+ verify(mMockNetd, times(1)).networkAddInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
// NAT64 prefix is removed. Expect that clat is stopped.
mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -6302,8 +6644,9 @@
verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
networkCallback.expectLinkPropertiesThat(mCellNetworkAgent,
(lp) -> lp.getStackedLinks().size() == 0);
+ verify(mMockNetd, times(1)).networkRemoveInterface(cellNetId, CLAT_PREFIX + MOBILE_IFNAME);
+ verify(mMockNetd, times(1)).interfaceGetCfg(CLAT_PREFIX + MOBILE_IFNAME);
verifyNoMoreInteractions(mMockNetd);
-
// Clean up.
mCellNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -6583,14 +6926,14 @@
mCellNetworkAgent.connect(false);
networkCallback.expectAvailableCallbacksUnvalidated(mCellNetworkAgent);
verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
-
+ verify(mSystemProperties, times(1)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Change link Properties should have updated tcp buffer size.
LinkProperties lp = new LinkProperties();
lp.setTcpBufferSizes(testTcpBufferSizes);
mCellNetworkAgent.sendLinkProperties(lp);
networkCallback.expectCallback(CallbackEntry.LINK_PROPERTIES_CHANGED, mCellNetworkAgent);
verifyTcpBufferSizeChange(testTcpBufferSizes);
-
+ verify(mSystemProperties, times(2)).setTcpInitRwnd(eq(TEST_TCP_INIT_RWND));
// Clean up.
mCellNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
@@ -6634,34 +6977,21 @@
waitForIdle();
assertNull(mService.getProxyForNetwork(null));
- // Set up a VPN network with a proxy
- final int uid = Process.myUid();
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN);
- final ArraySet<UidRange> ranges = new ArraySet<>();
- ranges.add(new UidRange(uid, uid));
- mMockVpn.setUids(ranges);
+ // Connect a VPN network with a proxy.
LinkProperties testLinkProperties = new LinkProperties();
testLinkProperties.setHttpProxy(testProxyInfo);
- vpnNetworkAgent.sendLinkProperties(testLinkProperties);
- waitForIdle();
-
- // Connect to VPN with proxy
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- vpnNetworkAgent.connect(true);
- mMockVpn.connect();
- waitForIdle();
+ mMockVpn.establishForMyUid(testLinkProperties);
// Test that the VPN network returns a proxy, and the WiFi does not.
- assertEquals(testProxyInfo, mService.getProxyForNetwork(vpnNetworkAgent.getNetwork()));
+ assertEquals(testProxyInfo, mService.getProxyForNetwork(mMockVpn.getNetwork()));
assertEquals(testProxyInfo, mService.getProxyForNetwork(null));
assertNull(mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
// Test that the VPN network returns no proxy when it is set to null.
testLinkProperties.setHttpProxy(null);
- vpnNetworkAgent.sendLinkProperties(testLinkProperties);
+ mMockVpn.sendLinkProperties(testLinkProperties);
waitForIdle();
- assertNull(mService.getProxyForNetwork(vpnNetworkAgent.getNetwork()));
+ assertNull(mService.getProxyForNetwork(mMockVpn.getNetwork()));
assertNull(mService.getProxyForNetwork(null));
// Set WiFi proxy and check that the vpn proxy is still null.
@@ -6672,7 +7002,7 @@
// Disconnect from VPN and check that the active network, which is now the WiFi, has the
// correct proxy setting.
- vpnNetworkAgent.disconnect();
+ mMockVpn.disconnect();
waitForIdle();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertEquals(testProxyInfo, mService.getProxyForNetwork(mWiFiNetworkAgent.getNetwork()));
@@ -6687,17 +7017,17 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+ mMockVpn.establish(lp, VPN_UID, vpnRange);
- // Connected VPN should have interface rules set up. There are two expected invocations,
- // one during VPN uid update, one during VPN LinkProperties update
+ // A connected VPN should have interface rules set up. There are two expected invocations,
+ // one during the VPN initial connection, one during the VPN LinkProperties update.
ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
verify(mMockNetd, times(2)).firewallAddUidInterfaceRules(eq("tun0"), uidCaptor.capture());
assertContainsExactly(uidCaptor.getAllValues().get(0), APP1_UID, APP2_UID);
assertContainsExactly(uidCaptor.getAllValues().get(1), APP1_UID, APP2_UID);
assertTrue(mService.mPermissionMonitor.getVpnUidRanges("tun0").equals(vpnRange));
- vpnNetworkAgent.disconnect();
+ mMockVpn.disconnect();
waitForIdle();
// Disconnected VPN should have interface rules removed
@@ -6714,8 +7044,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
- lp, Process.SYSTEM_UID, vpnRange);
+ mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
// Legacy VPN should not have interface rules set up
verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
@@ -6730,8 +7059,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), RTN_UNREACHABLE));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(
- lp, Process.SYSTEM_UID, vpnRange);
+ mMockVpn.establish(lp, Process.SYSTEM_UID, vpnRange);
// IPv6 unreachable route should not be misinterpreted as a default route
verify(mMockNetd, never()).firewallAddUidInterfaceRules(any(), any());
@@ -6745,7 +7073,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID, vpnRange);
+ mMockVpn.establish(lp, VPN_UID, vpnRange);
// Connected VPN should have interface rules set up. There are two expected invocations,
// one during VPN uid update, one during VPN LinkProperties update
@@ -6757,7 +7085,7 @@
reset(mMockNetd);
InOrder inOrder = inOrder(mMockNetd);
lp.setInterfaceName("tun1");
- vpnNetworkAgent.sendLinkProperties(lp);
+ mMockVpn.sendLinkProperties(lp);
waitForIdle();
// VPN handover (switch to a new interface) should result in rules being updated (old rules
// removed first, then new rules added)
@@ -6770,7 +7098,7 @@
lp = new LinkProperties();
lp.setInterfaceName("tun1");
lp.addRoute(new RouteInfo(new IpPrefix("192.0.2.0/24"), null, "tun1"));
- vpnNetworkAgent.sendLinkProperties(lp);
+ mMockVpn.sendLinkProperties(lp);
waitForIdle();
// VPN not routing everything should no longer have interface filtering rules
verify(mMockNetd).firewallRemoveUidInterfaceRules(uidCaptor.capture());
@@ -6781,7 +7109,7 @@
lp.setInterfaceName("tun1");
lp.addRoute(new RouteInfo(new IpPrefix(Inet4Address.ANY, 0), RTN_UNREACHABLE));
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
- vpnNetworkAgent.sendLinkProperties(lp);
+ mMockVpn.sendLinkProperties(lp);
waitForIdle();
// Back to routing all IPv6 traffic should have filtering rules
verify(mMockNetd).firewallAddUidInterfaceRules(eq("tun1"), uidCaptor.capture());
@@ -6796,8 +7124,7 @@
lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null));
// The uid range needs to cover the test app so the network is visible to it.
final UidRange vpnRange = UidRange.createForUser(VPN_USER);
- final TestNetworkAgentWrapper vpnNetworkAgent = establishVpn(lp, VPN_UID,
- Collections.singleton(vpnRange));
+ mMockVpn.establish(lp, VPN_UID, Collections.singleton(vpnRange));
reset(mMockNetd);
InOrder inOrder = inOrder(mMockNetd);
@@ -6806,7 +7133,7 @@
final Set<UidRange> newRanges = new HashSet<>(Arrays.asList(
new UidRange(vpnRange.start, APP1_UID - 1),
new UidRange(APP1_UID + 1, vpnRange.stop)));
- vpnNetworkAgent.setUids(newRanges);
+ mMockVpn.setUids(newRanges);
waitForIdle();
ArgumentCaptor<int[]> uidCaptor = ArgumentCaptor.forClass(int[].class);
@@ -6947,7 +7274,7 @@
private void setupConnectionOwnerUid(int vpnOwnerUid, @VpnManager.VpnType int vpnType)
throws Exception {
final Set<UidRange> vpnRange = Collections.singleton(UidRange.createForUser(VPN_USER));
- establishVpn(new LinkProperties(), vpnOwnerUid, vpnRange);
+ mMockVpn.establish(new LinkProperties(), vpnOwnerUid, vpnRange);
mMockVpn.setVpnType(vpnType);
final VpnInfo vpnInfo = new VpnInfo();
@@ -7028,19 +7355,6 @@
mService.getConnectionOwnerUid(getTestConnectionInfo());
}
- private TestNetworkAgentWrapper establishVpn(
- LinkProperties lp, int ownerUid, Set<UidRange> vpnRange) throws Exception {
- final TestNetworkAgentWrapper
- vpnNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_VPN, lp);
- vpnNetworkAgent.getNetworkCapabilities().setOwnerUid(ownerUid);
- mMockVpn.setNetworkAgent(vpnNetworkAgent);
- mMockVpn.connect();
- mMockVpn.setUids(vpnRange);
- vpnNetworkAgent.connect(true);
- waitForIdle();
- return vpnNetworkAgent;
- }
-
private static PackageInfo buildPackageInfo(boolean hasSystemPermission, int uid) {
final PackageInfo packageInfo = new PackageInfo();
if (hasSystemPermission) {
@@ -7220,22 +7534,23 @@
setupLocationPermissions(Build.VERSION_CODES.Q, true, AppOpsManager.OPSTR_FINE_LOCATION,
Manifest.permission.ACCESS_FINE_LOCATION);
+
+ mMockVpn.establishForMyUid();
+
+ // Wait for networks to connect and broadcasts to be sent before removing permissions.
+ waitForIdle();
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
- // setUp() calls mockVpn() which adds a VPN with the Test Runner's uid. Configure it to be
- // active
- final VpnInfo info = new VpnInfo();
- info.ownerUid = Process.myUid();
- info.vpnIface = "interface";
- mMockVpn.setVpnInfo(info);
- mMockVpn.overrideUnderlyingNetworks(new Network[] {network});
+ assertTrue(mService.setUnderlyingNetworksForVpn(new Network[] {network}));
+ waitForIdle();
assertTrue(
"Active VPN permission not applied",
mService.checkConnectivityDiagnosticsPermissions(
Process.myPid(), Process.myUid(), naiWithoutUid,
mContext.getOpPackageName()));
- mMockVpn.overrideUnderlyingNetworks(null);
+ assertTrue(mService.setUnderlyingNetworksForVpn(null));
+ waitForIdle();
assertFalse(
"VPN shouldn't receive callback on non-underlying network",
mService.checkConnectivityDiagnosticsPermissions(
@@ -7256,8 +7571,6 @@
Manifest.permission.ACCESS_FINE_LOCATION);
mServiceContext.setPermission(android.Manifest.permission.NETWORK_STACK, PERMISSION_DENIED);
- // Disconnect mock vpn so the uid check on NetworkAgentInfo is tested
- mMockVpn.disconnect();
assertTrue(
"NetworkCapabilities administrator uid permission not applied",
mService.checkConnectivityDiagnosticsPermissions(
@@ -7460,4 +7773,39 @@
mCm.unregisterNetworkCallback(networkCallback);
}
+
+ @Test
+ public void testDumpDoesNotCrash() {
+ StringWriter stringWriter = new StringWriter();
+
+ mService.dump(new FileDescriptor(), new PrintWriter(stringWriter), new String[0]);
+
+ assertFalse(stringWriter.toString().isEmpty());
+ }
+
+ @Test
+ public void testRequestsSortedByIdSortsCorrectly() {
+ final TestNetworkCallback genericNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback wifiNetworkCallback = new TestNetworkCallback();
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
+ final NetworkRequest genericRequest = new NetworkRequest.Builder()
+ .clearCapabilities().build();
+ final NetworkRequest wifiRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_WIFI).build();
+ final NetworkRequest cellRequest = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR).build();
+ mCm.registerNetworkCallback(genericRequest, genericNetworkCallback);
+ mCm.registerNetworkCallback(wifiRequest, wifiNetworkCallback);
+ mCm.registerNetworkCallback(cellRequest, cellNetworkCallback);
+
+ ConnectivityService.NetworkRequestInfo[] nriOutput = mService.requestsSortedById();
+
+ assertTrue(nriOutput.length > 1);
+ for (int i = 0; i < nriOutput.length - 1; i++) {
+ boolean isRequestIdInOrder =
+ nriOutput[i].mRequests.get(0).requestId
+ < nriOutput[i + 1].mRequests.get(0).requestId;
+ assertTrue(isRequestIdInOrder);
+ }
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 753dbf8..f5b85ca 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -98,7 +98,6 @@
@Mock Context mCtx;
@Mock IDnsResolver mMockDnsResolver;
- @Mock MockableSystemProperties mSystemProperties;
private void assertResolverOptionsEquals(
@NonNull ResolverOptionsParcel actual,
@@ -137,7 +136,7 @@
mContentResolver.addProvider(Settings.AUTHORITY,
new FakeSettingsProvider());
when(mCtx.getContentResolver()).thenReturn(mContentResolver);
- mDnsManager = new DnsManager(mCtx, mMockDnsResolver, mSystemProperties);
+ mDnsManager = new DnsManager(mCtx, mMockDnsResolver);
// Clear the private DNS settings
Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
@@ -159,7 +158,6 @@
// Send a validation event that is tracked on the alternate netId
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp);
@@ -196,7 +194,6 @@
}));
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
fixedLp = new LinkProperties(lp);
mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp);
@@ -232,7 +229,6 @@
lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updatePrivateDnsValidation(
new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
@@ -246,7 +242,6 @@
mDnsManager.getPrivateDnsConfig());
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updatePrivateDnsValidation(
new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED,
@@ -295,7 +290,6 @@
mDnsManager.getPrivateDnsConfig());
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
mDnsManager.updatePrivateDnsValidation(
new DnsManager.PrivateDnsValidationUpdate(TEST_NETID,
@@ -341,7 +335,6 @@
lp.addDnsServer(InetAddress.getByName("4.4.4.4"));
mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES);
mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp);
- mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers());
mDnsManager.flushVmDnsCache();
final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor =
diff --git a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
index de1028c..c53462c 100644
--- a/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
+++ b/tests/net/java/com/android/server/connectivity/MultipathPolicyTrackerTest.java
@@ -34,6 +34,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -53,6 +54,7 @@
import android.net.StringNetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.os.Handler;
+import android.os.UserHandle;
import android.provider.Settings;
import android.telephony.TelephonyManager;
import android.test.mock.MockContentResolver;
@@ -91,6 +93,7 @@
private static final int POLICY_SNOOZED = -100;
@Mock private Context mContext;
+ @Mock private Context mUserAllContext;
@Mock private Resources mResources;
@Mock private Handler mHandler;
@Mock private MultipathPolicyTracker.Dependencies mDeps;
@@ -127,8 +130,11 @@
when(mContext.getResources()).thenReturn(mResources);
when(mContext.getApplicationInfo()).thenReturn(new ApplicationInfo());
- when(mContext.registerReceiverAsUser(mConfigChangeReceiverCaptor.capture(),
- any(), argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
+ doReturn(UserHandle.ALL.getIdentifier()).when(mUserAllContext).getUserId();
+ when(mContext.createContextAsUser(eq(UserHandle.ALL), anyInt()))
+ .thenReturn(mUserAllContext);
+ when(mUserAllContext.registerReceiver(mConfigChangeReceiverCaptor.capture(),
+ argThat(f -> f.hasAction(ACTION_CONFIGURATION_CHANGED)), any(), any()))
.thenReturn(null);
when(mDeps.getClock()).thenReturn(mClock);
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index 5046b65..4f65b67 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -29,7 +29,7 @@
import android.net.ConnectivityManager;
import android.net.IDnsResolver;
import android.net.INetd;
-import android.net.InterfaceConfiguration;
+import android.net.InterfaceConfigurationParcel;
import android.net.IpPrefix;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -68,7 +68,6 @@
@Mock IDnsResolver mDnsResolver;
@Mock INetd mNetd;
@Mock INetworkManagementService mNms;
- @Mock InterfaceConfiguration mConfig;
@Mock NetworkAgentInfo mNai;
TestLooper mLooper;
@@ -106,9 +105,10 @@
when(mNai.connService()).thenReturn(mConnectivity);
when(mNai.netAgentConfig()).thenReturn(mAgentConfig);
when(mNai.handler()).thenReturn(mHandler);
-
- when(mNms.getInterfaceConfig(eq(STACKED_IFACE))).thenReturn(mConfig);
- when(mConfig.getLinkAddress()).thenReturn(ADDR);
+ final InterfaceConfigurationParcel mConfig = new InterfaceConfigurationParcel();
+ when(mNetd.interfaceGetCfg(eq(STACKED_IFACE))).thenReturn(mConfig);
+ mConfig.ipv4Addr = ADDR.getAddress().getHostAddress();
+ mConfig.prefixLength = ADDR.getPrefixLength();
}
private void assertRequiresClat(boolean expected, NetworkAgentInfo nai) {
@@ -213,7 +213,7 @@
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
mLooper.dispatchNext();
- verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
+ verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
verify(mConnectivity).handleUpdateLinkProperties(eq(mNai), c.capture());
assertFalse(c.getValue().getStackedLinks().isEmpty());
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
@@ -353,7 +353,7 @@
nat.interfaceLinkStateChanged(STACKED_IFACE, true);
mLooper.dispatchNext();
- verify(mNms).getInterfaceConfig(eq(STACKED_IFACE));
+ verify(mNetd).interfaceGetCfg(eq(STACKED_IFACE));
verify(mConnectivity, times(1)).handleUpdateLinkProperties(eq(mNai), c.capture());
assertFalse(c.getValue().getStackedLinks().isEmpty());
assertTrue(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
diff --git a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 47db5d4..b47be97 100644
--- a/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -22,6 +22,7 @@
import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
@@ -36,6 +37,7 @@
import android.content.res.Resources;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
+import android.os.UserHandle;
import android.telephony.TelephonyManager;
import androidx.test.filters.SmallTest;
@@ -47,6 +49,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -104,17 +107,22 @@
when(mCtx.getResources()).thenReturn(mResources);
when(mCtx.getPackageManager()).thenReturn(mPm);
when(mCtx.getApplicationInfo()).thenReturn(new ApplicationInfo());
+ final Context asUserCtx = mock(Context.class, AdditionalAnswers.delegatesTo(mCtx));
+ doReturn(UserHandle.ALL).when(asUserCtx).getUser();
+ when(mCtx.createContextAsUser(eq(UserHandle.ALL), anyInt())).thenReturn(asUserCtx);
+ when(mCtx.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
+ .thenReturn(mNotificationManager);
when(mNetworkInfo.getExtraInfo()).thenReturn("extra");
when(mResources.getColor(anyInt(), any())).thenReturn(0xFF607D8B);
- mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mNotificationManager);
+ mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
}
private void verifyTitleByNetwork(final int id, final NetworkAgentInfo nai, final int title) {
final String tag = NetworkNotificationManager.tagFor(id);
mManager.showNotification(id, PRIVATE_DNS_BROKEN, nai, null, null, true);
verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any(), any());
+ .notify(eq(tag), eq(PRIVATE_DNS_BROKEN.eventId), any());
final int transportType = NetworkNotificationManager.approximateTransportType(nai);
if (transportType == NetworkCapabilities.TRANSPORT_WIFI) {
verify(mResources, times(1)).getString(title, eq(any()));
@@ -164,8 +172,8 @@
final int id = ids.get(i);
final int eventId = types.get(i).eventId;
final String tag = NetworkNotificationManager.tagFor(id);
- verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
- verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(eventId), any());
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
+ verify(mNotificationManager, times(1)).cancel(eq(tag), eq(eventId));
}
}
@@ -174,13 +182,13 @@
mManager.showNotification(100, NO_INTERNET, mCellNai, mWifiNai, null, false);
mManager.showNotification(101, LOST_INTERNET, mCellNai, mWifiNai, null, false);
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
mManager.showNotification(102, NO_INTERNET, mWifiNai, mCellNai, null, false);
final int eventId = NO_INTERNET.eventId;
final String tag = NetworkNotificationManager.tagFor(102);
- verify(mNotificationManager, times(1)).notifyAsUser(eq(tag), eq(eventId), any(), any());
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(eventId), any());
}
@Test
@@ -191,7 +199,7 @@
mManager.showNotification(103, LOST_INTERNET, mWifiNai, mCellNai, null, false);
mManager.showNotification(104, NETWORK_SWITCH, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
}
@Test
@@ -201,19 +209,16 @@
// Show first NO_INTERNET
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
// Captive portal detection triggers SIGN_IN a bit later, clearing the previous NO_INTERNET
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
+ verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
// Network disconnects
mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
+ verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
}
@Test
@@ -223,18 +228,17 @@
// Show first SIGN_IN
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
reset(mNotificationManager);
// NO_INTERNET arrives after, but is ignored.
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, never()).cancelAsUser(any(), anyInt(), any());
- verify(mNotificationManager, never()).notifyAsUser(any(), anyInt(), any(), any());
+ verify(mNotificationManager, never()).cancel(any(), anyInt());
+ verify(mNotificationManager, never()).notify(any(), anyInt(), any());
// Network disconnects
mManager.clearNotification(id);
- verify(mNotificationManager, times(1)).cancelAsUser(eq(tag), eq(SIGN_IN.eventId), any());
+ verify(mNotificationManager, times(1)).cancel(eq(tag), eq(SIGN_IN.eventId));
}
@Test
@@ -246,24 +250,20 @@
// to previous type or not. If they are equal then clear the notification; if they are not
// equal then return.
mManager.showNotification(id, NO_INTERNET, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(NO_INTERNET.eventId), any(), any());
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(NO_INTERNET.eventId), any());
// Previous notification is NO_INTERNET and given type is NO_INTERNET too. The notification
// should be cleared.
mManager.clearNotification(id, NO_INTERNET);
- verify(mNotificationManager, times(1))
- .cancelAsUser(eq(tag), eq(NO_INTERNET.eventId), any());
+ verify(mNotificationManager, times(1)).cancel(eq(tag), eq(NO_INTERNET.eventId));
// SIGN_IN is popped-up.
mManager.showNotification(id, SIGN_IN, mWifiNai, mCellNai, null, false);
- verify(mNotificationManager, times(1))
- .notifyAsUser(eq(tag), eq(SIGN_IN.eventId), any(), any());
+ verify(mNotificationManager, times(1)).notify(eq(tag), eq(SIGN_IN.eventId), any());
// The notification type is not matching previous one, PARTIAL_CONNECTIVITY won't be
// cleared.
mManager.clearNotification(id, PARTIAL_CONNECTIVITY);
- verify(mNotificationManager, never())
- .cancelAsUser(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId), any());
+ verify(mNotificationManager, never()).cancel(eq(tag), eq(PARTIAL_CONNECTIVITY.eventId));
}
}
diff --git a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
index 5a29c2c..de35f91 100644
--- a/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/PermissionMonitorTest.java
@@ -123,7 +123,7 @@
MockitoAnnotations.initMocks(this);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
- when(mUserManager.getUsers(eq(true))).thenReturn(
+ when(mUserManager.getAliveUsers()).thenReturn(
Arrays.asList(new UserInfo[] {
new UserInfo(MOCK_USER1, "", 0),
new UserInfo(MOCK_USER2, "", 0),
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index f2b7c1e..337507a 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -21,15 +21,6 @@
import static android.content.pm.UserInfo.FLAG_PRIMARY;
import static android.content.pm.UserInfo.FLAG_RESTRICTED;
import static android.net.ConnectivityManager.NetworkCallback;
-import static android.net.NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED;
-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.assertArrayEquals;
import static org.junit.Assert.assertEquals;
@@ -41,10 +32,12 @@
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.argThat;
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.doReturn;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -85,10 +78,10 @@
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.INetworkManagementService;
-import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.test.TestLooper;
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore;
@@ -99,6 +92,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.R;
+import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
import com.android.server.IpSecService;
@@ -106,6 +100,7 @@
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.AdditionalAnswers;
import org.mockito.Answers;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder;
@@ -215,10 +210,14 @@
when(mContext.getOpPackageName()).thenReturn(TEST_VPN_PKG);
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
+ when(mContext.getSystemServiceName(NotificationManager.class))
+ .thenReturn(Context.NOTIFICATION_SERVICE);
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
.thenReturn(mNotificationManager);
when(mContext.getSystemService(eq(Context.CONNECTIVITY_SERVICE)))
.thenReturn(mConnectivityManager);
+ when(mContext.getSystemServiceName(eq(ConnectivityManager.class)))
+ .thenReturn(Context.CONNECTIVITY_SERVICE);
when(mContext.getSystemService(eq(Context.IPSEC_SERVICE))).thenReturn(mIpSecManager);
when(mContext.getString(R.string.config_customVpnAlwaysOnDisconnectedDialogComponent))
.thenReturn(Resources.getSystem().getString(
@@ -237,7 +236,7 @@
doNothing().when(mNetService).registerObserver(any());
// Deny all appops by default.
- when(mAppOps.noteOpNoThrow(anyInt(), anyInt(), anyString()))
+ when(mAppOps.noteOpNoThrow(anyString(), anyInt(), anyString(), any(), any()))
.thenReturn(AppOpsManager.MODE_IGNORED);
// Setup IpSecService
@@ -585,7 +584,7 @@
}
@Test
- public void testNotificationShownForAlwaysOnApp() {
+ public void testNotificationShownForAlwaysOnApp() throws Exception {
final UserHandle userHandle = UserHandle.of(primaryUser.id);
final Vpn vpn = createVpn(primaryUser.id);
setMockedUsers(primaryUser);
@@ -594,123 +593,23 @@
// Don't show a notification for regular disconnected states.
vpn.updateState(DetailedState.DISCONNECTED, TAG);
- order.verify(mNotificationManager, atLeastOnce())
- .cancelAsUser(anyString(), anyInt(), eq(userHandle));
+ order.verify(mNotificationManager, atLeastOnce()).cancel(anyString(), anyInt());
// Start showing a notification for disconnected once always-on.
vpn.setAlwaysOnPackage(PKGS[0], false, null, mKeyStore);
- order.verify(mNotificationManager)
- .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
+ order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
// Stop showing the notification once connected.
vpn.updateState(DetailedState.CONNECTED, TAG);
- order.verify(mNotificationManager).cancelAsUser(anyString(), anyInt(), eq(userHandle));
+ order.verify(mNotificationManager).cancel(anyString(), anyInt());
// Show the notification if we disconnect again.
vpn.updateState(DetailedState.DISCONNECTED, TAG);
- order.verify(mNotificationManager)
- .notifyAsUser(anyString(), anyInt(), any(), eq(userHandle));
+ order.verify(mNotificationManager).notify(anyString(), anyInt(), any());
// Notification should be cleared after unsetting always-on package.
vpn.setAlwaysOnPackage(null, false, null, mKeyStore);
- 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_CONGESTED)
- .setLinkDownstreamBandwidthKbps(10));
- networks.put(
- wifi,
- new NetworkCapabilities()
- .addTransportType(TRANSPORT_WIFI)
- .addCapability(NET_CAPABILITY_INTERNET)
- .addCapability(NET_CAPABILITY_NOT_METERED)
- .addCapability(NET_CAPABILITY_NOT_ROAMING)
- .addCapability(NET_CAPABILITY_NOT_CONGESTED)
- .addCapability(NET_CAPABILITY_NOT_SUSPENDED)
- .setLinkUpstreamBandwidthKbps(20));
- setMockedNetworks(networks);
-
- final NetworkCapabilities caps = new NetworkCapabilities();
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {}, caps, false /* isAlwaysMetered */);
- 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));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile},
- caps,
- false /* isAlwaysMetered */);
- 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());
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, false /* isAlwaysMetered */);
- 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());
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_METERED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager, new Network[] {wifi}, caps, true /* isAlwaysMetered */);
- 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));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
-
- Vpn.applyUnderlyingCapabilities(
- mConnectivityManager,
- new Network[] {mobile, wifi},
- caps,
- false /* isAlwaysMetered */);
- 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));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED));
- assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_SUSPENDED));
+ order.verify(mNotificationManager).cancel(anyString(), anyInt());
}
/**
@@ -728,26 +627,27 @@
assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
}
- private Vpn createVpnAndSetupUidChecks(int... grantedOps) throws Exception {
+ private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception {
return createVpnAndSetupUidChecks(primaryUser, grantedOps);
}
- private Vpn createVpnAndSetupUidChecks(UserInfo user, int... grantedOps) throws Exception {
+ private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception {
final Vpn vpn = createVpn(user.id);
setMockedUsers(user);
when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
.thenReturn(Process.myUid());
- for (final int op : grantedOps) {
- when(mAppOps.noteOpNoThrow(op, Process.myUid(), TEST_VPN_PKG))
+ for (final String opStr : grantedOps) {
+ when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
+ null /* attributionTag */, null /* message */))
.thenReturn(AppOpsManager.MODE_ALLOWED);
}
return vpn;
}
- private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, int... checkedOps) {
+ private void checkProvisionVpnProfile(Vpn vpn, boolean expectedResult, String... checkedOps) {
assertEquals(expectedResult, vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore));
// The profile should always be stored, whether or not consent has been previously granted.
@@ -758,8 +658,9 @@
eq(Process.SYSTEM_UID),
eq(0));
- for (final int checkedOp : checkedOps) {
- verify(mAppOps).noteOpNoThrow(checkedOp, Process.myUid(), TEST_VPN_PKG);
+ for (final String checkedOpStr : checkedOps) {
+ verify(mAppOps).noteOpNoThrow(checkedOpStr, Process.myUid(), TEST_VPN_PKG,
+ null /* attributionTag */, null /* message */);
}
}
@@ -767,11 +668,11 @@
public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
.thenReturn(false);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
fail("Expected exception due to missing feature");
} catch (UnsupportedOperationException expected) {
}
@@ -779,10 +680,10 @@
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
checkProvisionVpnProfile(
- vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
}
@Test
@@ -792,19 +693,19 @@
// Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
// had neither.
checkProvisionVpnProfile(vpn, false /* expectedResult */,
- AppOpsManager.OP_ACTIVATE_PLATFORM_VPN, AppOpsManager.OP_ACTIVATE_VPN);
+ AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
- checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OP_ACTIVATE_VPN);
+ checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileTooLarge() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
final VpnProfile bigProfile = new VpnProfile("");
bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
@@ -820,7 +721,7 @@
public void testProvisionVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.provisionVpnProfile(TEST_VPN_PKG, mVpnProfile, mKeyStore);
@@ -843,7 +744,7 @@
public void testDeleteVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.deleteVpnProfile(TEST_VPN_PKG, mKeyStore);
@@ -866,7 +767,7 @@
@Test
public void testStartVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -876,14 +777,16 @@
verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
}
@Test
public void testStartVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -891,7 +794,8 @@
vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
// Verify that the the ACTIVATE_VPN appop was checked, but no error was thrown.
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
+ verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+ TEST_VPN_PKG, null /* attributionTag */, null /* message */);
}
@Test
@@ -907,10 +811,13 @@
// Verify both appops were checked.
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
- verify(mAppOps).noteOpNoThrow(AppOpsManager.OP_ACTIVATE_VPN, Process.myUid(), TEST_VPN_PKG);
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
+ verify(mAppOps).noteOpNoThrow(AppOpsManager.OPSTR_ACTIVATE_VPN, Process.myUid(),
+ TEST_VPN_PKG, null /* attributionTag */, null /* message */);
// Keystore should never have been accessed.
verify(mKeyStore, never()).get(any());
@@ -918,7 +825,7 @@
@Test
public void testStartVpnProfileMissingProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mKeyStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
@@ -931,16 +838,18 @@
verify(mKeyStore).get(vpn.getProfileNameForPackage(TEST_VPN_PKG));
verify(mAppOps)
.noteOpNoThrow(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
- eq(TEST_VPN_PKG));
+ eq(TEST_VPN_PKG),
+ eq(null) /* attributionTag */,
+ eq(null) /* message */);
}
@Test
public void testStartVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.startVpnProfile(TEST_VPN_PKG, mKeyStore);
@@ -953,7 +862,7 @@
public void testStopVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
createVpnAndSetupUidChecks(
- restrictedProfileA, AppOpsManager.OP_ACTIVATE_PLATFORM_VPN);
+ restrictedProfileA, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.stopVpnProfile(TEST_VPN_PKG);
@@ -969,7 +878,7 @@
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
@@ -982,7 +891,7 @@
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_PLATFORM));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
@@ -995,13 +904,13 @@
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
verify(mAppOps)
.setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
eq(Process.myUid()),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
@@ -1026,7 +935,7 @@
when(exception.getErrorType())
.thenReturn(IkeProtocolException.ERROR_TYPE_AUTHENTICATION_FAILED);
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), (mVpnProfile));
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
@@ -1037,20 +946,20 @@
ikeCb.onClosedExceptionally(exception);
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
@Test
public void testStartPlatformVpnIllegalArgumentExceptionInSetup() throws Exception {
when(mIkev2SessionCreator.createIkeSession(any(), any(), any(), any(), any(), any()))
.thenThrow(new IllegalArgumentException());
- final Vpn vpn = startLegacyVpn(mVpnProfile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
final NetworkCallback cb = triggerOnAvailableAndGetCallback();
// Wait for createIkeSession() to be called before proceeding in order to ensure consistent
// state
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS)).unregisterNetworkCallback(eq(cb));
- assertEquals(DetailedState.FAILED, vpn.getNetworkInfo().getDetailedState());
+ assertEquals(LegacyVpnInfo.STATE_FAILED, vpn.getLegacyVpnInfo().state);
}
private void setAndVerifyAlwaysOnPackage(Vpn vpn, int uid, boolean lockdownEnabled) {
@@ -1058,7 +967,7 @@
verify(mKeyStore).get(eq(vpn.getProfileNameForPackage(TEST_VPN_PKG)));
verify(mAppOps).setMode(
- eq(AppOpsManager.OP_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
+ eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN), eq(uid), eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
verify(mSystemServices).settingsSecurePutStringForUser(
@@ -1089,8 +998,7 @@
// a subsequent CL.
}
- public Vpn startLegacyVpn(final VpnProfile vpnProfile) throws Exception {
- final Vpn vpn = createVpn(primaryUser.id);
+ private Vpn startLegacyVpn(final Vpn vpn, final VpnProfile vpnProfile) throws Exception {
setMockedUsers(primaryUser);
// Dummy egress interface
@@ -1107,7 +1015,7 @@
@Test
public void testStartPlatformVpn() throws Exception {
- startLegacyVpn(mVpnProfile);
+ startLegacyVpn(createVpn(primaryUser.id), mVpnProfile);
// TODO: Test the Ikev2VpnRunner started up properly. Relies on utility methods added in
// a subsequent patch.
}
@@ -1142,7 +1050,7 @@
legacyRunnerReady.open();
return new Network(102);
});
- final Vpn vpn = startLegacyVpn(profile);
+ final Vpn vpn = startLegacyVpn(createVpn(primaryUser.id), profile);
final TestDeps deps = (TestDeps) vpn.mDeps;
try {
// udppsk and 1701 are the values for TYPE_L2TP_IPSEC_PSK
@@ -1155,7 +1063,7 @@
new String[] { EGRESS_IFACE, "l2tp", expectedAddr, "1701", profile.l2tpSecret,
"name", profile.username, "password", profile.password,
"linkname", "vpn", "refuse-eap", "nodefaultroute", "usepeerdns",
- "idle", "1800", "mtu", "1400", "mru", "1400" },
+ "idle", "1800", "mtu", "1270", "mru", "1270" },
deps.mtpdArgs.get(10, TimeUnit.SECONDS));
// Now wait for the runner to be ready before testing for the route.
legacyRunnerReady.block(10_000);
@@ -1263,7 +1171,7 @@
}
@Override
- public boolean checkInterfacePresent(final Vpn vpn, final String iface) {
+ public boolean isInterfacePresent(final Vpn vpn, final String iface) {
return true;
}
}
@@ -1272,8 +1180,17 @@
* Mock some methods of vpn object.
*/
private Vpn createVpn(@UserIdInt int userId) {
- return new Vpn(Looper.myLooper(), mContext, new TestDeps(), mNetService,
+ final Context asUserContext = mock(Context.class, AdditionalAnswers.delegatesTo(mContext));
+ doReturn(UserHandle.of(userId)).when(asUserContext).getUser();
+ when(mContext.createContextAsUser(eq(UserHandle.of(userId)), anyInt()))
+ .thenReturn(asUserContext);
+ final TestLooper testLooper = new TestLooper();
+ final Vpn vpn = new Vpn(testLooper.getLooper(), mContext, new TestDeps(), mNetService,
userId, mKeyStore, mSystemServices, mIkev2SessionCreator);
+ verify(mConnectivityManager, times(1)).registerNetworkProvider(argThat(
+ provider -> provider.getName().contains("VpnNetworkProvider")
+ ));
+ return vpn;
}
private static void assertBlocked(Vpn vpn, int... uids) {
@@ -1303,15 +1220,14 @@
* @see UserManagerService#getUsers(boolean)
*/
doAnswer(invocation -> {
- final boolean excludeDying = (boolean) invocation.getArguments()[0];
final ArrayList<UserInfo> result = new ArrayList<>(users.length);
for (UserInfo ui : users) {
- if (!excludeDying || (ui.isEnabled() && !ui.partial)) {
+ if (ui.isEnabled() && !ui.partial) {
result.add(ui);
}
}
return result;
- }).when(mUserManager).getUsers(anyBoolean());
+ }).when(mUserManager).getAliveUsers();
doAnswer(invocation -> {
final int id = (int) invocation.getArguments()[0];
diff --git a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
index 858358c..8b730af 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsAccessTest.java
@@ -22,7 +22,6 @@
import android.Manifest;
import android.Manifest.permission;
import android.app.AppOpsManager;
-import android.app.admin.DeviceAdminInfo;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -167,13 +166,11 @@
}
private void setIsDeviceOwner(boolean isOwner) {
- when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER))
- .thenReturn(isOwner);
+ when(mDpmi.isActiveDeviceOwner(TEST_UID)).thenReturn(isOwner);
}
private void setIsProfileOwner(boolean isOwner) {
- when(mDpmi.isActiveAdminWithPolicy(TEST_UID, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER))
- .thenReturn(isOwner);
+ when(mDpmi.isActiveProfileOwner(TEST_UID)).thenReturn(isOwner);
}
private void setHasAppOpsPermission(int appOpsMode, boolean hasPermission) {
diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
index 7abe189..cd9406c 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java
@@ -35,7 +35,6 @@
import static android.net.NetworkStats.SET_ALL;
import static android.net.NetworkStats.SET_DEFAULT;
import static android.net.NetworkStats.SET_FOREGROUND;
-import static android.net.NetworkStats.STATS_PER_IFACE;
import static android.net.NetworkStats.STATS_PER_UID;
import static android.net.NetworkStats.TAG_ALL;
import static android.net.NetworkStats.TAG_NONE;
@@ -994,7 +993,7 @@
public void testTethering() throws Exception {
// pretend first mobile network comes online
expectDefaultSettings();
- NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)};
+ final NetworkState[] states = new NetworkState[]{buildMobile3gState(IMSI_1)};
expectNetworkStatsSummary(buildEmptyStats());
expectNetworkStatsUidDetail(buildEmptyStats());
@@ -1004,23 +1003,39 @@
incrementCurrentTime(HOUR_IN_MILLIS);
expectDefaultSettings();
+ // Register custom provider and retrieve callback.
+ final TestableNetworkStatsProviderBinder provider =
+ new TestableNetworkStatsProviderBinder();
+ final INetworkStatsProviderCallback cb =
+ mService.registerNetworkStatsProvider("TEST-TETHERING-OFFLOAD", provider);
+ assertNotNull(cb);
+ final long now = getElapsedRealtime();
+
// Traffic seen by kernel counters (includes software tethering).
- final NetworkStats ifaceStats = new NetworkStats(getElapsedRealtime(), 1)
+ final NetworkStats swIfaceStats = new NetworkStats(now, 1)
.insertEntry(TEST_IFACE, 1536L, 12L, 384L, 3L);
// Hardware tethering traffic, not seen by kernel counters.
- final NetworkStats tetherStatsHardware = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, 512L, 4L, 128L, 1L);
+ final NetworkStats tetherHwIfaceStats = new NetworkStats(now, 1)
+ .insertEntry(new NetworkStats.Entry(TEST_IFACE, UID_ALL, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 512L, 4L, 128L, 1L, 0L));
+ final NetworkStats tetherHwUidStats = new NetworkStats(now, 1)
+ .insertEntry(new NetworkStats.Entry(TEST_IFACE, UID_TETHERING, SET_DEFAULT,
+ TAG_NONE, METERED_YES, ROAMING_NO, DEFAULT_NETWORK_YES,
+ 512L, 4L, 128L, 1L, 0L));
+ cb.notifyStatsUpdated(0 /* unused */, tetherHwIfaceStats, tetherHwUidStats);
- // Traffic for UID_RED.
- final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1)
+ // Fake some traffic done by apps on the device (as opposed to tethering), and record it
+ // into UID stats (as opposed to iface stats).
+ final NetworkStats localUidStats = new NetworkStats(now, 1)
.insertEntry(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L);
- // All tethering traffic, both hardware and software.
- final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1)
- .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L,
+ // Software per-uid tethering traffic.
+ final NetworkStats tetherSwUidStats = new NetworkStats(now, 1)
+ .insertEntry(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1408L, 10L, 256L, 1L,
0L);
- expectNetworkStatsSummary(ifaceStats, tetherStatsHardware);
- expectNetworkStatsUidDetail(uidStats, tetherStats);
+ expectNetworkStatsSummary(swIfaceStats);
+ expectNetworkStatsUidDetail(localUidStats, tetherSwUidStats);
forcePollAndWaitForIdle();
// verify service recorded history
@@ -1362,12 +1377,6 @@
}
private void expectNetworkStatsSummary(NetworkStats summary) throws Exception {
- expectNetworkStatsSummary(summary, new NetworkStats(0L, 0));
- }
-
- private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats)
- throws Exception {
- expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats);
expectNetworkStatsSummaryDev(summary.clone());
expectNetworkStatsSummaryXt(summary.clone());
}
@@ -1380,11 +1389,6 @@
when(mStatsFactory.readNetworkStatsSummaryXt()).thenReturn(summary);
}
- private void expectNetworkStatsTethering(int how, NetworkStats stats)
- throws Exception {
- when(mNetManager.getNetworkStatsTethering(how)).thenReturn(stats);
- }
-
private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception {
expectNetworkStatsUidDetail(detail, new NetworkStats(0L, 0));
}
diff --git a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
index 8f09377..6d2c7dc 100644
--- a/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
+++ b/tests/net/java/com/android/server/net/NetworkStatsSubscriptionsMonitorTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.fail;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -150,7 +151,7 @@
}
private void assertRatTypeChangedForSub(String subscriberId, int ratType) {
- assertEquals(mMonitor.getRatTypeForSubscriberId(subscriberId), ratType);
+ assertEquals(ratType, mMonitor.getRatTypeForSubscriberId(subscriberId));
final ArgumentCaptor<Integer> typeCaptor = ArgumentCaptor.forClass(Integer.class);
// Verify callback with the subscriberId and the RAT type should be as expected.
// It will fail if get a callback with an unexpected RAT type.
@@ -302,26 +303,84 @@
reset(mDelegate);
// Set IMSI to null again to simulate somehow IMSI is not available, such as
- // modem crash. Verify service should not unregister listener.
+ // modem crash. Verify service should unregister listener.
updateSubscriberIdForTestSub(TEST_SUBID1, null);
- verify(mTelephonyManager, never()).listen(any(), anyInt());
- assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
reset(mDelegate);
+ clearInvocations(mTelephonyManager);
- // Set RAT type of sim1 to LTE. Verify RAT type of sim1 is still changed even if the IMSI
- // is not available. The monitor keeps the listener even if the IMSI disappears because
- // the IMSI can never change for any given subId, therefore even if the IMSI is updated
- // to null, the monitor should continue accepting updates of the RAT type. However,
- // telephony is never actually supposed to do this, if the IMSI disappears there should
- // not be updates, but it's still the right thing to do theoretically.
- setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ // Simulate somehow IMSI is back. Verify service will register with
+ // another listener and fire callback accordingly.
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI1);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ reset(mDelegate);
+ clearInvocations(mTelephonyManager);
+
+ // Set RAT type of sim1 to LTE. Verify RAT type of sim1 still works.
+ setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
TelephonyManager.NETWORK_TYPE_LTE);
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_LTE);
reset(mDelegate);
mMonitor.stop();
+ verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor2.getValue()),
+ eq(PhoneStateListener.LISTEN_NONE));
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ }
+
+ /**
+ * Verify that when IMSI suddenly changed for a given subId, the service will register a new
+ * listener and unregister the old one, and report changes on updated IMSI. This is for modem
+ * feature that may be enabled for certain carrier, which changes to use a different IMSI while
+ * roaming on certain networks for multi-IMSI SIM cards, but the subId stays the same.
+ */
+ @Test
+ public void testSubscriberIdChanged() {
+ mMonitor.start();
+ // Insert sim1, verify RAT type is NETWORK_TYPE_UNKNOWN, and never get any callback
+ // before changing RAT type.
+ addTestSub(TEST_SUBID1, TEST_IMSI1);
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+
+ // Set RAT type of sim1 to UMTS.
+ // Verify RAT type of sim1 changes accordingly.
+ setRatTypeForSub(ratTypeListenerCaptor.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
+ clearInvocations(mTelephonyManager);
+
+ // Simulate IMSI of sim1 changed to IMSI2. Verify the service will register with
+ // another listener and remove the old one. The RAT type of new IMSI stays at
+ // NETWORK_TYPE_UNKNOWN until received initial callback from telephony.
+ final ArgumentCaptor<RatTypeListener> ratTypeListenerCaptor2 =
+ ArgumentCaptor.forClass(RatTypeListener.class);
+ updateSubscriberIdForTestSub(TEST_SUBID1, TEST_IMSI2);
+ verify(mTelephonyManager, times(1)).listen(ratTypeListenerCaptor2.capture(),
+ eq(PhoneStateListener.LISTEN_SERVICE_STATE));
verify(mTelephonyManager, times(1)).listen(eq(ratTypeListenerCaptor.getValue()),
eq(PhoneStateListener.LISTEN_NONE));
assertRatTypeChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertRatTypeNotChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ reset(mDelegate);
+
+ // Set RAT type of sim1 to UMTS for new listener to simulate the initial callback received
+ // from telephony after registration. Verify RAT type of sim1 changes with IMSI2
+ // accordingly.
+ setRatTypeForSub(ratTypeListenerCaptor2.getAllValues(), TEST_SUBID1,
+ TelephonyManager.NETWORK_TYPE_UMTS);
+ assertRatTypeNotChangedForSub(TEST_IMSI1, TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ assertRatTypeChangedForSub(TEST_IMSI2, TelephonyManager.NETWORK_TYPE_UMTS);
+ reset(mDelegate);
}
}
diff --git a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
index fb84611..ebbc0ef 100644
--- a/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
+++ b/tests/net/java/com/android/server/net/ipmemorystore/NetworkAttributesTest.java
@@ -19,6 +19,7 @@
import static org.junit.Assert.assertEquals;
import android.net.ipmemorystore.NetworkAttributes;
+import android.net.networkstack.aidl.quirks.IPv6ProvisioningLossQuirk;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -52,6 +53,8 @@
}
assertEquals(sum, NetworkAttributes.TOTAL_WEIGHT, EPSILON);
+ final IPv6ProvisioningLossQuirk ipv6ProvisioningLossQuirk =
+ new IPv6ProvisioningLossQuirk(3, System.currentTimeMillis() + 7_200_000);
// Use directly the constructor with all attributes, and make sure that when compared
// to itself the score is a clean 1.0f.
final NetworkAttributes na =
@@ -61,7 +64,7 @@
"some hint",
Arrays.asList(Inet4Address.getByAddress(new byte[] {5, 6, 7, 8}),
Inet4Address.getByAddress(new byte[] {9, 0, 1, 2})),
- 98);
+ 98, ipv6ProvisioningLossQuirk);
assertEquals(1.0f, na.getNetworkGroupSamenessConfidence(na), EPSILON);
}
}